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}&nbsp;
 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;