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