import { useState, useRef } from 'react' import { Link, useNavigate } from 'react-router-dom' import { registerApi, verifyCodeApi } from '../services/auth' import { useAuth } from '../context/AuthContext' import usePageMeta from '../hooks/usePageMeta' import Captcha from '../components/Captcha' import { CAPTCHA_ENABLED } from '../config/captcha' import { isPasswordValid, PASSWORD_RULES_ERROR } from '../utils/passwordRules' import PasswordRules from '../components/PasswordRules' // Une naissance ne peut pas être dans le futur : borne haute du sélecteur. const AUJOURD_HUI = new Date().toISOString().split('T')[0] // Le jeu est réservé aux personnes majeures. function hasAtLeast18Years(birthdate) { const birth = new Date(birthdate) const today = new Date() let age = today.getFullYear() - birth.getFullYear() const monthDiff = today.getMonth() - birth.getMonth() if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) { age-- } return age >= 18 } // Valeurs alignées sur le tableau de bord admin, qui compte exactement // "Homme" et "Femme" ; toute autre valeur retombe dans la catégorie "autre". const GENRES = ['Femme', 'Homme', 'Autre'] export default function Inscription() { usePageMeta({ title: 'Créer un compte | Thé Tip Top', description: "Inscrivez-vous en quelques instants pour participer au jeu-concours 100 % Gagnant Thé Tip Top et saisir le code de votre ticket de caisse.", }) const navigate = useNavigate() const { login } = useAuth() // Étape : 'form' | 'verify' const [step, setStep] = useState('form') const [email, setEmail] = useState('') const [form, setForm] = useState({ email: '', lastName: '', firstName: '', password: '', confirmPassword: '', birthdate: '', gender: '', }) const [acceptedTerms, setAcceptedTerms] = useState(false) // Consentement marketing : distinct des CGU et décoché par défaut, il doit // rester un choix libre et non une condition d'inscription. const [marketingOptIn, setMarketingOptIn] = useState(false) const [showPassword, setShowPassword] = useState(false) const [error, setError] = useState('') const [loading, setLoading] = useState(false) const [captchaToken, setCaptchaToken] = useState('') const captchaRef = useRef() // Code à 4 chiffres const [digits, setDigits] = useState(['', '', '', '']) const [codeError, setCodeError] = useState('') const [codeLoading, setCodeLoading] = useState(false) const inputRefs = [useRef(), useRef(), useRef(), useRef()] const handleChange = (e) => setForm({ ...form, [e.target.name]: e.target.value }) // Signalé dès que la confirmation est saisie, sans attendre l'envoi. const passwordMismatch = form.confirmPassword !== '' && form.password !== form.confirmPassword // Même route que la connexion : le provider crée le compte à la première venue. const handleOAuthSignup = (provider) => { const apiUrl = import.meta.env.VITE_API_URL || '' window.location.href = `${apiUrl}/api/auth/${provider}` } // Étape 1 — Inscription const handleSubmit = async (e) => { e.preventDefault() setError('') if (!hasAtLeast18Years(form.birthdate)) { setError('Vous devez avoir au moins 18 ans pour vous inscrire.') return } if (!isPasswordValid(form.password)) { setError(PASSWORD_RULES_ERROR) return } if (form.password !== form.confirmPassword) { setError('Les deux mots de passe ne correspondent pas.') return } setLoading(true) try { await registerApi({ email: form.email, firstname: form.firstName, lastname: form.lastName, password: form.password, confirmPassword: form.confirmPassword, birthdate: form.birthdate, gender: form.gender, marketingOptIn, captchaToken, }) setEmail(form.email) setStep('verify') } catch (err) { setError(err.message) // Le jeton a été consommé par le backend : on en redemande un. captchaRef.current?.reset() setCaptchaToken('') } finally { setLoading(false) } } // Étape 2 — Saisie du code const handleDigit = (index, value) => { if (!/^\d?$/.test(value)) return const next = [...digits] next[index] = value setDigits(next) if (value && index < 3) inputRefs[index + 1].current?.focus() } const handleDigitKeyDown = (index, e) => { if (e.key === 'Backspace' && !digits[index] && index > 0) { inputRefs[index - 1].current?.focus() } } const handleVerify = async (e) => { e.preventDefault() const code = digits.join('') if (code.length !== 4) return setCodeError('') setCodeLoading(true) try { const data = await verifyCodeApi({ email, code }) login(data.user, data.token) navigate('/saisir-code-unique') } catch (err) { setCodeError(err.message) setDigits(['', '', '', '']) inputRefs[0].current?.focus() } finally { setCodeLoading(false) } } // ── Étape 2 : Vérification du code ── if (step === 'verify') { return (

Vérifiez votre email

Un code à 4 chiffres a été envoyé à
{email}

{codeError && (
{codeError}
)}
{digits.map((d, i) => ( handleDigit(i, e.target.value)} onKeyDown={(e) => handleDigitKeyDown(i, e)} aria-label={`Chiffre ${i + 1} du code de vérification`} className="w-14 h-14 text-center text-2xl font-bold border-2 border-gray-200 rounded-xl focus:outline-none focus:border-[#006B6B] focus:ring-1 focus:ring-[#006B6B] transition-colors" /> ))}

Le code expire dans 15 minutes.{' '}

) } // ── Étape 1 : Formulaire d'inscription ── return (

S'inscrire

Créer votre compte

{error && (
{error}
)}

Le jeu-concours est réservé aux personnes majeures.

{passwordMismatch && (

Les deux mots de passe ne correspondent pas.

)}
Ou

Vous avez déjà un compte ?{' '} Se connecter

) }