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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119            2x 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" fontWeight="bold">
                      {t(`auth:motivations_form.${key}`)}
                    </Typography>
                    <Typography variant="body2" 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>
    </>
  );
}