All files / app/features/auth/signup MotivationsForm.tsx

100% Statements 26/26
80% Branches 4/5
100% Functions 8/8
100% Lines 24/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 1012x 2x 2x 2x 2x   2x 2x 2x 2x   2x           93x               8x 18x 18x   18x                   18x   20x 4x 3x     4x     4x       18x 4x               90x                                                                            
import { Box, Checkbox, FormControlLabel, styled, Typography } from "@mui/material";
import { useMutation } from "@tanstack/react-query";
import Alert from "components/Alert";
import { useAuthContext } from "features/auth/AuthProvider";
import { StyledButton, StyledForm } from "features/auth/useAuthStyles";
import { RpcError } from "grpc-web";
import { useTranslation } from "i18n";
import { AUTH, GLOBAL } from "i18n/namespaces";
import { Controller, useForm } from "react-hook-form";
import { service } from "service";
 
const MOTIVATION_OPTIONS = ["surfing", "hosting", "events", "community_organizing", "something_else"] as const;
 
type MotivationKey = (typeof MOTIVATION_OPTIONS)[number];
 
type MotivationsFormInputs = Record<MotivationKey, boolean>;
 
const StyledFormControlLabel = styled(FormControlLabel)(({ theme }) => ({
  alignItems: "flex-start",
  marginBottom: theme.spacing(1),
  "& .MuiCheckbox-root": {
    paddingTop: theme.spacing(0.5),
  },
}));
 
export default function MotivationsForm() {
  const { t } = useTranslation([AUTH, GLOBAL]);
  const { authActions, authState } = useAuthContext();
 
  const { control, handleSubmit } = useForm<MotivationsFormInputs>({
    defaultValues: {
      surfing: false,
      hosting: false,
      events: false,
      community_organizing: false,
      something_else: false,
    },
  });
 
  const mutation = useMutation<void, RpcError, MotivationsFormInputs>({
    mutationFn: async (data) => {
      const selectedMotivations = MOTIVATION_OPTIONS.filter((key) => data[key]);
      const state = await service.auth.signupFlowMotivations(authState.flowState!.flowToken, selectedMotivations);
      authActions.updateSignupState(state);
    },
    onMutate() {
      authActions.clearError();
    },
    onSettled() {
      window.scroll({ top: 0, behavior: "smooth" });
    },
  });
 
  const submit = handleSubmit((data) => {
    mutation.mutate(data);
  });
 
  return (
    <>
      {mutation.error && <Alert severity="error">{mutation.error.message || ""}</Alert>}
      <StyledForm onSubmit={submit}>
        {MOTIVATION_OPTIONS.map((key) => (
          <Controller
            key={key}
            name={key}
            control={control}
            render={({ field }) => (
              <StyledFormControlLabel
                control={<Checkbox checked={field.value} onChange={field.onChange} onBlur={field.onBlur} />}
                label={
                  <Box>
                    <Typography
                      variant="body1"
                      sx={{
                        fontWeight: "bold",
                      }}
                    >
                      {t(`auth:motivations_form.${key}`)}
                    </Typography>
                    <Typography
                      variant="body2"
                      sx={{
                        color: "text.secondary",
                      }}
                    >
                      {t(`auth:motivations_form.${key}_description`)}
                    </Typography>
                  </Box>
                }
              />
            )}
          />
        ))}
        <StyledButton onClick={submit} type="submit" loading={authState.loading || mutation.isPending} fullWidth>
          {t("global:continue")}
        </StyledButton>
      </StyledForm>
    </>
  );
}