43f1f6e9f2
sign.js : - aria-label sur les 4 Fab (Se déconnecter, dashboard, Se connecter, S'enregistrer) - Correction des guillemets typographiques U+2018/U+2019 en ASCII (empêchaient le parsing JSX) - Suppression de useMemo inutilisé - IIFE async ;() → startSubscription() nommée + .catch() explicite (semi-style + no-void) auth-form/index.js : - aria-label des IconButton visibility traduits en français avec état dynamique : 'Afficher/Masquer le mot de passe' et 'Afficher/Masquer la vérification' version-timeline.js : - aria-label='Comparer les versions' sur IconButton Comparer - aria-label dynamique + aria-expanded sur le bouton expand/collapse - Correction object-curly-newline et jsx-closing-bracket-location (pré-existants) version-search.js : - inputProps aria-label='Rechercher dans les versions' (placeholder seul insuffisant) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
221 lines
6.9 KiB
JavaScript
221 lines
6.9 KiB
JavaScript
/* eslint-disable camelcase */
|
||
import PropTypes from 'prop-types'
|
||
import Link from 'next/link'
|
||
import {useState} from 'react'
|
||
import Button from '@mui/material/Button'
|
||
import Container from '@mui/material/Container'
|
||
import Box from '@mui/material/Box'
|
||
import Typography from '@mui/material/Typography'
|
||
import InputAdornment from '@mui/material/InputAdornment'
|
||
import IconButton from '@mui/material/IconButton'
|
||
import FormControl from '@mui/material/FormControl'
|
||
import FormHelperText from '@mui/material/FormHelperText'
|
||
import OutlinedInput from '@mui/material/OutlinedInput'
|
||
import InputLabel from '@mui/material/InputLabel'
|
||
import Visibility from '@mui/icons-material/Visibility'
|
||
import VisibilityOff from '@mui/icons-material/VisibilityOff'
|
||
|
||
export default function AuthForm({
|
||
title,
|
||
buttonText,
|
||
onSubmit,
|
||
linkText,
|
||
linkHref,
|
||
linkDescription,
|
||
isRegister
|
||
}) {
|
||
const [formData, setFormData] = useState({
|
||
first_name: '',
|
||
email: '',
|
||
password: '',
|
||
password_verification: ''
|
||
})
|
||
|
||
const [showPassword, setShowPassword] = useState(false)
|
||
const [showPasswordVerification, setShowPasswordVerification] = useState(false)
|
||
|
||
const handleFormSubmit = async e => {
|
||
e.preventDefault()
|
||
onSubmit(formData)
|
||
setFormData({
|
||
first_name: '',
|
||
email: '',
|
||
password: '',
|
||
password_verification: ''
|
||
})
|
||
}
|
||
|
||
const handleInputChange = e => {
|
||
setFormData({
|
||
...formData,
|
||
[e.target.name]: e.target.value,
|
||
})
|
||
}
|
||
|
||
const handleClickShowPassword = () => {
|
||
setShowPassword(!showPassword)
|
||
}
|
||
|
||
const handleMouseDownPassword = event => {
|
||
event.preventDefault()
|
||
}
|
||
|
||
const handleClickShowPasswordVerifiation = () => {
|
||
setShowPasswordVerification(!showPasswordVerification)
|
||
}
|
||
|
||
const handleMouseDownPasswordVerification = event => {
|
||
event.preventDefault()
|
||
}
|
||
|
||
return (
|
||
<Container
|
||
maxWidth='sm'
|
||
sx={{
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
minHeight: '100vh',
|
||
}}
|
||
>
|
||
<Box
|
||
component='form'
|
||
sx={{
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
gap: 2,
|
||
width: '100%',
|
||
p: 3,
|
||
border: '1px solid #ccc',
|
||
borderRadius: '8px',
|
||
boxShadow: 3,
|
||
bgcolor: 'background.paper'
|
||
}}
|
||
onSubmit={handleFormSubmit}
|
||
>
|
||
<Typography variant='h4' component='h1' align='center'>
|
||
{title}
|
||
</Typography>
|
||
{isRegister && (
|
||
<FormControl required>
|
||
<InputLabel htmlFor='first_name'>Pseudo</InputLabel>
|
||
<OutlinedInput
|
||
required
|
||
fullWidth
|
||
label='Pseudo'
|
||
name='first_name'
|
||
id='first_name'
|
||
value={formData.first_name}
|
||
onChange={handleInputChange}
|
||
/>
|
||
</FormControl>
|
||
)}
|
||
<FormControl required>
|
||
<InputLabel htmlFor='email'>E-mail</InputLabel>
|
||
<OutlinedInput
|
||
required
|
||
fullWidth
|
||
autoComplete='email'
|
||
label='E-mail'
|
||
type='email'
|
||
name='email'
|
||
id='email'
|
||
value={formData.email}
|
||
onChange={handleInputChange}
|
||
/>
|
||
</FormControl>
|
||
<FormControl required>
|
||
<InputLabel htmlFor='password'>Mot de passe</InputLabel>
|
||
<OutlinedInput
|
||
required
|
||
fullWidth
|
||
autoComplete='new-password' // Disable auto complete
|
||
label='Mot de passe'
|
||
type={showPassword ? 'text' : 'password'}
|
||
name='password'
|
||
id='password'
|
||
endAdornment={
|
||
<InputAdornment position='end'>
|
||
<IconButton
|
||
aria-label={showPassword ? 'Masquer le mot de passe' : 'Afficher le mot de passe'}
|
||
size='large'
|
||
onClick={handleClickShowPassword}
|
||
onMouseDown={handleMouseDownPassword}
|
||
>
|
||
{showPassword ? <Visibility /> : <VisibilityOff />}
|
||
</IconButton>
|
||
</InputAdornment>
|
||
}
|
||
value={formData.password}
|
||
onChange={handleInputChange}
|
||
/>
|
||
</FormControl>
|
||
{isRegister && (
|
||
<FormControl required error={formData.password !== formData.password_verification}>
|
||
<InputLabel htmlFor='password_verification'>Vérification du mot de passe</InputLabel>
|
||
<OutlinedInput
|
||
fullWidth
|
||
autoComplete='new-password' // Disable auto complete
|
||
label='Vérification du mot de passe'
|
||
type={showPasswordVerification ? 'text' : 'password'}
|
||
name='password_verification'
|
||
id='password_verification'
|
||
value={formData.password_verification}
|
||
error={formData.password !== formData.password_verification}
|
||
aria-describedby='password_verification'
|
||
endAdornment={
|
||
<InputAdornment position='end'>
|
||
<IconButton
|
||
aria-label={showPasswordVerification ? 'Masquer la vérification du mot de passe' : 'Afficher la vérification du mot de passe'}
|
||
size='large'
|
||
onClick={handleClickShowPasswordVerifiation}
|
||
onMouseDown={handleMouseDownPasswordVerification}
|
||
>
|
||
{showPasswordVerification ? <Visibility /> : <VisibilityOff />}
|
||
</IconButton>
|
||
</InputAdornment>
|
||
}
|
||
onChange={handleInputChange}
|
||
/>
|
||
{formData.password !== formData.password_verification && (
|
||
<FormHelperText id='password_verification'>Les mots de passe ne correspondent pas !</FormHelperText>
|
||
)}
|
||
</FormControl>
|
||
)}
|
||
<Button fullWidth variant='contained' color='success' type='submit'>
|
||
{buttonText}
|
||
</Button>
|
||
<Typography variant='body2' align='center'>
|
||
{linkDescription}{' '}
|
||
<Link passHref href={linkHref}>
|
||
<Button color='success'>{linkText}</Button>
|
||
</Link>
|
||
</Typography>
|
||
{!isRegister && (
|
||
<Typography align='center'>
|
||
<Link passHref style={{color: 'white'}} href='/request-reset-password'>
|
||
Mot de passe oublié
|
||
</Link>
|
||
</Typography>
|
||
)}
|
||
</Box>
|
||
<Typography align='center' mt={2}>
|
||
<Link passHref style={{color: 'white'}} href='/'>
|
||
Retourner à l’accueil
|
||
</Link>
|
||
</Typography>
|
||
</Container>
|
||
)
|
||
}
|
||
|
||
AuthForm.propTypes = {
|
||
title: PropTypes.string.isRequired,
|
||
buttonText: PropTypes.string.isRequired,
|
||
onSubmit: PropTypes.func.isRequired,
|
||
linkText: PropTypes.string.isRequired,
|
||
linkHref: PropTypes.string.isRequired,
|
||
linkDescription: PropTypes.string.isRequired,
|
||
isRegister: PropTypes.bool.isRequired
|
||
}
|