import { useRoute } from "wouter"; import { trpc } from "@/lib/trpc"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Progress } from "@/components/ui/progress"; import DashboardLayout from "@/components/DashboardLayout"; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, PieChart, Pie, Cell } from "recharts"; import { FileText, Users, CheckCircle2, TrendingUp, Download } from "lucide-react"; import { Button } from "@/components/ui/button"; import { toast } from "sonner"; const COLORS = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#ec4899"]; export default function AdminQuestionnaireAnalyse() { const [, params] = useRoute("/admin/questionnaires/:id/analyse"); const questionnaireId = parseInt(params?.id || "0"); const { data: questionnaire } = trpc.questionnaires.getById.useQuery({ id: questionnaireId }); const { data: stats } = trpc.questionnaires.getStats.useQuery({ id: questionnaireId }); const { data: questions } = trpc.questions.list.useQuery({ questionnaireId }); const { data: reponsesDetaillees } = trpc.questionnaires.getReponsesDetaillees.useQuery({ id: questionnaireId }); // Mutations d'export const exportExcelMutation = trpc.questionnaires.exportExcel.useMutation(); const exportPDFMutation = trpc.questionnaires.exportPDF.useMutation(); const handleExportExcel = async () => { try { const result = await exportExcelMutation.mutateAsync({ id: questionnaireId }); const blob = new Blob([Uint8Array.from(atob(result.data), c => c.charCodeAt(0))], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = result.filename; a.click(); window.URL.revokeObjectURL(url); toast.success('Export Excel réussi'); } catch (error) { toast.error('Erreur lors de l\'export Excel'); } }; const handleExportPDF = async () => { try { const result = await exportPDFMutation.mutateAsync({ id: questionnaireId }); const blob = new Blob([Uint8Array.from(atob(result.data), c => c.charCodeAt(0))], { type: 'application/pdf' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = result.filename; a.click(); window.URL.revokeObjectURL(url); toast.success('Export PDF réussi'); } catch (error) { toast.error('Erreur lors de l\'export PDF'); } }; if (!questionnaire) { return (

Chargement...

); } // Analyser les réponses par question const analyseParQuestion = questions?.map((question) => { const reponsesQuestion = reponsesDetaillees?.filter((r) => r.questionId === question.id) || []; if (question.typeQuestion === "echelle" || question.typeQuestion === "oui_non") { // Calculer la moyenne et la distribution const valeurs = reponsesQuestion .map((r) => r.reponseNumerique) .filter((v): v is number => v !== null); const moyenne = valeurs.length > 0 ? valeurs.reduce((a, b) => a + b, 0) / valeurs.length : 0; // Distribution des réponses const distribution: Record = {}; valeurs.forEach((v) => { distribution[v] = (distribution[v] || 0) + 1; }); const distributionData = Object.entries(distribution).map(([valeur, count]) => ({ valeur: parseInt(valeur), count, label: question.typeQuestion === "oui_non" ? (valeur === "1" ? "Oui" : "Non") : valeur, })); return { question, type: "numerique", moyenne: Math.round(moyenne * 10) / 10, totalReponses: valeurs.length, distribution: distributionData, }; } else if (question.typeQuestion === "choix_multiple") { // Distribution des choix const choix: Record = {}; reponsesQuestion.forEach((r) => { if (r.reponseTexte) { choix[r.reponseTexte] = (choix[r.reponseTexte] || 0) + 1; } }); const distributionData = Object.entries(choix).map(([label, count]) => ({ label, count, })); return { question, type: "choix", totalReponses: reponsesQuestion.length, distribution: distributionData, }; } else { // Texte libre - afficher les réponses const reponses = reponsesQuestion .map((r) => r.reponseTexte) .filter((t): t is string => !!t); return { question, type: "texte", totalReponses: reponses.length, reponses: reponses.slice(0, 10), // Limiter à 10 réponses }; } }) || []; return (

{questionnaire.nom}

Analyse des réponses

{/* Statistiques globales */}
Envois
{stats?.totalEnvois || 0}

Questionnaires envoyés

Réponses
{stats?.totalReponses || 0}

Questionnaires complétés

Taux de réponse
{stats?.tauxReponse || 0}%
Questions
{questions?.length || 0}

Questions au total

{/* Analyse par question */}
{analyseParQuestion.map((analyse, index) => ( Question {index + 1} : {analyse.question.texte} {analyse.totalReponses} réponse(s) {analyse.type === "numerique" && ` - Moyenne: ${analyse.moyenne}`} {analyse.type === "numerique" && analyse.distribution && (
)} {analyse.type === "choix" && analyse.distribution && (
`${label} (${(percent * 100).toFixed(0)}%)`} outerRadius={80} fill="#8884d8" dataKey="count" > {analyse.distribution.map((entry, index) => ( ))}
)} {analyse.type === "texte" && analyse.reponses && (
{analyse.reponses.map((reponse, i) => (

{reponse}

))} {analyse.totalReponses > 10 && (

... et {analyse.totalReponses - 10} autre(s) réponse(s)

)}
)}
))}
{analyseParQuestion.length === 0 && (

Aucune réponse pour le moment

)}
); }