mirror of
https://github.com/R0m1k3/CollectFlow.git
synced 2026-10-23 06:58:10 +02:00
feat: Add AI Copilot Zustand store for managing and persisting product insights.
This commit is contained in:
1 parent
86df5d6f29
commit
99954fb001
2 files changed
+26
-10
No files matched your search
@@ -13,6 +13,7 @@ interface AiInsight {
|
|||||||
interface AiCopilotState {
|
interface AiCopilotState {
|
||||||
insights: Record<string, AiInsight>;
|
insights: Record<string, AiInsight>;
|
||||||
setInsight: (codein: string, insight: string, isDuplicate?: boolean) => void;
|
setInsight: (codein: string, insight: string, isDuplicate?: boolean) => void;
|
||||||
|
batchSetInsights: (entries: { codein: string; insight: string }[]) => void;
|
||||||
setLoading: (codein: string) => void;
|
setLoading: (codein: string) => void;
|
||||||
batchSetLoading: (codeins: string[]) => void;
|
batchSetLoading: (codeins: string[]) => void;
|
||||||
setError: (codein: string, error: string) => void;
|
setError: (codein: string, error: string) => void;
|
||||||
@@ -76,6 +77,16 @@ export const useAiCopilotStore = create<AiCopilotState>()(
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
batchSetInsights: (entries) => {
|
||||||
|
set((s) => {
|
||||||
|
const nextInsights = { ...s.insights };
|
||||||
|
entries.forEach(({ codein, insight }) => {
|
||||||
|
nextInsights[codein] = { codein, insight, status: "done" };
|
||||||
|
});
|
||||||
|
return { insights: nextInsights };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setLoading: (codein) => {
|
setLoading: (codein) => {
|
||||||
set((s) => ({
|
set((s) => ({
|
||||||
insights: {
|
insights: {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export function BulkAiAnalyzer() {
|
|||||||
|
|
||||||
const batchSetDraftGamme = useGridStore((s) => s.batchSetDraftGamme);
|
const batchSetDraftGamme = useGridStore((s) => s.batchSetDraftGamme);
|
||||||
const setDraftGamme = useGridStore((s) => s.setDraftGamme);
|
const setDraftGamme = useGridStore((s) => s.setDraftGamme);
|
||||||
const { setInsight, batchSetLoading, setError } = useAiCopilotStore();
|
const { setInsight, batchSetInsights, batchSetLoading, setError } = useAiCopilotStore();
|
||||||
|
|
||||||
const prevSupplierRef = useRef(supplierCode);
|
const prevSupplierRef = useRef(supplierCode);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -61,9 +61,10 @@ export function BulkAiAnalyzer() {
|
|||||||
const zChanges: Record<string, GammeCode> = {};
|
const zChanges: Record<string, GammeCode> = {};
|
||||||
zeroSalesRows.forEach(r => { zChanges[r.codein] = "Z"; });
|
zeroSalesRows.forEach(r => { zChanges[r.codein] = "Z"; });
|
||||||
batchSetDraftGamme(zChanges);
|
batchSetDraftGamme(zChanges);
|
||||||
zeroSalesRows.forEach(r => {
|
batchSetInsights(zeroSalesRows.map(r => ({
|
||||||
setInsight(r.codein, "Aucune vente sur 12 mois — produit classé Z automatiquement.");
|
codein: r.codein,
|
||||||
});
|
insight: "Aucune vente sur 12 mois — produit classé Z automatiquement.",
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construire les payloads uniquement pour les produits avec ventes
|
// Construire les payloads uniquement pour les produits avec ventes
|
||||||
@@ -129,9 +130,10 @@ export function BulkAiAnalyzer() {
|
|||||||
const zChanges: Record<string, GammeCode> = {};
|
const zChanges: Record<string, GammeCode> = {};
|
||||||
deadStockRows.forEach(r => { zChanges[r.codein] = "Z"; });
|
deadStockRows.forEach(r => { zChanges[r.codein] = "Z"; });
|
||||||
batchSetDraftGamme(zChanges);
|
batchSetDraftGamme(zChanges);
|
||||||
deadStockRows.forEach(r => {
|
batchSetInsights(deadStockRows.map(r => ({
|
||||||
setInsight(r.codein, `CA < 100€ (${(r.totalCa ?? 0).toFixed(0)}€) et quantité < 30 (${r.totalQuantite} uté) — stock mort absolu, classé Z automatiquement.`);
|
codein: r.codein,
|
||||||
});
|
insight: `CA < 100€ (${(r.totalCa ?? 0).toFixed(0)}€) et quantité < 30 (${r.totalQuantite} uté) — stock mort absolu, classé Z automatiquement.`,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
const deadStockCodes = new Set(deadStockRows.map(r => r.codein));
|
const deadStockCodes = new Set(deadStockRows.map(r => r.codein));
|
||||||
|
|
||||||
@@ -145,12 +147,15 @@ export function BulkAiAnalyzer() {
|
|||||||
const aChanges: Record<string, GammeCode> = {};
|
const aChanges: Record<string, GammeCode> = {};
|
||||||
top20Rows.forEach(r => { aChanges[r.codein] = "A"; });
|
top20Rows.forEach(r => { aChanges[r.codein] = "A"; });
|
||||||
batchSetDraftGamme(aChanges);
|
batchSetDraftGamme(aChanges);
|
||||||
top20Rows.forEach(r => {
|
batchSetInsights(top20Rows.map(r => {
|
||||||
const rkCa = r.rankingCa != null ? `${r.rankingCa}e CA` : "";
|
const rkCa = r.rankingCa != null ? `${r.rankingCa}e CA` : "";
|
||||||
const rkQte = r.rankingQte != null ? `${r.rankingQte}e Qté` : "";
|
const rkQte = r.rankingQte != null ? `${r.rankingQte}e Qté` : "";
|
||||||
const total = r.totalRankedProducts ? ` / ${r.totalRankedProducts.toLocaleString("fr-FR")} produits` : "";
|
const total = r.totalRankedProducts ? ` / ${r.totalRankedProducts.toLocaleString("fr-FR")} produits` : "";
|
||||||
setInsight(r.codein, `Top 20 réseau (${[rkCa, rkQte].filter(Boolean).join(", ")}${total}) — classé A automatiquement.`);
|
return {
|
||||||
});
|
codein: r.codein,
|
||||||
|
insight: `Top 20 réseau (${[rkCa, rkQte].filter(Boolean).join(", ")}${total}) — classé A automatiquement.`,
|
||||||
|
};
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
const top20Codes = new Set(top20Rows.map(r => r.codein));
|
const top20Codes = new Set(top20Rows.map(r => r.codein));
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user