frontend/containers/SignInForm/index.tsx (view raw)
1import {useState, useMemo} from 'react';
2import NextLink from 'next/link';
3import TextField from '@mui/material/TextField';
4import Button from '@mui/material/Button';
5import Typography from '@mui/material/Typography';
6import CardContent from '@mui/material/CardContent';
7import FormHelperText from '@mui/material/FormHelperText';
8import CardActions from '@mui/material/CardActions';
9import Divider from '@mui/material/Divider';
10import Box from '@mui/material/Box';
11import {useTheme} from '@mui/material/styles';
12import {useTranslation} from 'react-i18next';
13import {signIn} from 'next-auth/react';
14import useAddToEvents from '../../hooks/useAddToEvents';
15import LoginGoogle from '../LoginGoogle';
16
17interface Props {
18 error?: string;
19}
20
21const errorsMap = {
22 CredentialsSignin: 'signin.errors.CredentialsSignin',
23 EmailNotConfirmed: 'signin.errors.EmailNotConfirmed',
24};
25
26const SignIn = (props: Props) => {
27 const {error} = props;
28 const {t} = useTranslation();
29 const theme = useTheme();
30 const [email, setEmail] = useState('');
31 const [password, setPassword] = useState('');
32 const {saveStoredEvents} = useAddToEvents();
33
34 const canSubmit = useMemo(
35 () => [email, password].filter(s => s.length < 4).length === 0,
36 [email, password]
37 );
38
39 const onSubmit = async e => {
40 e.preventDefault?.();
41 try {
42 await signIn('credentials', {
43 email,
44 password,
45 callbackUrl: '/dashboard',
46 });
47 saveStoredEvents();
48 } catch (error) {
49 console.error(error);
50 }
51
52 return false;
53 };
54
55 const spaceAround = {
56 width: '100%',
57 textAlign: 'center',
58 margin: theme.spacing(2, 0),
59 };
60
61 return (
62 <form onSubmit={onSubmit}>
63 <CardContent
64 sx={{
65 display: 'flex',
66 flexDirection: 'column',
67 px: 2,
68 }}
69 >
70 <Typography variant="h6" align="center">
71 {t('signin.title')}
72 </Typography>
73 {error && (
74 <FormHelperText error sx={{textAlign: 'center'}}>
75 {t(errorsMap[error])}
76 </FormHelperText>
77 )}
78 <Box
79 sx={{
80 display: 'flex',
81 flexDirection: 'column',
82 }}
83 >
84 <TextField
85 label={t('signin.email')}
86 fullWidth
87 required={true}
88 InputLabelProps={{required: false}}
89 margin="dense"
90 value={email}
91 onChange={({target: {value = ''}}) => setEmail(value)}
92 name="email"
93 type="email"
94 error={!!error}
95 />
96 <TextField
97 label={t('signin.password')}
98 fullWidth
99 InputLabelProps={{required: false}}
100 required={true}
101 margin="dense"
102 value={password}
103 onChange={({target: {value = ''}}) => setPassword(value)}
104 id="SignInEmail"
105 name="password"
106 type="password"
107 error={!!error}
108 />
109 </Box>
110
111 <Box sx={spaceAround}>
112 <NextLink href="/auth/lost-password" passHref>
113 <Typography
114 align="center"
115 variant="body2"
116 color="primary"
117 sx={{
118 textDecoration: 'underline',
119 textDecorationColor: 'primary',
120 }}
121 >
122 {t('lost_password.message')}
123 </Typography>
124 </NextLink>
125 </Box>
126 <Box
127 sx={{
128 display: 'flex',
129 flexDirection: 'column',
130 alignItems: 'center',
131 width: '100%',
132 pb: 1,
133 }}
134 >
135 <Button
136 color="primary"
137 variant="contained"
138 fullWidth
139 type="submit"
140 disabled={!canSubmit}
141 aria-disabled={!canSubmit}
142 >
143 {t('signin.login')}
144 </Button>
145 <Box sx={spaceAround}>
146 <Typography>{t('signin.or')}</Typography>
147 </Box>
148 <LoginGoogle />
149 </Box>
150 </CardContent>
151 <Divider />
152 <CardActions
153 sx={{
154 flexDirection: 'column',
155 justifyContent: 'center',
156 marginBottom: theme.spacing(2),
157 textAlign: 'center',
158 px: 2,
159 }}
160 >
161 <Typography align="center" variant="body2" sx={{pt: 2}}>
162 {t('signin.no_account')}
163 </Typography>
164 <NextLink href="/auth/register" passHref>
165 <Button size="small">{t('signin.register')}</Button>
166 </NextLink>
167 </CardActions>
168 </form>
169 );
170};
171
172export default SignIn;