react-garden
Version:
React + TypeScript + ThreeJS app using Material UI on NextJS, Apollo Client, GraphQL + WordPress REST APIs, for ThreeD web development.. a part of the threed.ai code family.
436 lines (410 loc) • 17.6 kB
JavaScript
// ** React Imports
import { useState, Fragment } from 'react'
// ** Next Imports
import Link from 'next/link'
// ** MUI Components
import Button from '@mui/material/Button'
import Divider from '@mui/material/Divider'
import Checkbox from '@mui/material/Checkbox'
import TextField from '@mui/material/TextField'
import InputLabel from '@mui/material/InputLabel'
import IconButton from '@mui/material/IconButton'
import Box from '@mui/material/Box'
import FormControl from '@mui/material/FormControl'
import useMediaQuery from '@mui/material/useMediaQuery'
import OutlinedInput from '@mui/material/OutlinedInput'
import { styled, useTheme } from '@mui/material/styles'
import FormHelperText from '@mui/material/FormHelperText'
import InputAdornment from '@mui/material/InputAdornment'
import FormControlLabel from '@mui/material/FormControlLabel'
import Typography from '@mui/material/Typography'
// ** Icons Imports
import Google from 'mdi-material-ui/Google'
import Github from 'mdi-material-ui/Github'
import Twitter from 'mdi-material-ui/Twitter'
import Facebook from 'mdi-material-ui/Facebook'
import EyeOutline from 'mdi-material-ui/EyeOutline'
import EyeOffOutline from 'mdi-material-ui/EyeOffOutline'
// ** Third Party Imports
import * as yup from 'yup'
import { yupResolver } from '@hookform/resolvers/yup'
import { useForm, Controller } from 'react-hook-form'
// ** Configs
import themeConfig from '~/configs/themeConfig'
// ** Layout Import
import BlankLayout from '~/@core/layouts/BlankLayout'
// ** Hooks
import { useAuth } from '~/hooks/useAuth'
import { useSettings } from '~/@core/hooks/useSettings'
// ** Demo Imports
import FooterIllustrationsV2 from '~/views/pages/auth/FooterIllustrationsV2'
const defaultValues = {
email: '',
username: '',
password: '',
terms: false
}
// ** Styled Components
const RegisterIllustrationWrapper = styled(Box)(({ theme }) => ({
padding: theme.spacing(20),
paddingRight: '0 !important',
[theme.breakpoints.down('lg')]: {
padding: theme.spacing(10)
}
}))
const RegisterIllustration = styled('img')(({ theme }) => ({
maxWidth: '46rem',
[theme.breakpoints.down('lg')]: {
maxWidth: '35rem'
}
}))
const TreeIllustration = styled('img')(({ theme }) => ({
bottom: 0,
left: '1.875rem',
position: 'absolute',
[theme.breakpoints.down('lg')]: {
left: 0
}
}))
const RightWrapper = styled(Box)(({ theme }) => ({
width: '100%',
[theme.breakpoints.up('md')]: {
maxWidth: 450
}
}))
const BoxWrapper = styled(Box)(({ theme }) => ({
[theme.breakpoints.down('xl')]: {
width: '100%'
},
[theme.breakpoints.down('md')]: {
maxWidth: 400
}
}))
const TypographyStyled = styled(Typography)(({ theme }) => ({
fontWeight: 600,
marginBottom: theme.spacing(1.5),
[theme.breakpoints.down('md')]: { mt: theme.spacing(8) }
}))
const LinkStyled = styled('a')(({ theme }) => ({
textDecoration: 'none',
color: theme.palette.primary.main
}))
const Register = () => {
// ** States
const [showPassword, setShowPassword] = useState(false)
// ** Hooks
const theme = useTheme()
const { register } = useAuth()
const { settings } = useSettings()
const hidden = useMediaQuery(theme.breakpoints.down('md'))
// ** Vars
const { skin } = settings
const schema = yup.object().shape({
password: yup.string().min(5).required(),
username: yup.string().min(3).required(),
email: yup.string().email().required(),
terms: yup.bool().oneOf([true], 'You must accept the privacy policy & terms')
})
const {
control,
setError,
handleSubmit,
formState: { errors }
} = useForm({
defaultValues,
mode: 'onBlur',
resolver: yupResolver(schema)
})
const onSubmit = data => {
const { email, username, password } = data
register({ email, username, password }, err => {
if (err.email) {
setError('email', {
type: 'manual',
message: err.email
})
}
if (err.username) {
setError('username', {
type: 'manual',
message: err.username
})
}
})
}
const imageSource = skin === 'bordered' ? 'auth-v2-register-illustration-bordered' : 'auth-v2-register-illustration'
return (
<Box className='content-right'>
{!hidden ? (
<Box sx={{ flex: 1, display: 'flex', position: 'relative', alignItems: 'center', justifyContent: 'center' }}>
<RegisterIllustrationWrapper>
<RegisterIllustration
alt='register-illustration'
src={`/images/pages/${imageSource}-${theme.palette.mode}.png`}
/>
</RegisterIllustrationWrapper>
<FooterIllustrationsV2 image={<TreeIllustration alt='tree' src='/images/pages/tree-2.png' />} />
</Box>
) : null}
<RightWrapper sx={skin === 'bordered' && !hidden ? { borderLeft: `1px solid ${theme.palette.divider}` } : {}}>
<Box
sx={{
p: 12,
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'background.paper'
}}
>
<BoxWrapper>
<Box
sx={{
top: 30,
left: 40,
display: 'flex',
position: 'absolute',
alignItems: 'center',
justifyContent: 'center'
}}
>
<svg
width={35}
height={29}
version='1.1'
viewBox='0 0 30 23'
xmlns='http://www.w3.org/2000/svg'
xmlnsXlink='http://www.w3.org/1999/xlink'
>
<g stroke='none' strokeWidth='1' fill='none' fillRule='evenodd'>
<g id='Artboard' transform='translate(-95.000000, -51.000000)'>
<g id='logo' transform='translate(95.000000, 50.000000)'>
<path
id='Combined-Shape'
fill={theme.palette.primary.main}
d='M30,21.3918362 C30,21.7535219 29.9019196,22.1084381 29.7162004,22.4188007 C29.1490236,23.366632 27.9208668,23.6752135 26.9730355,23.1080366 L26.9730355,23.1080366 L23.714971,21.1584295 C23.1114106,20.7972624 22.7419355,20.1455972 22.7419355,19.4422291 L22.7419355,19.4422291 L22.741,12.7425689 L15,17.1774194 L7.258,12.7425689 L7.25806452,19.4422291 C7.25806452,20.1455972 6.88858935,20.7972624 6.28502902,21.1584295 L3.0269645,23.1080366 C2.07913318,23.6752135 0.850976404,23.366632 0.283799571,22.4188007 C0.0980803893,22.1084381 2.0190442e-15,21.7535219 0,21.3918362 L0,3.58469444 L0.00548573643,3.43543209 L0.00548573643,3.43543209 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 L15,9.19354839 L26.9548759,1.86636639 C27.2693965,1.67359571 27.6311047,1.5715689 28,1.5715689 C29.1045695,1.5715689 30,2.4669994 30,3.5715689 L30,3.5715689 Z'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='0 8.58870968 7.25806452 12.7505183 7.25806452 16.8305646'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='0 8.58870968 7.25806452 12.6445567 7.25806452 15.1370162'
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='22.7419355 8.58870968 30 12.7417372 30 16.9537453'
transform='translate(26.370968, 12.771227) scale(-1, 1) translate(-26.370968, -12.771227) '
/>
<polygon
id='Rectangle'
opacity='0.077704'
fill={theme.palette.common.black}
points='22.7419355 8.58870968 30 12.6409734 30 15.2601969'
transform='translate(26.370968, 11.924453) scale(-1, 1) translate(-26.370968, -11.924453) '
/>
<path
id='Rectangle'
fillOpacity='0.15'
fill={theme.palette.common.white}
d='M3.04512412,1.86636639 L15,9.19354839 L15,9.19354839 L15,17.1774194 L0,8.58649679 L0,3.5715689 C3.0881846e-16,2.4669994 0.8954305,1.5715689 2,1.5715689 C2.36889529,1.5715689 2.73060353,1.67359571 3.04512412,1.86636639 Z'
/>
<path
id='Rectangle'
fillOpacity='0.35'
fill={theme.palette.common.white}
transform='translate(22.500000, 8.588710) scale(-1, 1) translate(-22.500000, -8.588710) '
d='M18.0451241,1.86636639 L30,9.19354839 L30,9.19354839 L30,17.1774194 L15,8.58649679 L15,3.5715689 C15,2.4669994 15.8954305,1.5715689 17,1.5715689 C17.3688953,1.5715689 17.7306035,1.67359571 18.0451241,1.86636639 Z'
/>
</g>
</g>
</g>
</svg>
<Typography
variant='h6'
sx={{
ml: 3,
lineHeight: 1,
fontWeight: 600,
textTransform: 'uppercase',
fontSize: '1.5rem !important'
}}
>
{themeConfig.templateName}
</Typography>
</Box>
<Box sx={{ mb: 6 }}>
<TypographyStyled variant='h5'>Adventure starts here 🚀</TypographyStyled>
<Typography variant='body2'>Make your app management easy and fun!</Typography>
</Box>
<form noValidate autoComplete='off' onSubmit={handleSubmit(onSubmit)}>
<FormControl fullWidth sx={{ mb: 4 }}>
<Controller
name='username'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange, onBlur } }) => (
<TextField
autoFocus
value={value}
onBlur={onBlur}
label='Username'
onChange={onChange}
placeholder='johndoe'
error={Boolean(errors.username)}
/>
)}
/>
{errors.username && (
<FormHelperText sx={{ color: 'error.main' }}>{errors.username.message}</FormHelperText>
)}
</FormControl>
<FormControl fullWidth sx={{ mb: 4 }}>
<Controller
name='email'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange, onBlur } }) => (
<TextField
value={value}
label='Email'
onBlur={onBlur}
onChange={onChange}
error={Boolean(errors.email)}
placeholder='user@email.com'
/>
)}
/>
{errors.email && <FormHelperText sx={{ color: 'error.main' }}>{errors.email.message}</FormHelperText>}
</FormControl>
<FormControl fullWidth>
<InputLabel htmlFor='auth-login-v2-password' error={Boolean(errors.password)}>
Password
</InputLabel>
<Controller
name='password'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange, onBlur } }) => (
<OutlinedInput
value={value}
label='Password'
onBlur={onBlur}
onChange={onChange}
id='auth-login-v2-password'
error={Boolean(errors.password)}
type={showPassword ? 'text' : 'password'}
endAdornment={
<InputAdornment position='end'>
<IconButton
edge='end'
onMouseDown={e => e.preventDefault()}
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? <EyeOutline /> : <EyeOffOutline />}
</IconButton>
</InputAdornment>
}
/>
)}
/>
{errors.password && (
<FormHelperText sx={{ color: 'error.main' }}>{errors.password.message}</FormHelperText>
)}
</FormControl>
<FormControl sx={{ mt: 1.5, mb: 4 }} error={Boolean(errors.terms)}>
<Controller
name='terms'
control={control}
rules={{ required: true }}
render={({ field: { value, onChange } }) => {
return (
<FormControlLabel
sx={{
...(errors.terms ? { color: 'error.main' } : null),
'& .MuiFormControlLabel-label': { fontSize: '0.875rem' }
}}
control={
<Checkbox
checked={value}
onChange={onChange}
sx={errors.terms ? { color: 'error.main' } : null}
/>
}
label={
<>
<Typography
variant='body2'
component='span'
sx={{ color: errors.terms ? 'error.main' : '' }}
>
I agree to{' '}
</Typography>
<Link href='/' passHref>
<LinkStyled onClick={e => e.preventDefault()}>privacy policy & terms</LinkStyled>
</Link>
</>
}
/>
)
}}
/>
{errors.terms && (
<FormHelperText sx={{ mt: 0, color: 'error.main' }}>{errors.terms.message}</FormHelperText>
)}
</FormControl>
<Button fullWidth size='large' type='submit' variant='contained' sx={{ mb: 7 }}>
Sign up
</Button>
<Box sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', justifyContent: 'center' }}>
<Typography variant='body2' sx={{ mr: 2 }}>
Already have an account?
</Typography>
<Typography variant='body2'>
<Link href='/login' passHref>
<LinkStyled>Sign in instead</LinkStyled>
</Link>
</Typography>
</Box>
<Divider sx={{ my: 5 }}>or</Divider>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Facebook sx={{ color: '#497ce2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Twitter sx={{ color: '#1da1f2' }} />
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Github
sx={{ color: theme => (theme.palette.mode === 'light' ? '#272727' : theme.palette.grey[300]) }}
/>
</IconButton>
</Link>
<Link href='/' passHref>
<IconButton component='a' onClick={e => e.preventDefault()}>
<Google sx={{ color: '#db4437' }} />
</IconButton>
</Link>
</Box>
</form>
</BoxWrapper>
</Box>
</RightWrapper>
</Box>
)
}
Register.getLayout = page => <BlankLayout>{page}</BlankLayout>
Register.guestGuard = true
export default Register