import { useEffect, useState } from 'react'; import { useAuth } from '../lib/AuthContext.jsx'; import { api, seasonLabel } from '../lib/api.js'; import ImageSlot from '../components/ImageSlot.jsx'; import { AdminShell } from './Admin.jsx'; function LoginSection({ title = 'Gérez votre présence au Club', kicker = 'Espace membre' }) { const { login } = useAuth(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const [busy, setBusy] = useState(false); const submit = async (e) => { e.preventDefault(); setError(''); setBusy(true); try { await login(email, password); } catch (err) { setError(err.message); } finally { setBusy(false); } }; return (
{kicker}

{title}

{error &&

{error}

}
); } function PasswordCard() { const [form, setForm] = useState({ currentPassword: '', newPassword: '' }); const [msg, setMsg] = useState(null); const submit = async (e) => { e.preventDefault(); setMsg(null); try { await api.post('/api/auth/change-password', form); setMsg({ ok: true, text: '✓ Mot de passe modifié' }); setForm({ currentPassword: '', newPassword: '' }); } catch (err) { setMsg({ ok: false, text: err.message }); } }; return (

Mot de passe

10 caractères minimum, avec au moins une lettre et un chiffre.

{msg && {msg.text}}
); } // Blocking gate shown right after login when the account still carries a // temporary password (new member, or an admin reset). The temporary // password itself doubles as "mot de passe actuel" here. function ForcedPasswordChange() { const { logout, refreshUser } = useAuth(); const [form, setForm] = useState({ currentPassword: '', newPassword: '' }); const [confirm, setConfirm] = useState(''); const [error, setError] = useState(''); const [busy, setBusy] = useState(false); const submit = async (e) => { e.preventDefault(); setError(''); if (form.newPassword !== confirm) { setError('Les deux mots de passe ne correspondent pas.'); return; } setBusy(true); try { await api.post('/api/auth/change-password', form); await refreshUser(); } catch (err) { setError(err.message); } finally { setBusy(false); } }; return (
Première connexion

Choisissez votre mot de passe

Votre mot de passe temporaire doit être remplacé avant de continuer.

{error &&

{error}

}
); } function Portal() { const { logout } = useAuth(); const [member, setMember] = useState(null); const [categories, setCategories] = useState([]); const [form, setForm] = useState(null); const [saved, setSaved] = useState(false); const [error, setError] = useState(''); const season = seasonLabel(); useEffect(() => { Promise.all([api.get('/api/member/profile'), api.get('/api/public/bootstrap')]) .then(([p, b]) => { setMember(p.member); setForm(p.member); setCategories(b.categories); }) .catch((e) => setError(e.message)); }, []); if (!form) { return (

{error || 'Chargement…'}

); } const onChange = (e) => { const { name, value } = e.target; setForm({ ...form, [name]: name === 'categorie_id' ? (value ? Number(value) : null) : value }); setSaved(false); }; const save = async (e) => { e.preventDefault(); setError(''); try { const d = await api.put('/api/member/profile', { nom: form.nom, secteur: form.secteur, categorie_id: form.categorie_id, dirigeant: form.dirigeant, email: form.email || '', tel: form.tel || '', site: form.site || '', presentation: form.presentation || '', }); setMember(d.member); setForm(d.member); setSaved(true); } catch (err) { setError(err.message); } }; const valide = member?.valide; const catName = categories.find((c) => c.id === form.categorie_id)?.name || 'Non classée'; return (
Espace membre

Bonjour {member.dirigeant}

{member.nom}
{valide ? '✓' : '⏳'}
{valide ? `Adhésion validée pour la saison ${season}` : 'Adhésion à renouveler'}
{valide ? "Votre fiche est visible dans l'annuaire et vous pouvez vous inscrire aux rencontres." : "Tant que votre adhésion n'est pas validée par le Club, votre fiche n'apparaît pas dans l'annuaire et vous ne pouvez pas vous inscrire aux rencontres."}

Mon profil

Ces informations alimentent votre fiche dans l'annuaire des membres.

Logo
{ setForm((f) => ({ ...f, logo_path: path })); setMember((m) => ({ ...m, logo_path: path })); }} />
Photo dirigeant·e
{ setForm((f) => ({ ...f, photo_path: path })); setMember((m) => ({ ...m, photo_path: path })); }} />