index.js
1 import {useCallback, useState, useEffect} from 'react'; 2 import { styled } from '@mui/material/styles'; 3 import {useTranslation} from 'react-i18next'; 4 import router from 'next/router'; 5 import TextField from '@mui/material/TextField'; 6 import Button from '@mui/material/Button'; 7 import CardContent from '@mui/material/CardContent'; 8 import Card from '@mui/material/Card'; 9 import CircularProgress from '@mui/material/CircularProgress'; 10 import CardActions from '@mui/material/CardActions'; 11 import Link from '@mui/material/Link'; 12 import LostPasswordSuccess from './Success'; 13 import useToastStore from '../../stores/useToastStore'; 14 import useProfile from '../../hooks/useProfile'; 15 import {useForgotPasswordMutation} from '../../generated/graphql'; 16 17 const PREFIX = 'LostPassword'; 18 19 const classes = { 20 loader: `${PREFIX}-loader`, 21 actions: `${PREFIX}-actions` 22 }; 23 24 const 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 39 const 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 132 export default LostPassword;