"use client" import { useState, useEffect } from "react" import { useRouter } from "next/navigation" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Badge } from "@/components/ui/badge" import { ScrollArea } from "@/components/ui/scroll-area" import { ArrowLeft, Calendar, Database, FileText, Trash2, Clock, Activity, ThumbsUp, LogOut, ArrowRightLeft, Trophy } from "lucide-react" import Link from "next/link" import ComparisonChart from "@/components/neurolink/comparison-chart" // --- CORRECTION ICI : On récupère l'URL du Cloud définie dans Vercel --- const API_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000" const CircularProgress = ({ value, color, label, icon: Icon }: any) => { const radius = 30; const circumference = 2 * Math.PI * radius; const offset = circumference - (value / 100) * circumference return (
{value}%
{Icon && } {label}
) } export default function AdminPage() { const [sessions, setSessions] = useState([]) const [isAuthorized, setIsAuthorized] = useState(false) const router = useRouter() const [isCompareMode, setIsCompareMode] = useState(false) const [sessionA, setSessionA] = useState(null); const [dataA, setDataA] = useState([]); const [statsA, setStatsA] = useState(null) const [sessionB, setSessionB] = useState(null); const [dataB, setDataB] = useState([]); const [statsB, setStatsB] = useState(null) useEffect(() => { const token = localStorage.getItem("startech_admin_token") if (token !== "authorized_access_granted") { router.push("/admin/login") } else { setIsAuthorized(true); // --- UTILISATION DE L'API CLOUD --- fetch(`${API_URL}/api/sessions`) .then(res => res.json()) .then(data => setSessions(data)) .catch(err => console.error("Erreur chargement sessions:", err)) } }, []) const handleSelectSession = (sessionId: number) => { // --- UTILISATION DE L'API CLOUD --- fetch(`${API_URL}/api/sessions/${sessionId}`).then(res => res.json()).then(response => { const info = response.info; const data = response.data; const stats = calculateStatsInternal(data) if (isCompareMode) { if (!sessionA) { setSessionA(info); setDataA(data); setStatsA(stats) } else if (!sessionB && sessionId !== sessionA.id) { setSessionB(info); setDataB(data); setStatsB(stats) } else if (sessionA && sessionB) { setSessionA(info); setDataA(data); setStatsA(stats); setSessionB(null); setDataB([]); setStatsB(null) } } else { setSessionA(info); setDataA(data); setStatsA(stats); setSessionB(null); setDataB([]); setStatsB(null) } }) } const calculateStatsInternal = (data: any[]) => { if (data.length === 0) return null const avg = (key: string) => Math.round(data.reduce((acc, curr) => acc + curr[key], 0) / data.length) return { duration: data.length, avg_engagement: avg('engagement_val'), avg_satisfaction: avg('satisfaction_val'), dominant_label: data[data.length - 1]?.satisfaction_lbl || "N/A" } } const toggleCompareMode = () => { setIsCompareMode(!isCompareMode); setSessionB(null); setDataB([]); setStatsB(null) } const handleDeleteSession = async (e: React.MouseEvent, sessionId: number) => { e.stopPropagation(); if (!confirm("Supprimer définitivement ?")) return // --- UTILISATION DE L'API CLOUD --- const res = await fetch(`${API_URL}/api/sessions/${sessionId}`, { method: 'DELETE' }) if (res.ok) { setSessions(prev => prev.filter(s => s.id !== sessionId)); if (sessionA?.id === sessionId) { setSessionA(null); setDataA([]); setStatsA(null) }; if (sessionB?.id === sessionId) { setSessionB(null); setDataB([]); setStatsB(null) } } } const handleExport = (session: any, data: any) => { if (!data.length) return const headers = ["Temps", "Emotion", "Score IA", "Engagement", "Label Engagement", "Satisfaction", "Label Satisfaction", "Confiance", "Fidelite", "Avis"] const rows = data.map((row: any) => [ String(row.session_time).replace('.', ','), row.emotion, row.emotion_score ? String(row.emotion_score.toFixed(2)).replace('.', ',') : "0", String(row.engagement_val), `"${row.engagement_lbl}"`, String(row.satisfaction_val), `"${row.satisfaction_lbl}"`, String(row.trust_val), String(row.loyalty_val), `"${row.opinion_lbl}"` ]) const csvContent = [headers.join(";"), ...rows.map((e: any) => e.join(";"))].join("\n") const blob = new Blob(["\uFEFF" + csvContent], { type: "text/csv;charset=utf-8;" }); const link = document.createElement("a"); link.href = URL.createObjectURL(blob); link.setAttribute("download", `Rapport_${session.first_name}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link) } const formatDate = (dateStr: string) => { if (!dateStr) return "Date inconnue"; try { return new Date(dateStr).toLocaleString('fr-FR', { day: 'numeric', month: 'short', hour: '2-digit', minute:'2-digit' }) } catch (e) { return "Erreur date" } } if (!isAuthorized) return null return (

STARTECH ADMIN

Historique

{sessions.map((session) => { const isA = sessionA?.id === session.id; const isB = sessionB?.id === session.id let activeClass = "border-l-4 border-l-transparent" if (isA) activeClass = "bg-blue-50 border-l-blue-500"; if (isB) activeClass = "bg-orange-50 border-l-orange-500" return (
handleSelectSession(session.id)} className={`group flex items-center justify-between p-4 border-b border-slate-100 hover:bg-slate-50 cursor-pointer transition-all ${activeClass}`}>
{session.first_name} {session.last_name} {isA && A} {isB && B}
{formatDate(session.created_at)}
) })}
{!isCompareMode && sessionA && statsA && (

{sessionA.first_name} {sessionA.last_name}

Durée: {statsA.duration}s | ID: {sessionA.client_id || "N/A"}

Verdict
{statsA.dominant_label}
Analyse Temporelle Données Brutes Complètes
{dataA.map((row, i) => ())}
TempsÉmotionScore IAEngagementSatisfactionConfianceFidélitéAvis
{row.session_time}s{row.emotion}{row.emotion_score?.toFixed(1)}%
{row.engagement_val}%{row.engagement_lbl}
50 ? "text-green-600" : "text-orange-500"}`}>{row.satisfaction_val}%{row.satisfaction_lbl}
{row.trust_val}%{row.trust_lbl}
{row.loyalty_val}%{row.loyalty_lbl}
{row.opinion_lbl}
)} {isCompareMode && sessionA && sessionB && statsA && statsB && (
{sessionA.first_name}
Session A
VS
{sessionB.first_name}
Session B
Duel d'Engagement
statsB.avg_engagement ? "bg-blue-50" : ""}`}>{sessionA.first_name}{statsA.avg_engagement > statsB.avg_engagement && Vainqueur} statsA.avg_engagement ? "bg-orange-50" : ""}`}>{sessionB.first_name}{statsB.avg_engagement > statsA.avg_engagement && Vainqueur}
)} {(!sessionA) &&

Sélectionnez une session à gauche pour commencer.

} {(isCompareMode && sessionA && !sessionB) &&
Session A : {sessionA.first_name} sélectionnée.

Maintenant, sélectionnez la Session B dans la liste.

}
) }