import { useState, useEffect } from "react"; import { trpc } from "@/lib/trpc"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Switch } from "@/components/ui/switch"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Badge } from "@/components/ui/badge"; import { toast } from "sonner"; import { Loader2, Save, Settings, CheckCircle2, XCircle, History } from "lucide-react"; import DashboardLayout from "@/components/DashboardLayout"; export default function AdminParametres() { const { data: parametres, isLoading, refetch } = trpc.parametres.get.useQuery(); const { data: historique, isLoading: isLoadingHistorique } = trpc.parametres.getHistorique.useQuery({ limit: 20 }); const [urlPublique, setUrlPublique] = useState(""); const [delaiExpirationQR, setDelaiExpirationQR] = useState(30); const [dureeValiditeToken, setDureeValiditeToken] = useState(24); const [notificationsActives, setNotificationsActives] = useState(true); const [testUrlStatus, setTestUrlStatus] = useState<{ loading: boolean; result?: { accessible: boolean; message: string } }>({ loading: false }); // Initialiser les valeurs quand les données sont chargées useEffect(() => { if (parametres) { setUrlPublique(parametres.urlPublique); setDelaiExpirationQR(parametres.delaiExpirationQR); setDureeValiditeToken(parametres.dureeValiditeToken); setNotificationsActives(parametres.notificationsActives); } }, [parametres]); const updateMutation = trpc.parametres.update.useMutation({ onSuccess: () => { toast.success("Paramètres mis à jour avec succès"); refetch(); }, onError: (error) => { toast.error(`Erreur : ${error.message}`); }, }); const testUrlMutation = trpc.parametres.testerUrl.useMutation({ onSuccess: (result) => { setTestUrlStatus({ loading: false, result }); if (result.accessible) { toast.success(result.message); } else { toast.error(result.message); } }, onError: (error) => { setTestUrlStatus({ loading: false }); toast.error(`Erreur lors du test : ${error.message}`); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // Validation de l'URL try { new URL(urlPublique); } catch { toast.error("L'URL saisie n'est pas valide"); return; } updateMutation.mutate({ urlPublique, delaiExpirationQR, dureeValiditeToken, notificationsActives, }); }; const handleTestUrl = () => { try { new URL(urlPublique); setTestUrlStatus({ loading: true }); testUrlMutation.mutate({ url: urlPublique }); } catch { toast.error("L'URL saisie n'est pas valide"); } }; if (isLoading) { return (
); } return (

Paramètres de l'application

Configuration globale de l'application

{/* Configuration générale */} Configuration générale Paramètres globaux de l'application
{/* URL publique */}
{ setUrlPublique(e.target.value); setTestUrlStatus({ loading: false }); }} required className="flex-1" />

Cette URL est utilisée pour générer les QR codes d'émargement. Exemple : https://formations.itinova.org (sans slash à la fin)

{/* Délai d'expiration QR codes */}
setDelaiExpirationQR(parseInt(e.target.value))} required />

Durée de validité des QR codes d'émargement après leur génération (entre 5 et 120 minutes)

{/* Durée de validité des tokens */}
setDureeValiditeToken(parseInt(e.target.value))} required />

Durée pendant laquelle les tokens d'émargement restent valides (entre 1 et 72 heures)

{/* Notifications actives */}

Activer ou désactiver l'envoi automatique de notifications

{/* Historique des modifications */}
Historique des modifications
Traçabilité des changements de paramètres
{isLoadingHistorique ? (
) : !historique || historique.length === 0 ? (
Aucune modification enregistrée
) : (
Date Utilisateur Champ modifié Ancienne valeur Nouvelle valeur {historique.map((entry) => ( {new Date(entry.dateModification).toLocaleString('fr-FR', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', })} {entry.userName} {entry.champModifie} {entry.ancienneValeur || vide} {entry.nouvelleValeur || vide} ))}
)}
); }