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;