all repos — caroster @ d9c8403b4d46365a357d1ba4583e293e717fd526

[Octree] Group carpool to your event https://caroster.io

frontend/containers/SignInForm/index.js (view raw)

  1import {useState, useMemo, useEffect} from 'react';
  2import {useTranslation} from 'react-i18next';
  3import TextField from '@material-ui/core/TextField';
  4import {useRouter} from 'next/router';
  5import RouterLink from 'next/link';
  6import Button from '@material-ui/core/Button';
  7import Link from '@material-ui/core/Link';
  8import Typography from '@material-ui/core/Typography';
  9import CardContent from '@material-ui/core/CardContent';
 10import CircularProgress from '@material-ui/core/CircularProgress';
 11import FormHelperText from '@material-ui/core/FormHelperText';
 12import CardActions from '@material-ui/core/CardActions';
 13import {makeStyles} from '@material-ui/core/styles';
 14import useLoginForm from '../../hooks/useLoginForm';
 15import useToastsStore from '../../stores/useToastStore';
 16import useLoginWithProvider from '../../hooks/useLoginWithProvider';
 17import useAddToEvents from '../../hooks/useAddToEvents';
 18
 19const SignIn = () => {
 20  const {t} = useTranslation();
 21  const classes = useStyles();
 22  const router = useRouter();
 23  const {loginWithProvider} = useLoginWithProvider();
 24  const [error, setError] = useState('');
 25  const [email, setEmail] = useState('');
 26  const [password, setPassword] = useState('');
 27  const addToast = useToastsStore(s => s.addToast);
 28  const {login, loading} = useLoginForm(email, password);
 29  const {saveStoredEvents} = useAddToEvents();
 30
 31  const canSubmit = useMemo(
 32    () => [email, password].filter(s => s.length < 4).length === 0,
 33    [email, password]
 34  );
 35
 36  const onSubmit = async e => {
 37    e.preventDefault?.();
 38    try {
 39      await login();
 40      saveStoredEvents();
 41      router.push('/');
 42    } catch (error) {
 43      handleAuthError(error);
 44    }
 45
 46    return false;
 47  };
 48
 49  useEffect(() => {
 50    const authWithGoogle = async search => {
 51      try {
 52        await loginWithProvider('google', search);
 53      } catch (error) {
 54        handleAuthError(error);
 55      }
 56    };
 57
 58    const search = getURLSearch(router);
 59    if (search) authWithGoogle(search);
 60  }, [router.route]); // eslint-disable-line react-hooks/exhaustive-deps
 61
 62  const handleAuthError = error => {
 63    const strapiError = getStrapiError(error);
 64    console.error({strapiError});
 65    if (strapiError === 'Auth.form.error.invalid') {
 66      setError(t('signin.errors'));
 67      addToast(t('signin.errors'));
 68    } else if (strapiError === 'Auth.form.error.confirmed') {
 69      setError(t('signin.unconfirmed'));
 70      addToast(t('signin.unconfirmed'));
 71    } else if (strapiError === 'Auth.form.error.email.taken') {
 72      addToast(t('signup.errors.email_taken'));
 73    } else console.error(error);
 74  };
 75
 76  return (
 77    <form onSubmit={onSubmit}>
 78      <CardContent className={classes.content}>
 79        <Typography variant="h6">{t('signin.title')}</Typography>
 80        {error && <FormHelperText error={true}>{error}</FormHelperText>}
 81        <TextField
 82          label={t('signin.email')}
 83          fullWidth
 84          required={true}
 85          margin="dense"
 86          value={email}
 87          onChange={({target: {value = ''}}) => setEmail(value)}
 88          id="SignInEmail"
 89          name="email"
 90          type="email"
 91          error={!!error}
 92        />
 93        <TextField
 94          label={t('signin.password')}
 95          fullWidth
 96          required={true}
 97          margin="dense"
 98          value={password}
 99          onChange={({target: {value = ''}}) => setPassword(value)}
100          id="SignInEmail"
101          name="password"
102          type="password"
103          error={!!error}
104        />
105        <RouterLink href="/auth/lost-password">
106          <Link>
107            <Typography align="center" variant="body2">
108              {t('lost_password.message')}
109            </Typography>
110          </Link>
111        </RouterLink>
112      </CardContent>
113      <CardActions className={classes.actions} align="center">
114        <Button size="small" id="SignInRegister" href="/auth/register">
115          {t('signin.register')}
116        </Button>
117        <Button
118          color="primary"
119          variant="contained"
120          type="submit"
121          disabled={!canSubmit}
122          aria-disabled={!canSubmit}
123          id="SignInSubmit"
124          endIcon={
125            loading && <CircularProgress className={classes.loader} size={20} />
126          }
127        >
128          {t('signin.login')}
129        </Button>
130      </CardActions>
131    </form>
132  );
133};
134
135const getStrapiError = error => {
136  if (error.message?.[0]?.messages?.[0]) return error.message[0].messages[0].id;
137  return error?.graphQLErrors?.[0].extensions.exception.data.message[0]
138    .messages[0].id;
139};
140
141const getURLSearch = router => router.asPath.replace(router.route, '');
142
143const useStyles = makeStyles(theme => ({
144  content: {
145    display: 'flex',
146    flexDirection: 'column',
147  },
148  loader: {
149    marginLeft: '14px',
150    color: theme.palette.background.paper,
151  },
152  actions: {
153    justifyContent: 'center',
154    marginBottom: theme.spacing(2),
155  },
156}));
157export default SignIn;