#7 Introduce proper error handling on sign-up
This commit is contained in:
parent
b6f6adac22
commit
2979f1b1af
|
@ -1,8 +1,8 @@
|
|||
import React, {useState} from 'react';
|
||||
import React, {ChangeEvent, useState} from 'react';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import {Link} from 'react-router-dom';
|
||||
import {Link, useHistory} from 'react-router-dom';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
|
||||
|
@ -12,6 +12,7 @@ import Container from '@material-ui/core/Container';
|
|||
import {Copyright} from "./Copyright";
|
||||
import {gql, useMutation} from "@apollo/client";
|
||||
import ButtonWithSpinner from "./ButtonWithSpinner";
|
||||
import {errorHandler, SignUpError} from "./SignUpErrorHandler";
|
||||
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
|
@ -45,14 +46,49 @@ export default function SignUp() {
|
|||
const [password, setPassword] = useState("");
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [createAccount, {loading, error, data}] = useMutation<RegisterMutationResponse, RegisterMutationVariables>(
|
||||
registerMutation
|
||||
const [error, setError] = useState<SignUpError | undefined>(undefined)
|
||||
const history = useHistory();
|
||||
const [createAccount, {loading, data}] = useMutation<RegisterMutationResponse, RegisterMutationVariables>(
|
||||
registerMutation,
|
||||
{
|
||||
onCompleted: (data) => {history.push("/login")},
|
||||
onError: (e) => {console.error(e); setPassword(""); setError(errorHandler(e))}
|
||||
}
|
||||
);
|
||||
const classes = useStyles();
|
||||
|
||||
|
||||
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
createAccount({variables: {firstName, lastName, email, password}}).catch(error => console.log(error));
|
||||
createAccount({variables: {firstName, lastName, email, password}});
|
||||
}
|
||||
|
||||
const onFirstNameChange = (e: ChangeEvent<HTMLTextAreaElement|HTMLInputElement>) => {
|
||||
setFirstName(e.target.value)
|
||||
if (error?.firstNameInvalid) {
|
||||
setError(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
const onLastNameChange = (e: ChangeEvent<HTMLTextAreaElement|HTMLInputElement>) => {
|
||||
setLastName(e.target.value)
|
||||
if (error?.lastNameInvalid) {
|
||||
setError(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
const onEmailChange = (e: ChangeEvent<HTMLTextAreaElement|HTMLInputElement>) => {
|
||||
setEmail(e.target.value)
|
||||
if (error?.emailInvalid) {
|
||||
setError(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
const onPasswordChange = (e: ChangeEvent<HTMLTextAreaElement|HTMLInputElement>) => {
|
||||
setPassword(e.target.value)
|
||||
if (error?.passwordInvalid) {
|
||||
setError(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -78,7 +114,8 @@ export default function SignUp() {
|
|||
label="First Name"
|
||||
autoFocus
|
||||
value={firstName}
|
||||
onChange={(e) => setFirstName(e.target.value)}
|
||||
onChange={onFirstNameChange}
|
||||
error={error?.firstNameInvalid}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
|
@ -91,7 +128,8 @@ export default function SignUp() {
|
|||
name="lastName"
|
||||
autoComplete="lname"
|
||||
value={lastName}
|
||||
onChange={(e) => setLastName(e.target.value)}
|
||||
onChange={onLastNameChange}
|
||||
error={error?.lastNameInvalid}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
|
@ -104,7 +142,8 @@ export default function SignUp() {
|
|||
name="email"
|
||||
autoComplete="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
onChange={onEmailChange}
|
||||
error={error?.emailInvalid}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
|
@ -118,7 +157,8 @@ export default function SignUp() {
|
|||
id="password"
|
||||
autoComplete="current-password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
onChange={onPasswordChange}
|
||||
error={error?.passwordInvalid}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
@ -131,7 +171,7 @@ export default function SignUp() {
|
|||
</ButtonWithSpinner>
|
||||
{
|
||||
error
|
||||
? <p className={classes.error}> `Error while trying to create a new account: ${error.message}`}</p>
|
||||
? <p className={classes.error}>{error.message}</p>
|
||||
: data && data.registerPerson.person.nodeId
|
||||
? <p className={classes.success}>`Created new account successfully.
|
||||
<Link to={"/login"}>Return to login page</Link></p>
|
||||
|
|
62
redaktions-app/src/components/SignUpErrorHandler.ts
Normal file
62
redaktions-app/src/components/SignUpErrorHandler.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import {ApolloError} from "@apollo/client";
|
||||
|
||||
|
||||
export interface SignUpError {
|
||||
message: string,
|
||||
emailInvalid: boolean,
|
||||
firstNameInvalid: boolean,
|
||||
lastNameInvalid: boolean,
|
||||
passwordInvalid: boolean
|
||||
}
|
||||
|
||||
const parseErrorMessage = (error: ApolloError): string => {
|
||||
let result = "Sign-up failed because of the following reason(s): ";
|
||||
if (isEmailAlreadyUsed(error)) {
|
||||
result += "The E-Mail is already in use. "
|
||||
}
|
||||
if (isFirstNameInvalid(error)) {
|
||||
result += "The provided 'First Name' is invalid. "
|
||||
}
|
||||
if (isLastNameInvalid(error)) {
|
||||
result += "The provided 'Last Name' is invalid. "
|
||||
}
|
||||
if (isPasswordInvalid(error)) {
|
||||
result += "The provided password is invalid. "
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const isEmailAlreadyUsed = (error: ApolloError): boolean => {
|
||||
const errorMessage = error.message.toLowerCase();
|
||||
|
||||
return errorMessage.includes("unique-constraint") && errorMessage.includes("email");
|
||||
}
|
||||
|
||||
const isFirstNameInvalid = (error: ApolloError): boolean => {
|
||||
const errorMessage = error.message.toLowerCase();
|
||||
|
||||
return errorMessage.includes("invalid") && errorMessage.includes("first name");
|
||||
}
|
||||
|
||||
const isLastNameInvalid = (error: ApolloError): boolean => {
|
||||
const errorMessage = error.message.toLowerCase();
|
||||
|
||||
return errorMessage.includes("invalid") && errorMessage.includes("last name");
|
||||
}
|
||||
|
||||
const isPasswordInvalid = (error: ApolloError): boolean => {
|
||||
const errorMessage = error.message.toLowerCase();
|
||||
|
||||
return errorMessage.includes("invalid") && errorMessage.includes("password");
|
||||
}
|
||||
|
||||
export const errorHandler = (error: undefined | ApolloError): undefined | SignUpError => {
|
||||
return error ? {
|
||||
message: parseErrorMessage(error),
|
||||
emailInvalid: isEmailAlreadyUsed(error),
|
||||
firstNameInvalid: isFirstNameInvalid(error),
|
||||
lastNameInvalid: isLastNameInvalid(error),
|
||||
passwordInvalid: isPasswordInvalid(error)
|
||||
} : undefined
|
||||
}
|
||||
|
Loading…
Reference in a new issue