399 lines
13 KiB
JavaScript
399 lines
13 KiB
JavaScript
import {useEffect, useState, forwardRef} from 'react'
|
||
import {signIn} from 'next-auth/react'
|
||
import {useRouter} from 'next/router'
|
||
import PropTypes from 'prop-types'
|
||
import Box from '@mui/material/Box'
|
||
import Button from '@mui/material/Button'
|
||
import Container from '@mui/material/Container'
|
||
import FormControl from '@mui/material/FormControl'
|
||
import IconButton from '@mui/material/IconButton'
|
||
import Input from '@mui/material/Input'
|
||
import InputAdornment from '@mui/material/InputAdornment'
|
||
import InputLabel from '@mui/material/InputLabel'
|
||
import LinearProgress from '@mui/material/LinearProgress'
|
||
import Snackbar from '@mui/material/Snackbar'
|
||
import Tab from '@mui/material/Tab'
|
||
import Tabs from '@mui/material/Tabs'
|
||
import Typography from '@mui/material/Typography'
|
||
import Visibility from '@mui/icons-material/Visibility'
|
||
import VisibilityOff from '@mui/icons-material/VisibilityOff'
|
||
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'
|
||
|
||
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) {
|
||
return <MuiAlert ref={ref} elevation={6} variant='filled' {...props} />
|
||
})
|
||
|
||
function Koneksyon({chimen}) {
|
||
const [loginError, setError] = useState('')
|
||
const [loginCredentials, setLoginCredentials] = useState({username: '', password: ''})
|
||
const [registerCredentials, setRegisterCredentials] = useState({username: '', email: '', password: ''})
|
||
const [passwordVerification, setPasswordVerification] = useState('')
|
||
const [showPassword, setShowPassword] = useState(false)
|
||
const [showRegisterPassword, setShowRegisterPassword] = useState(false)
|
||
const [showVerificationPassword, setShowVerificationPassword] = useState(false)
|
||
const [loading, setLoading] = useState(false)
|
||
const [open, setOpen] = useState(true)
|
||
const [registrationSuccess, setRegistrationSuccess] = useState(false)
|
||
const [value, setValue] = useState(0)
|
||
const router = useRouter()
|
||
|
||
const handleUpdate = update => {
|
||
setLoginCredentials({...loginCredentials, ...update})
|
||
}
|
||
|
||
const handleRegisterUpdate = update => {
|
||
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 s’est produite')
|
||
}
|
||
}
|
||
}
|
||
|
||
const resetRegisterForm = () => {
|
||
setRegisterCredentials({username: '', email: '', password: ''})
|
||
setPasswordVerification('')
|
||
}
|
||
|
||
const handleClickLogin = async () => {
|
||
if (!validateEmail(loginCredentials.username) || loginCredentials.password === '') {
|
||
return
|
||
}
|
||
|
||
setLoading(true)
|
||
const response = await signIn('credentials', {
|
||
callbackUrl: `${siteUrl}${chimen}`,
|
||
redirect: false,
|
||
...loginCredentials
|
||
})
|
||
if (response.error) {
|
||
setError(response.error)
|
||
setLoading(false)
|
||
} else if (response.ok) {
|
||
setLoading(false)
|
||
router.push(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 d’utilisateur est trop court, 3 caratères minimum')
|
||
setLoading(false)
|
||
return
|
||
}
|
||
|
||
if (registerCredentials.password.length < 6) {
|
||
setError('Le mot de passe est trop court, 6 caratères minimum')
|
||
setLoading(false)
|
||
return
|
||
}
|
||
|
||
await register()
|
||
setLoading(false)
|
||
}
|
||
|
||
const handleClose = (event, reason) => {
|
||
if (reason === 'clickaway') {
|
||
return
|
||
}
|
||
|
||
setOpen(false)
|
||
setRegistrationSuccess(false)
|
||
setError('')
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (loginError) {
|
||
setOpen(true)
|
||
}
|
||
|
||
return () => {
|
||
setLoading(false)
|
||
}
|
||
}, [loginError])
|
||
|
||
const handleClickShowPassword = () => {
|
||
setShowPassword(!showPassword)
|
||
}
|
||
|
||
const handleClickShowRegisterPassword = () => {
|
||
setShowRegisterPassword(!showRegisterPassword)
|
||
}
|
||
|
||
const handleClickShowVerificationPassword = () => {
|
||
setShowVerificationPassword(!showVerificationPassword)
|
||
}
|
||
|
||
const handleMouseDownPassword = event => {
|
||
event.preventDefault()
|
||
}
|
||
|
||
const handleMouseDownRegisterPassword = event => {
|
||
event.preventDefault()
|
||
}
|
||
|
||
const handleMouseDownVerificationPassword = event => {
|
||
event.preventDefault()
|
||
}
|
||
|
||
const handleKeyUpLogin = event => {
|
||
if (event.keyCode === 13) {
|
||
handleClickLogin()
|
||
}
|
||
}
|
||
|
||
const handleKeyUpRegister = event => {
|
||
if (event.keyCode === 13) {
|
||
handleClickRegister()
|
||
}
|
||
}
|
||
|
||
return (
|
||
<Container sx={{marginTop: 2}} maxWidth='sm'>
|
||
|
||
<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='S’inscrire' {...a11yProps(1)} />
|
||
</Tabs>
|
||
<TabPanel value={value} index={0}>
|
||
<FormControl fullWidth autoComplete='off'>
|
||
<InputLabel htmlFor='username'>Email</InputLabel>
|
||
<Input
|
||
autoComplete='email'
|
||
value={loginCredentials.username}
|
||
name='username'
|
||
type='email'
|
||
id='email'
|
||
onChange={event => handleUpdate({username: event.target.value})}
|
||
onKeyUp={handleKeyUpLogin}
|
||
/>
|
||
</FormControl>
|
||
|
||
<FormControl fullWidth style={{marginTop: '1em'}}>
|
||
<InputLabel htmlFor='password'>Mot de passe</InputLabel>
|
||
<Input
|
||
value={loginCredentials.password}
|
||
name='password'
|
||
type={showPassword ? 'text' : 'password'}
|
||
id='password'
|
||
endAdornment={
|
||
<InputAdornment position='end'>
|
||
<IconButton
|
||
aria-label='password visibility'
|
||
size='large'
|
||
onClick={handleClickShowPassword}
|
||
onMouseDown={handleMouseDownPassword}
|
||
>
|
||
{showPassword ? <Visibility /> : <VisibilityOff />}
|
||
</IconButton>
|
||
</InputAdornment>
|
||
}
|
||
onChange={event => handleUpdate({password: event.target.value})}
|
||
onKeyUp={handleKeyUpLogin}
|
||
/>
|
||
</FormControl>
|
||
|
||
<Button
|
||
fullWidth
|
||
disabled={loading || !validateEmail(loginCredentials.username) || loginCredentials.password === ''}
|
||
style={{marginTop: 20}}
|
||
variant='contained'
|
||
color='primary'
|
||
onClick={handleClickLogin}
|
||
>
|
||
<Typography style={{fontWeight: 'bold'}}>
|
||
Connexion
|
||
</Typography>
|
||
</Button>
|
||
</TabPanel>
|
||
<TabPanel value={value} index={1}>
|
||
<FormControl fullWidth>
|
||
<InputLabel htmlFor='register-email'>Email</InputLabel>
|
||
<Input
|
||
autoComplete='email'
|
||
value={registerCredentials.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='register-username'>Nom d’utilisateur</InputLabel>
|
||
<Input
|
||
autoComplete='username'
|
||
value={registerCredentials.username}
|
||
name='register-username'
|
||
type='text'
|
||
id='register-username'
|
||
onChange={event => handleRegisterUpdate({username: 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'}} />}
|
||
|
||
{loginError && (
|
||
<Snackbar
|
||
open={open}
|
||
autoHideDuration={6000}
|
||
onClose={handleClose}
|
||
>
|
||
<Alert severity='error' onClose={handleClose}><strong>{loginError}</strong></Alert>
|
||
</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>
|
||
)
|
||
}
|
||
|
||
Koneksyon.propTypes = {
|
||
chimen: PropTypes.string.isRequired
|
||
}
|
||
|
||
export default Koneksyon
|