diff --git a/src/features/ai-copilot/components/ai-insight-block.tsx b/src/features/ai-copilot/components/ai-insight-block.tsx index a875bad..08a1f7f 100644 --- a/src/features/ai-copilot/components/ai-insight-block.tsx +++ b/src/features/ai-copilot/components/ai-insight-block.tsx @@ -12,15 +12,18 @@ interface AiInsightBlockProps { } export function AiInsightBlock({ row }: AiInsightBlockProps) { - const { insights, analyzeProduct } = useAiCopilotStore(); - const setDraftGamme = useGridStore(state => state.setDraftGamme); - const insight = insights[row.codein]; + 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 status = insight?.status ?? "idle"; const handleAnalyze = () => { if (status === "loading") return; - // Vider la recommandation actuelle avant de relancer l'IA + // Reset Visuel Immédiat + setLoading(row.codein); setDraftGamme(row.codein, "Aucune"); const regScore = Object.values(row.sales12m || {}).filter(v => v > 0).length; diff --git a/src/features/ai-copilot/store/use-ai-copilot-store.ts b/src/features/ai-copilot/store/use-ai-copilot-store.ts index f230e2a..7d23a0c 100644 --- a/src/features/ai-copilot/store/use-ai-copilot-store.ts +++ b/src/features/ai-copilot/store/use-ai-copilot-store.ts @@ -14,6 +14,7 @@ interface AiCopilotState { insights: Record; setInsight: (codein: string, insight: string, isDuplicate?: boolean) => void; setLoading: (codein: string) => void; + batchSetLoading: (codeins: string[]) => void; setError: (codein: string, error: string) => void; analyzeProduct: (payload: { codein: string; @@ -56,6 +57,16 @@ export const useAiCopilotStore = create()( })); }, + batchSetLoading: (codeins) => { + set((s) => { + const nextInsights = { ...s.insights }; + codeins.forEach(codein => { + nextInsights[codein] = { codein, insight: "", status: "loading" }; + }); + return { insights: nextInsights }; + }); + }, + setError: (codein, error) => { set((s) => ({ insights: { diff --git a/src/features/grid/components/bulk-ai-analyzer.tsx b/src/features/grid/components/bulk-ai-analyzer.tsx index 2f06904..7f90c5e 100644 --- a/src/features/grid/components/bulk-ai-analyzer.tsx +++ b/src/features/grid/components/bulk-ai-analyzer.tsx @@ -12,8 +12,9 @@ export function BulkAiAnalyzer() { const [progress, setProgress] = useState({ current: 0, total: 0, message: "", errors: 0 }); const isCancelledRef = useRef(false); + const batchSetDraftGamme = useGridStore((s) => s.batchSetDraftGamme); const setDraftGamme = useGridStore((s) => s.setDraftGamme); - const { setInsight, setLoading, setError } = useAiCopilotStore(); + const { setInsight, batchSetLoading, setError } = useAiCopilotStore(); const handleStop = () => { isCancelledRef.current = true; @@ -111,6 +112,14 @@ export function BulkAiAnalyzer() { const totalItems = productPayloads.length; setProgress({ current: 0, total: totalItems, message: "Initialisation...", errors: 0 }); + // Reset global ATOMIQUE et IMMÉDIAT + const codeins = productPayloads.map(p => p.codein); + batchSetLoading(codeins); + + const gammeChanges: Record = {}; + codeins.forEach(c => gammeChanges[c] = "Aucune"); + batchSetDraftGamme(gammeChanges); + const CONCURRENCY = 3; const remaining = [...productPayloads]; @@ -120,9 +129,6 @@ export function BulkAiAnalyzer() { const payload = remaining.shift(); if (!payload) break; - setLoading(payload.codein); - setDraftGamme(payload.codein, "Aucune"); - try { let res: Response | null = null; for (let i = 0; i < 3; i++) { diff --git a/src/features/grid/store/use-grid-store.ts b/src/features/grid/store/use-grid-store.ts index 4b7ef49..b06b47d 100644 --- a/src/features/grid/store/use-grid-store.ts +++ b/src/features/grid/store/use-grid-store.ts @@ -25,6 +25,7 @@ interface GridState { setDisplayDensity: (density: "compact" | "normal" | "comfortable") => void; setActiveGridQuery: (query: string) => void; restoreSnapshot: (changes: Record) => void; + batchSetDraftGamme: (changes: Record) => void; } function computeSummary(rows: ProductRow[], drafts: Record): GridSummary { @@ -105,6 +106,24 @@ export const useGridStore = create()( restoreSnapshot: (changes) => { set({ draftChanges: changes, summary: computeSummary(get().rows, changes) }); }, + + batchSetDraftGamme: (newChanges) => { + const { rows, draftChanges: oldDrafts } = get(); + const updatedDrafts = { ...oldDrafts }; + + Object.entries(newChanges).forEach(([codein, gamme]) => { + const originalRow = rows.find(r => r.codein === codein); + const originalGamme = originalRow?.codeGamme; + + if (gamme === originalGamme) { + delete updatedDrafts[codein]; + } else { + updatedDrafts[codein] = gamme; + } + }); + + set({ draftChanges: updatedDrafts, summary: computeSummary(rows, updatedDrafts) }); + }, }), { name: "collectflow-grid-storage",