221 lines
6.2 KiB
JavaScript
221 lines
6.2 KiB
JavaScript
import { useQuery, useMutation, gql } from "@apollo/client";
|
||
import Grid from '@mui/material/Grid'
|
||
import { makeStyles } from '@mui/styles'
|
||
import Paper from '@mui/material/Paper'
|
||
import { Field, Form, Formik } from 'formik'
|
||
import React, { useReducer } from 'react'
|
||
import { useLocation, useHistory } from 'react-router-dom'
|
||
import { H2, Label3, P } from 'src/components/typography'
|
||
import Logo from 'src/styling/icons/menu/logo.svg?react'
|
||
import * as Yup from 'yup'
|
||
|
||
import { Button } from 'src/components/buttons'
|
||
import { SecretInput } from 'src/components/inputs/formik'
|
||
|
||
import styles from './shared.styles'
|
||
|
||
const QueryParams = () => new URLSearchParams(useLocation().search)
|
||
const useStyles = makeStyles(styles)
|
||
|
||
const VALIDATE_REGISTER_LINK = gql`
|
||
query validateRegisterLink($token: String!) {
|
||
validateRegisterLink(token: $token) {
|
||
username
|
||
role
|
||
}
|
||
}
|
||
`
|
||
|
||
const REGISTER = gql`
|
||
mutation register(
|
||
$token: String!
|
||
$username: String!
|
||
$password: String!
|
||
$role: String!
|
||
) {
|
||
register(
|
||
token: $token
|
||
username: $username
|
||
password: $password
|
||
role: $role
|
||
)
|
||
}
|
||
`
|
||
|
||
const PASSWORD_MIN_LENGTH = 8
|
||
const validationSchema = Yup.object({
|
||
password: Yup.string()
|
||
.required('A password is required')
|
||
.min(
|
||
PASSWORD_MIN_LENGTH,
|
||
`Your password must contain at least ${PASSWORD_MIN_LENGTH} characters`
|
||
),
|
||
confirmPassword: Yup.string()
|
||
.required('Please confirm the password')
|
||
.oneOf([Yup.ref('password')], 'Passwords must match')
|
||
})
|
||
|
||
const initialValues = {
|
||
password: '',
|
||
confirmPassword: ''
|
||
}
|
||
|
||
const initialState = {
|
||
username: null,
|
||
role: null,
|
||
result: ''
|
||
}
|
||
|
||
const reducer = (state, action) => {
|
||
const { type, payload } = action
|
||
return { ...state, ...payload, result: type }
|
||
}
|
||
|
||
const getErrorMsg = (
|
||
formikErrors,
|
||
formikTouched,
|
||
queryError,
|
||
mutationError
|
||
) => {
|
||
if (!formikErrors || !formikTouched) return null
|
||
if (queryError || mutationError) return 'Internal server error'
|
||
if (formikErrors.password && formikTouched.password)
|
||
return formikErrors.password
|
||
if (formikErrors.confirmPassword && formikTouched.confirmPassword)
|
||
return formikErrors.confirmPassword
|
||
return null
|
||
}
|
||
|
||
const Register = () => {
|
||
const classes = useStyles()
|
||
const history = useHistory()
|
||
const token = QueryParams().get('t')
|
||
|
||
const [state, dispatch] = useReducer(reducer, initialState)
|
||
|
||
const queryOptions = {
|
||
variables: { token: token },
|
||
onCompleted: ({ validateRegisterLink: info }) => {
|
||
if (!info) {
|
||
return dispatch({
|
||
type: 'failure'
|
||
})
|
||
}
|
||
dispatch({
|
||
type: 'success',
|
||
payload: {
|
||
username: info.username,
|
||
role: info.role
|
||
}
|
||
})
|
||
},
|
||
onError: () =>
|
||
dispatch({
|
||
type: 'failure'
|
||
})
|
||
}
|
||
|
||
const { error: queryError, loading } = useQuery(
|
||
VALIDATE_REGISTER_LINK,
|
||
queryOptions
|
||
)
|
||
|
||
const [register, { error: mutationError }] = useMutation(REGISTER, {
|
||
onCompleted: ({ register: success }) => {
|
||
if (success) history.push('/wizard', { fromAuthRegister: true })
|
||
}
|
||
})
|
||
|
||
return (
|
||
<Grid
|
||
container
|
||
spacing={0}
|
||
direction="column"
|
||
alignItems="center"
|
||
justifyContent="center"
|
||
className={classes.welcomeBackground}>
|
||
<Grid>
|
||
<div>
|
||
<Paper elevation={1}>
|
||
<div className={classes.wrapper}>
|
||
<div className={classes.titleWrapper}>
|
||
<Logo className={classes.icon} />
|
||
<H2 className={classes.title}>Lamassu Admin</H2>
|
||
</div>
|
||
{!loading && state.result === 'success' && (
|
||
<Formik
|
||
validationSchema={validationSchema}
|
||
initialValues={initialValues}
|
||
onSubmit={values => {
|
||
register({
|
||
variables: {
|
||
token: token,
|
||
username: state.username,
|
||
password: values.password,
|
||
role: state.role
|
||
}
|
||
})
|
||
}}>
|
||
{({ errors, touched }) => (
|
||
<Form id="register-form">
|
||
<Field
|
||
name="password"
|
||
label="Insert a password"
|
||
autoFocus
|
||
component={SecretInput}
|
||
size="lg"
|
||
fullWidth
|
||
className={classes.input}
|
||
/>
|
||
<Field
|
||
name="confirmPassword"
|
||
label="Confirm your password"
|
||
component={SecretInput}
|
||
size="lg"
|
||
fullWidth
|
||
/>
|
||
<div className={classes.footer}>
|
||
{getErrorMsg(
|
||
errors,
|
||
touched,
|
||
queryError,
|
||
mutationError
|
||
) && (
|
||
<P className={classes.errorMessage}>
|
||
{getErrorMsg(
|
||
errors,
|
||
touched,
|
||
queryError,
|
||
mutationError
|
||
)}
|
||
</P>
|
||
)}
|
||
<Button
|
||
type="submit"
|
||
form="register-form"
|
||
buttonClassName={classes.loginButton}>
|
||
Done
|
||
</Button>
|
||
</div>
|
||
</Form>
|
||
)}
|
||
</Formik>
|
||
)}
|
||
{!loading && state.result === 'failure' && (
|
||
<>
|
||
<Label3>Link has expired</Label3>
|
||
<Label3>
|
||
To obtain a new link, run the command{' '}
|
||
<strong>lamassu-register</strong> in your server’s terminal.
|
||
</Label3>
|
||
</>
|
||
)}
|
||
</div>
|
||
</Paper>
|
||
</div>
|
||
</Grid>
|
||
</Grid>
|
||
);
|
||
}
|
||
|
||
export default Register
|