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