Add registration tab in Koneksyon component
This commit is contained in:
+257
-68
@@ -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 s’est 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 d’utilisateur 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='S’inscrire' {...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 d’utilisateur</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'>
|
|
||||||
📩
|
|
||||||
</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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user