merge: integrate Emmanuel changes into main

This commit is contained in:
2026-09-17 18:36:09 +00:00
108 changed files with 4335 additions and 515 deletions

View File

@@ -1,6 +1,7 @@
import { useEffect, useRef, useState } from 'react'
import { useEffect, useRef } from 'react'
import { useNavigate, useSearchParams, Link } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
import { homeFor } from '../config/roles'
// Point d'arrivée après un aller-retour OAuth : le backend nous renvoie ici
// avec le JWT et le profil encodés dans l'URL.
@@ -8,46 +9,40 @@ export default function AuthCallback() {
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const { login } = useAuth()
const errorParam = searchParams.get('error')
const [error, setError] = useState(errorParam || '')
// StrictMode monte deux fois en dev : on ne traite le token qu'une seule fois.
const handled = useRef(false)
const errorParam = searchParams.get('error')
const token = searchParams.get('token')
const encodedUser = searchParams.get('user')
let error = ''
let user = null
if (errorParam) {
error = errorParam
} else if (!token || !encodedUser) {
error = 'Réponse de connexion incomplète.'
} else {
try {
// atob renvoie des octets : on les relit en UTF-8.
const bytes = Uint8Array.from(
atob(encodedUser),
(c) => c.charCodeAt(0)
)
user = JSON.parse(new TextDecoder().decode(bytes))
} catch {
error = 'Réponse de connexion illisible.'
}
}
useEffect(() => {
if (handled.current) return
if (handled.current || !user) return
handled.current = true
if (errorParam) return
const token = searchParams.get('token')
const encodedUser = searchParams.get('user')
if (!token || !encodedUser) {
setTimeout(() => {
setError('Réponse de connexion incomplète.')
}, 0)
return
}
try {
const user = JSON.parse(atob(encodedUser))
login(user, token)
if (user.role === 'ADMIN') {
navigate('/admin', { replace: true })
} else if (user.role === 'EMPLOYEE') {
navigate('/employe', { replace: true })
} else {
navigate('/mes-gains', { replace: true })
}
} catch {
setTimeout(() => {
setError('Réponse de connexion illisible.')
}, 0)
}
}, [searchParams, errorParam, login, navigate])
login(user, token)
navigate(homeFor(user), { replace: true })
}, [user, token, login, navigate])
if (error) {
return (