Add registration tab in Koneksyon component

This commit is contained in:
Cédric FAMIBELLE-PRONZOLA
2022-02-06 18:40:47 +04:00
parent b74fb426ef
commit 5092dfc598
+257 -68
View File
@@ -2,45 +2,122 @@ import {useEffect, useState, forwardRef} from 'react'
import {signIn} from 'next-auth/react' import {signIn} from 'next-auth/react'
import {useRouter} from 'next/router' import {useRouter} from 'next/router'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Link from 'next/link' import Box from '@mui/material/Box'
import { import Button from '@mui/material/Button'
Box, import Container from '@mui/material/Container'
Button, import FormControl from '@mui/material/FormControl'
Container, import IconButton from '@mui/material/IconButton'
FormControl, import Input from '@mui/material/Input'
IconButton, import InputAdornment from '@mui/material/InputAdornment'
Input, import InputLabel from '@mui/material/InputLabel'
InputAdornment, import LinearProgress from '@mui/material/LinearProgress'
InputLabel, import Snackbar from '@mui/material/Snackbar'
LinearProgress, import Tab from '@mui/material/Tab'
Snackbar, import Tabs from '@mui/material/Tabs'
Typography import Typography from '@mui/material/Typography'
} from '@mui/material' import Visibility from '@mui/icons-material/Visibility'
import {Visibility, VisibilityOff} from '@mui/icons-material' import VisibilityOff from '@mui/icons-material/VisibilityOff'
import MuiAlert from '@mui/material/Alert' import MuiAlert from '@mui/material/Alert'
import LoginIcon from '@mui/icons-material/Login'
import AppRegistrationRoundedIcon from '@mui/icons-material/AppRegistrationRounded'
import axios from 'axios'
import {validateEmail} from '../../lib/utils/emails' import {validateEmail} from '../../lib/utils/emails'
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000' const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:1337'
function TabPanel(props) {
const {children, value, index, ...other} = props
return (
<div
role='tabpanel'
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box sx={{p: 3}}>
{children}
</Box>
)}
</div>
)
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
}
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
}
}
const Alert = forwardRef(function Alert(props, ref) { const Alert = forwardRef(function Alert(props, ref) {
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} /> return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
}) })
function Koneksyon({detay, tit, soutit, titGwose, chimen}) { function Koneksyon({chimen}) {
const [loginError, setError] = useState('') const [loginError, setError] = useState('')
const [credentials, setCredentials] = useState({username: '', password: ''}) const [loginCredentials, setLoginCredentials] = useState({username: '', password: ''})
const [registerCredentials, setRegisterCredentials] = useState({username: '', email: '', password: ''})
const [passwordVerification, setPasswordVerification] = useState('')
const [showPassword, setShowPassword] = useState(false) const [showPassword, setShowPassword] = useState(false)
const [showRegisterPassword, setShowRegisterPassword] = useState(false)
const [showVerificationPassword, setShowVerificationPassword] = useState(false)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [open, setOpen] = useState(true) const [open, setOpen] = useState(true)
const [registrationSuccess, setRegistrationSuccess] = useState(false)
const [value, setValue] = useState(0)
const router = useRouter() const router = useRouter()
const handleUpdate = update => { const handleUpdate = update => {
setCredentials({...credentials, ...update}) setLoginCredentials({...loginCredentials, ...update})
} }
const handleClick = async () => { const handleRegisterUpdate = update => {
if (!validateEmail(credentials.username) || credentials.password === '') { setRegisterCredentials({...registerCredentials, ...update})
}
const handleChange = (event, newValue) => {
setValue(newValue)
}
const register = async () => {
try {
const response = await axios.post(`${apiUrl}/auth/local/register`, {
...registerCredentials
}, {
headers: {
'content-type': 'application/json'
}
})
localStorage.setItem('user-id', response?.data?.user?._id)
setRegistrationSuccess(true)
resetRegisterForm()
} catch (error) {
if (error.message.endsWith(400)) {
setError('Email ou utilisateur déjà enregistré')
} else {
setError('Une erreur sest produite')
}
}
}
const resetRegisterForm = () => {
setRegisterCredentials({username: '', email: '', password: ''})
setPasswordVerification('')
}
const handleClickLogin = async () => {
if (!validateEmail(loginCredentials.username) || loginCredentials.password === '') {
return return
} }
@@ -48,7 +125,7 @@ function Koneksyon({detay, tit, soutit, titGwose, chimen}) {
const response = await signIn('credentials', { const response = await signIn('credentials', {
callbackUrl: `${siteUrl}${chimen}`, callbackUrl: `${siteUrl}${chimen}`,
redirect: false, redirect: false,
...credentials ...loginCredentials
}) })
if (response.error) { if (response.error) {
setError(response.error) setError(response.error)
@@ -59,12 +136,35 @@ function Koneksyon({detay, tit, soutit, titGwose, chimen}) {
} }
} }
const handleClickRegister = async () => {
setLoading(true)
if (!validateEmail(registerCredentials.email) || registerCredentials.password === '') {
return
}
if (registerCredentials.password !== passwordVerification) {
setError('Les 2 mots de passe de correspondent pas')
setLoading(false)
return
}
if (registerCredentials.username.length < 3) {
setError('Le nom dutilisateur est trop court, 3 caratères minimum')
setLoading(false)
return
}
await register()
setLoading(false)
}
const handleClose = (event, reason) => { const handleClose = (event, reason) => {
if (reason === 'clickaway') { if (reason === 'clickaway') {
return return
} }
setOpen(false) setOpen(false)
setRegistrationSuccess(false)
setError('') setError('')
} }
@@ -82,47 +182,64 @@ function Koneksyon({detay, tit, soutit, titGwose, chimen}) {
setShowPassword(!showPassword) setShowPassword(!showPassword)
} }
const handleClickShowRegisterPassword = () => {
setShowRegisterPassword(!showRegisterPassword)
}
const handleClickShowVerificationPassword = () => {
setShowVerificationPassword(!showVerificationPassword)
}
const handleMouseDownPassword = event => { const handleMouseDownPassword = event => {
event.preventDefault() event.preventDefault()
} }
const handleKeyUp = event => { const handleMouseDownRegisterPassword = event => {
event.preventDefault()
}
const handleMouseDownVerificationPassword = event => {
event.preventDefault()
}
const handleKeyUpLogin = event => {
if (event.keyCode === 13) { if (event.keyCode === 13) {
handleClick() handleClickLogin()
}
}
const handleKeyUpRegister = event => {
if (event.keyCode === 13) {
handleClickRegister()
} }
} }
return ( return (
<Container maxWidth='sm'> <Container sx={{marginTop: 2}} maxWidth='sm'>
{tit && (
<Box sx={{textAlign: 'center', marginTop: 5}}>
<Typography display='inline' variant={`h${titGwose}`} component='h1'>
{tit}
</Typography>
{soutit && (
<Typography>
<small>{soutit}</small>
</Typography>
)}
</Box>
)}
<FormControl fullWidth style={{marginTop: '1em'}} autoComplete='off'> <Box sx={{width: '100%'}}>
<Tabs centered value={value} aria-label='basic tabs example' onChange={handleChange}>
<Tab icon={<LoginIcon />} label='Se connecter' {...a11yProps(0)} />
<Tab icon={<AppRegistrationRoundedIcon />} label='Sinscrire' {...a11yProps(1)} />
</Tabs>
<TabPanel value={value} index={0}>
<FormControl fullWidth autoComplete='off'>
<InputLabel htmlFor='username'>Email</InputLabel> <InputLabel htmlFor='username'>Email</InputLabel>
<Input <Input
value={credentials.username} autoComplete='email'
value={loginCredentials.username}
name='username' name='username'
type='email' type='email'
id='email' id='email'
onChange={event => handleUpdate({username: event.target.value})} onChange={event => handleUpdate({username: event.target.value})}
onKeyUp={handleKeyUp} onKeyUp={handleKeyUpLogin}
/> />
</FormControl> </FormControl>
<FormControl fullWidth style={{marginTop: '1em'}}> <FormControl fullWidth style={{marginTop: '1em'}}>
<InputLabel htmlFor='password'>Mot de passe</InputLabel> <InputLabel htmlFor='password'>Mot de passe</InputLabel>
<Input <Input
value={credentials.password} value={loginCredentials.password}
name='password' name='password'
type={showPassword ? 'text' : 'password'} type={showPassword ? 'text' : 'password'}
id='password' id='password'
@@ -139,39 +256,112 @@ function Koneksyon({detay, tit, soutit, titGwose, chimen}) {
</InputAdornment> </InputAdornment>
} }
onChange={event => handleUpdate({password: event.target.value})} onChange={event => handleUpdate({password: event.target.value})}
onKeyUp={handleKeyUp} onKeyUp={handleKeyUpLogin}
/> />
</FormControl> </FormControl>
<Button <Button
fullWidth fullWidth
disabled={loading || !validateEmail(credentials.username) || credentials.password === ''} disabled={loading || !validateEmail(loginCredentials.username) || loginCredentials.password === ''}
style={{marginTop: 20}} style={{marginTop: 20}}
variant='contained' variant='contained'
color='primary' color='primary'
onClick={handleClick} onClick={handleClickLogin}
> >
<Typography style={{fontWeight: 'bold'}}> <Typography style={{fontWeight: 'bold'}}>
Connexion Connexion
</Typography> </Typography>
</Button> </Button>
</TabPanel>
<TabPanel value={value} index={1}>
<FormControl fullWidth autoComplete='off'>
<InputLabel htmlFor='register-username'>Nom dutilisateur</InputLabel>
<Input
value={registerCredentials.username}
autoComplete='username'
name='register-username'
type='text'
id='register-username'
onChange={event => handleRegisterUpdate({username: event.target.value})}
onKeyUp={handleKeyUpRegister}
/>
</FormControl>
<FormControl fullWidth style={{marginTop: '1em'}} autoComplete='off'>
<InputLabel htmlFor='register-email'>Email</InputLabel>
<Input
value={registerCredentials.email}
autoComplete='email'
name='register-email'
type='email'
id='register-email'
onChange={event => handleRegisterUpdate({email: event.target.value})}
onKeyUp={handleKeyUpRegister}
/>
</FormControl>
<FormControl fullWidth style={{marginTop: '1em'}}>
<InputLabel htmlFor='password'>Mot de passe</InputLabel>
<Input
value={registerCredentials.password}
name='register-password'
type={showRegisterPassword ? 'text' : 'password'}
id='register-password'
endAdornment={
<InputAdornment position='end'>
<IconButton
aria-label='password visibility'
size='large'
onClick={handleClickShowRegisterPassword}
onMouseDown={handleMouseDownRegisterPassword}
>
{showRegisterPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
onChange={event => handleRegisterUpdate({password: event.target.value})}
onKeyUp={handleKeyUpRegister}
/>
</FormControl>
<FormControl fullWidth style={{marginTop: '1em'}}>
<InputLabel htmlFor='password'>Vérification du mot de passe</InputLabel>
<Input
value={passwordVerification}
name='verification-password'
type={showVerificationPassword ? 'text' : 'password'}
id='verification-password'
error={registerCredentials.password !== passwordVerification}
endAdornment={
<InputAdornment position='end'>
<IconButton
aria-label='password visibility'
size='large'
onClick={handleClickShowVerificationPassword}
onMouseDown={handleMouseDownVerificationPassword}
>
{showVerificationPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
onChange={event => setPasswordVerification(event.target.value)}
onKeyUp={handleKeyUpRegister}
/>
</FormControl>
<Button
fullWidth
disabled={loading || !validateEmail(registerCredentials.email) || registerCredentials.username === '' || registerCredentials.password === ''}
style={{marginTop: 20}}
variant='contained'
color='primary'
onClick={handleClickRegister}
>
<Typography style={{fontWeight: 'bold'}}>
Inscription
</Typography>
</Button>
</TabPanel>
</Box>
{loading && <LinearProgress size={24} style={{width: '100%', marginTop: '1em'}} />} {loading && <LinearProgress size={24} style={{width: '100%', marginTop: '1em'}} />}
{detay && (
<Box sx={{textAlign: 'center', marginTop: 3}}>
<Typography display='block' variant='h6' component='h2'>
Pour obtenir un accès, faites-en la demande
</Typography>
<Typography style={{fontSize: 20}} display='block'>
&#x1F4E9;
</Typography>
<Link passHref href='mailto:kontak@oki.re?subject=Accès à #OKi'>
<a style={{color: 'green', fontSize: 20, textDecoration: 'none', fontWeight: 'bold'}}>kontak@oki.re</a>
</Link>
</Box>
)}
{loginError && ( {loginError && (
<Snackbar <Snackbar
open={open} open={open}
@@ -181,22 +371,21 @@ function Koneksyon({detay, tit, soutit, titGwose, chimen}) {
<Alert severity='error' onClose={handleClose}><strong>{loginError}</strong></Alert> <Alert severity='error' onClose={handleClose}><strong>{loginError}</strong></Alert>
</Snackbar> </Snackbar>
)} )}
{registrationSuccess && (
<Snackbar
open={registrationSuccess}
autoHideDuration={15_000}
onClose={handleClose}
>
<Alert severity='success' onClose={handleClose}><strong>Inscription réussie. Veuillez confirmer votre adresse email, via le lien qui vous a été envoyé.</strong></Alert>
</Snackbar>
)}
</Container> </Container>
) )
} }
Koneksyon.defaultProps = {
detay: false,
tit: null,
soutit: null,
titGwose: 5
}
Koneksyon.propTypes = { Koneksyon.propTypes = {
detay: PropTypes.bool,
tit: PropTypes.string,
soutit: PropTypes.string,
titGwose: PropTypes.number,
chimen: PropTypes.string.isRequired chimen: PropTypes.string.isRequired
} }