diff --git a/src/features/ai-copilot/components/ai-explanation-modal.tsx b/src/features/ai-copilot/components/ai-explanation-modal.tsx
new file mode 100644
index 0000000..303659d
--- /dev/null
+++ b/src/features/ai-copilot/components/ai-explanation-modal.tsx
@@ -0,0 +1,156 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { X, Bot, Sparkles, TrendingUp, ShieldAlert, History } from "lucide-react";
+
+interface AiExplanationModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ productName: string;
+ productCode: string;
+ explanation: string;
+ recommandation?: "A" | "C" | "Z" | null;
+}
+
+export function AiExplanationModal({
+ isOpen,
+ onClose,
+ productName,
+ productCode,
+ explanation,
+ recommandation
+}: AiExplanationModalProps) {
+ const [isVisible, setIsVisible] = useState(false);
+
+ useEffect(() => {
+ if (isOpen) {
+ setIsVisible(true);
+ } else {
+ setIsVisible(false);
+ }
+ }, [isOpen]);
+
+ const handleClose = () => {
+ setIsVisible(false);
+ setTimeout(onClose, 250);
+ };
+
+ if (!isOpen && !isVisible) return null;
+
+ const getGammeColor = (g?: string | null) => {
+ switch (g) {
+ case "A": return "text-emerald-500 border-emerald-500/50 bg-emerald-500/10";
+ case "C": return "text-amber-500 border-amber-500/50 bg-amber-500/10";
+ case "Z": return "text-rose-500 border-rose-500/50 bg-rose-500/10";
+ default: return "text-slate-500 border-slate-500/50 bg-slate-500/10";
+ }
+ };
+
+ return (
+
+ {/* Backdrop */}
+
+
+ {/* Panel */}
+
+ {/* Header with Mary Icon */}
+
+
+
+
+
+
+
+ Analyse de Mary đź§™
+
+
+ {productName} ({productCode})
+
+
+
+
+
+
+ {/* Content */}
+
+
+ {/* Recommandation Badge */}
+
+
Verdict :
+
+ {recommandation === "A" && }
+ {recommandation === "C" && }
+ {recommandation === "Z" && }
+ {recommandation ? `GAMME ${recommandation}` : "AUCUN"}
+
+
+
+ {/* Explanation Text */}
+
+
+
+
+ "{explanation}"
+
+
+
+
+
+
+
+ Analyse générée en temps réel selon les indicateurs CA, Marge et Régularité.
+
+
+
+
+
+ {/* Footers / Action */}
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/features/ai-copilot/components/ai-insight-block.tsx b/src/features/ai-copilot/components/ai-insight-block.tsx
index 08a1f7f..6bb6340 100644
--- a/src/features/ai-copilot/components/ai-insight-block.tsx
+++ b/src/features/ai-copilot/components/ai-insight-block.tsx
@@ -1,7 +1,10 @@
"use client";
-import { Bot, Loader2, AlertCircle, Sparkles } from "lucide-react";
+import React, { useState } from "react";
+
+import { Bot, Loader2, AlertCircle, Sparkles, Maximize2 } from "lucide-react";
import { useAiCopilotStore } from "@/features/ai-copilot/store/use-ai-copilot-store";
+import { AiExplanationModal } from "./ai-explanation-modal";
import type { ProductRow } from "@/types/grid";
import { cn } from "@/lib/utils";
@@ -12,10 +15,11 @@ interface AiInsightBlockProps {
}
export function AiInsightBlock({ row }: AiInsightBlockProps) {
- const insight = useAiCopilotStore((s) => s.insights[row.codein]);
- const analyzeProduct = useAiCopilotStore((s) => s.analyzeProduct);
- const setLoading = useAiCopilotStore((s) => s.setLoading);
- const setDraftGamme = useGridStore((s) => s.setDraftGamme);
+ const insight = useAiCopilotStore((s: any) => s.insights[row.codein]);
+ const analyzeProduct = useAiCopilotStore((s: any) => s.analyzeProduct);
+ const setLoading = useAiCopilotStore((s: any) => s.setLoading);
+ const setDraftGamme = useGridStore((s: any) => s.setDraftGamme);
+ const [isModalOpen, setIsModalOpen] = useState(false);
const status = insight?.status ?? "idle";
@@ -97,18 +101,46 @@ export function AiInsightBlock({ row }: AiInsightBlockProps) {
}
return (
-
-
-
-
- {insight?.insight}
-
+ <>
+
+
+
{
+ e.stopPropagation();
+ handleAnalyze();
+ }}
+ />
+
+
{
+ e.stopPropagation();
+ setIsModalOpen(true);
+ }}
+ >
+
+ {insight?.insight}
+
+
+
+
+
+ {insight?.isDuplicate && (
+
+ ⚠️ Doublon probable
+
+ )}
- {insight?.isDuplicate && (
-
- ⚠️ Doublon probable
-
- )}
-
+
+
setIsModalOpen(false)}
+ productName={row.libelle1}
+ productCode={row.codein}
+ explanation={insight?.insight || ""}
+ recommandation={insight?.recommandation}
+ />
+ >
);
}
diff --git a/task.md b/task.md
index 1052884..8eefec7 100644
--- a/task.md
+++ b/task.md
@@ -18,6 +18,8 @@ Activation et initialisation de l'Agent Master BMAD.
- [x] Étape 10 : Ajustement du seuil de protection (Score < 20)
- [x] Étape 11 : Intégration de l'analyse critique systématique (même score > 50)
- [x] Étape 12 : Validation finale et correction TS
+- [x] Étape 13 : Implémentation du modal pour les explications IA détaillées
+- [/] Étape 14 : Polissage de l'UI (Sally/UX)
# Progress Log
@@ -38,3 +40,7 @@ Activation et initialisation de l'Agent Master BMAD.
- Arbitrage IA maintenu entre 20 et 50 basé sur CA / Marge / Quantité.
- Michael exige une analyse critique systématique même pour les scores > 50.
- Logique finale implémentée et validée (Score < 20 = Z).
+- Demande de Michael : Ajouter une icône + modal pour voir l'explication complète.
+- Recherche du composant de la grille en cours.
+- Nouveau composant `AiExplanationModal` créé.
+- Intégration dans `AiInsightBlock` terminée (icône + déclenchement).