import { useEffect, useState } from 'react'; import { Link, Navigate } from 'react-router-dom'; import { useAuth } from '../lib/AuthContext.jsx'; import { api, dateParts, statutLabel } from '../lib/api.js'; import { MembersTab, RencontresTab, InscriptionsTab } from '../components/admin/AdminTabs.jsx'; import { CategoriesTab, ContenuTab } from '../components/admin/AdminContent.jsx'; import { PastEventsTab } from '../components/admin/AdminPast.jsx'; import { UsersTab } from '../components/admin/AdminUsers.jsx'; // Moderators only get members/rencontres/inscriptions/rencontres passées // (create + edit, never delete) — everything else (dashboard, taxonomy, // site content, staff account management) is admin-only, enforced both // here (sidebar) and server-side (routes). const TABS = [ { key: 'dashboard', icon: '◧', label: 'Tableau de bord', title: 'Tableau de bord', roles: ['admin'] }, { key: 'membres', icon: '▤', label: 'Membres', title: 'Gestion des membres', roles: ['admin', 'moderator'] }, { key: 'rencontres', icon: '◈', label: 'Rencontres', title: 'Rencontres', roles: ['admin', 'moderator'] }, { key: 'passees', icon: '▦', label: 'Rencontres passées', title: 'Rencontres passées', roles: ['admin', 'moderator'] }, { key: 'inscriptions', icon: '✎', label: 'Inscriptions', title: 'Inscriptions', roles: ['admin', 'moderator'] }, { key: 'categories', icon: '☲', label: 'Catégories', title: 'Catégories', roles: ['admin'] }, { key: 'contenu', icon: '▧', label: 'Contenu du site', title: 'Contenu du site', roles: ['admin'] }, { key: 'utilisateurs', icon: '⚿', label: 'Administrateurs', title: 'Administrateurs & modérateurs', roles: ['admin'] }, ]; function Dashboard() { const [data, setData] = useState(null); useEffect(() => { api.get('/api/admin/dashboard').then(setData).catch(() => {}); }, []); if (!data) return
Chargement…
; const k = data.kpis; const daysToNext = k.prochaine_date ? Math.max(0, Math.round((new Date(k.prochaine_date) - Date.now()) / 86400000)) : null; const kpis = [ { n: k.membres_valides, l: 'Membres validés', d: 'saison en cours' }, { n: k.a_renouveler, l: 'À renouveler', d: 'non validés' }, { n: k.rencontres_a_venir, l: 'Rencontres à venir', d: daysToNext != null ? `prochaine dans ${daysToNext} j` : '—' }, { n: k.inscriptions_attente, l: 'Inscriptions en attente', d: 'à valider' }, ]; return ( <>