frontend/containers/LostPassword/index.js (view raw)
1import {useCallback, useState, useEffect} from 'react';
2import {styled} from '@mui/material/styles';
3import {useTranslation} from 'next-i18next';
4import router from 'next/router';
5import TextField from '@mui/material/TextField';
6import Button from '@mui/material/Button';
7import CardContent from '@mui/material/CardContent';
8import Card from '@mui/material/Card';
9import CircularProgress from '@mui/material/CircularProgress';
10import CardActions from '@mui/material/CardActions';
11import Link from '@mui/material/Link';
12import LostPasswordSuccess from './Success';
13import useToastStore from '../../stores/useToastStore';
14import useProfile from '../../hooks/useProfile';
15import {useForgotPasswordMutation} from '../../generated/graphql';
16
17const PREFIX = 'LostPassword';
18
19const classes = {
20 loader: `${PREFIX}-loader`,
21 actions: `${PREFIX}-actions`,
22};
23
24const Root = styled('form')(({theme}) => ({
25 [`& .${classes.loader}`]: {
26 marginLeft: theme.spacing(4),
27 },
28
29 [`& .${classes.actions}`]: {
30 marginTop: theme.spacing(2),
31 justifyContent: 'flex-end',
32 },
33}));
34
35const LostPassword = () => {
36 const {t} = useTranslation();
37
38 const addToast = useToastStore(s => s.addToast);
39 const {profile} = useProfile();
40 const [sendForgotPassword, {loading}] = useForgotPasswordMutation();
41 const [isSent, setIsSent] = useState(false);
42 const [error, setError] = useState('');
43 const [email, setEmail] = useState('');
44 const canSubmit = email.length > 4;
45
46 useEffect(() => {
47 if (profile?.confirmed) router.replace('/confirm');
48 else if (profile) router.replace('/dashboard');
49 }, [profile]);
50
51 const onSubmit = useCallback(
52 async e => {
53 if (e.preventDefault) e.preventDefault();
54
55 try {
56 await sendForgotPassword({variables: {email}});
57 setIsSent(true);
58 } catch (error) {
59 if (error.message === 'Bad Request') {
60 addToast(t('lost_password.error'));
61 setError(t('lost_password.error'));
62 } else {
63 addToast(t('generic.errors.unknown'));
64 }
65 }
66 return false;
67 },
68 [sendForgotPassword, email, addToast, t]
69 );
70
71 if (!loading && isSent) return <LostPasswordSuccess email={email} />;
72
73 return (
74 <Root onSubmit={onSubmit}>
75 <Card>
76 <CardContent>
77 <TextField
78 label={t('lost_password.email')}
79 fullWidth
80 required={true}
81 margin="dense"
82 value={email}
83 onChange={({target: {value = ''}}) => setEmail(value)}
84 id="LostPasswordEmail"
85 name="email"
86 type="email"
87 error={!!error}
88 helperText={
89 error && (
90 <>
91 {error}
92 <Link href="/auth/register">
93 {t('lost_password.actions.register')}
94 </Link>
95 </>
96 )
97 }
98 />
99 </CardContent>
100 <CardActions className={classes.actions}>
101 <Button id="LostPasswordRegister" href="/auth/login">
102 {t('lost_password.actions.cancel')}
103 </Button>
104
105 <Button
106 color="primary"
107 variant="contained"
108 type="submit"
109 disabled={!canSubmit}
110 aria-disabled={!canSubmit}
111 id="LostPasswordSubmit"
112 >
113 {t('lost_password.actions.send')}
114 {loading && (
115 <CircularProgress
116 className={classes.loader}
117 color="primary"
118 size={20}
119 />
120 )}
121 </Button>
122 </CardActions>
123 </Card>
124 </Root>
125 );
126};
127
128export default LostPassword;