frontend/containers/SignInForm/index.tsx (view raw)
1import {useState, useMemo, useEffect} from 'react';
2import {useRouter} from 'next/router';
3import RouterLink from 'next/link';
4import {makeStyles} from '@material-ui/core/styles';
5import TextField from '@material-ui/core/TextField';
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 {useTranslation} from 'react-i18next';
14import useToastsStore from '../../stores/useToastStore';
15import useLoginWithProvider from '../../hooks/useLoginWithProvider';
16import useLoginForm from '../../hooks/useLoginForm';
17import useAddToEvents from '../../hooks/useAddToEvents';
18
19const SignIn = () => {
20 const {t} = useTranslation();
21 const router = useRouter();
22 const {loginWithProvider} = useLoginWithProvider();
23 const [error, setError] = useState('');
24 const [email, setEmail] = useState('');
25 const [password, setPassword] = useState('');
26 const addToast = useToastsStore(s => s.addToast);
27 const {login, loading} = useLoginForm(email, password);
28 const {saveStoredEvents} = useAddToEvents();
29 const classes = useStyles();
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 = error.message;
64 console.error({strapiError});
65 if (strapiError === 'Invalid identifier or password') {
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 }
72 };
73
74 return (
75 <form onSubmit={onSubmit}>
76 <CardContent className={classes.content}>
77 <Typography variant="h6">{t('signin.title')}</Typography>
78 {error && <FormHelperText error={true}>{error}</FormHelperText>}
79 <TextField
80 label={t('signin.email')}
81 fullWidth
82 required={true}
83 margin="dense"
84 value={email}
85 onChange={({target: {value = ''}}) => setEmail(value)}
86 id="SignInEmail"
87 name="email"
88 type="email"
89 error={!!error}
90 />
91 <TextField
92 label={t('signin.password')}
93 fullWidth
94 required={true}
95 margin="dense"
96 value={password}
97 onChange={({target: {value = ''}}) => setPassword(value)}
98 id="SignInEmail"
99 name="password"
100 type="password"
101 error={!!error}
102 />
103 <RouterLink href="/auth/lost-password">
104 <Link>
105 <Typography align="center" variant="body2">
106 {t('lost_password.message')}
107 </Typography>
108 </Link>
109 </RouterLink>
110 </CardContent>
111 <CardActions className={classes.actions} align="center">
112 <Button size="small" id="SignInRegister" href="/auth/register">
113 {t('signin.register')}
114 </Button>
115 <Button
116 color="primary"
117 variant="contained"
118 type="submit"
119 disabled={!canSubmit}
120 aria-disabled={!canSubmit}
121 id="SignInSubmit"
122 endIcon={
123 loading && <CircularProgress className={classes.loader} size={20} />
124 }
125 >
126 {t('signin.login')}
127 </Button>
128 </CardActions>
129 </form>
130 );
131};
132
133const getURLSearch = router => router.asPath.replace(router.route, '');
134
135const useStyles = makeStyles(theme => ({
136 content: {
137 display: 'flex',
138 flexDirection: 'column',
139 },
140 loader: {
141 marginLeft: '14px',
142 color: theme.palette.background.paper,
143 },
144 actions: {
145 justifyContent: 'center',
146 marginBottom: theme.spacing(2),
147 },
148}));
149export default SignIn;