frontend/containers/SignUpForm/index.tsx (view raw)
1import {useState, useMemo} from 'react';
2import {useTranslation} from 'react-i18next';
3import TextField from '@material-ui/core/TextField';
4import {useRouter} from 'next/router';
5import Button from '@material-ui/core/Button';
6import CardContent from '@material-ui/core/CardContent';
7import CardActions from '@material-ui/core/CardActions';
8import Typography from '@material-ui/core/Typography';
9import CircularProgress from '@material-ui/core/CircularProgress';
10import {makeStyles} from '@material-ui/core/styles';
11import useToastsStore from '../../stores/useToastStore';
12import {useRegisterMutation} from '../../generated/graphql';
13import Link from 'next/link';
14
15const SignUp = () => {
16 const {t, i18n} = useTranslation();
17 const classes = useStyles();
18 const addToast = useToastsStore(s => s.addToast);
19 const router = useRouter();
20 const [isLoading, setIsLoading] = useState(false);
21 const [error, setError] = useState('');
22 const [firstName, setFirstName] = useState('');
23 const [lastName, setLastName] = useState('');
24 const [email, setEmail] = useState('');
25 const [password, setPassword] = useState('');
26 const [register] = useRegisterMutation();
27
28 const canSubmit = useMemo(
29 () =>
30 [firstName, lastName, email, password].filter(s => s.length < 2)
31 .length === 0,
32 [firstName, lastName, email, password]
33 );
34
35 const onSubmit = async e => {
36 e.preventDefault?.();
37 if (isLoading) return;
38 setIsLoading(true);
39 try {
40 const lang = i18n.language.toUpperCase();
41 await register({
42 variables: {
43 user: {
44 username: email,
45 email,
46 password,
47 firstName,
48 lastName,
49 lang,
50 },
51 },
52 });
53 router.push('/auth/confirm');
54 } catch (error) {
55 const strapiError = error.message;
56 console.error({strapiError});
57 if (strapiError === 'Email or Username are already taken')
58 setError(t('signup.errors.email_taken'));
59 else addToast(t(`generic.errors.unknown`));
60 }
61 setIsLoading(false);
62 return false;
63 };
64
65 return (
66 <form onSubmit={onSubmit}>
67 <CardContent className={classes.content}>
68 <Typography variant="h6">{t('signup.title')}</Typography>
69 <TextField
70 label={t('signup.firstName')}
71 fullWidth
72 autoFocus
73 margin="dense"
74 value={firstName}
75 required={true}
76 onChange={({target: {value = ''}}) => setFirstName(value)}
77 id="SignUpFirstName"
78 name="firstName"
79 />
80 <TextField
81 label={t('signup.lastName')}
82 fullWidth
83 required={true}
84 margin="dense"
85 value={lastName}
86 onChange={({target: {value = ''}}) => setLastName(value)}
87 id="SignUpLastName"
88 name="lastName"
89 />
90 <TextField
91 label={t('signup.email')}
92 fullWidth
93 required={true}
94 error={!!error}
95 helperText={error}
96 margin="dense"
97 value={email}
98 onChange={({target: {value = ''}}) => setEmail(value)}
99 id="SignUpEmail"
100 name="email"
101 type="email"
102 />
103 <TextField
104 label={t('signup.password')}
105 fullWidth
106 required={true}
107 margin="dense"
108 value={password}
109 onChange={({target: {value = ''}}) => setPassword(value)}
110 id="SignUpEmail"
111 name="password"
112 type="password"
113 />
114 </CardContent>
115 <CardActions className={classes.actions}>
116 <Link href="/auth/login" passHref>
117 <Button id="SignUpLogin" variant="text">
118 {t('signup.login')}
119 </Button>
120 </Link>
121 <Button
122 color="primary"
123 variant="contained"
124 type="submit"
125 disabled={!canSubmit}
126 className={classes.button}
127 aria-disabled={!canSubmit}
128 id="SignUpSubmit"
129 endIcon={
130 isLoading && (
131 <CircularProgress
132 className={classes.loader}
133 size={20}
134 color="secondary"
135 />
136 )
137 }
138 >
139 {t('signup.submit')}
140 </Button>
141 </CardActions>
142 </form>
143 );
144};
145
146const getStrapiError = error => {
147 try {
148 if (error.message?.[0]?.messages?.[0])
149 return error.message[0].messages[0].id;
150 return error?.graphQLErrors?.[0].extensions.exception.data.message?.[0]
151 ?.messages[0].id;
152 } catch {
153 return 'generic.error';
154 }
155};
156
157const useStyles = makeStyles(theme => ({
158 content: {
159 display: 'flex',
160 flexDirection: 'column',
161 alignItems: 'center',
162 },
163 loader: {
164 marginLeft: '14px',
165 color: theme.palette.background.paper,
166 },
167 actions: {
168 justifyContent: 'center',
169 marginBottom: theme.spacing(2),
170 },
171 button: {
172 margin: theme.spacing(1),
173 },
174}));
175export default SignUp;