diff --git a/app/categories/page.tsx b/app/categories/page.tsx index e1c46ff..a5aa731 100644 --- a/app/categories/page.tsx +++ b/app/categories/page.tsx @@ -10,14 +10,28 @@ import { } from "@/components/categories"; import { useBankingData } from "@/lib/hooks"; import { Button } from "@/components/ui/button"; -import { Plus } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, +} from "@/components/ui/dialog"; +import { Badge } from "@/components/ui/badge"; +import { CategoryIcon } from "@/components/ui/category-icon"; +import { Plus, ArrowRight, CheckCircle2, RefreshCw } from "lucide-react"; import { autoCategorize, addCategory, updateCategory, deleteCategory, } from "@/lib/store-db"; -import type { Category } from "@/lib/types"; +import type { Category, Transaction } from "@/lib/types"; + +interface RecategorizationResult { + transaction: Transaction; + category: Category; +} export default function CategoriesPage() { const { data, isLoading, refresh } = useBankingData(); @@ -34,6 +48,9 @@ export default function CategoriesPage() { parentId: null as string | null, }); const [searchQuery, setSearchQuery] = useState(""); + const [recatResults, setRecatResults] = useState([]); + const [isRecatDialogOpen, setIsRecatDialogOpen] = useState(false); + const [isRecategorizing, setIsRecategorizing] = useState(false); // Organiser les catégories par parent const { parentCategories, childrenByParent, orphanCategories } = @@ -195,12 +212,8 @@ export default function CategoriesPage() { }; const reApplyAutoCategories = async () => { - if ( - !confirm( - "Recatégoriser automatiquement les transactions non catégorisées ?" - ) - ) - return; + setIsRecategorizing(true); + const results: RecategorizationResult[] = []; try { const { updateTransaction } = await import("@/lib/store-db"); @@ -212,13 +225,22 @@ export default function CategoriesPage() { data.categories ); if (categoryId) { - await updateTransaction({ ...transaction, categoryId }); + const category = data.categories.find((c) => c.id === categoryId); + if (category) { + results.push({ transaction, category }); + await updateTransaction({ ...transaction, categoryId }); + } } } + + setRecatResults(results); + setIsRecatDialogOpen(true); refresh(); } catch (error) { console.error("Error re-categorizing:", error); alert("Erreur lors de la recatégorisation"); + } finally { + setIsRecategorizing(false); } }; @@ -249,7 +271,14 @@ export default function CategoriesPage() { actions={ <> {uncategorizedCount > 0 && ( - )} @@ -335,6 +364,72 @@ export default function CategoriesPage() { parentCategories={parentCategories} onSave={handleSave} /> + + {/* Dialog des résultats de recatégorisation */} + + + + + + Recatégorisation terminée + + + {recatResults.length === 0 + ? "Aucune transaction n'a pu être catégorisée automatiquement." + : `${recatResults.length} transaction${recatResults.length > 1 ? "s" : ""} catégorisée${recatResults.length > 1 ? "s" : ""}`} + + + + {recatResults.length > 0 && ( +
+
+ {recatResults.map((result, index) => ( +
+
+

+ {result.transaction.description} +

+

+ {new Date(result.transaction.date).toLocaleDateString("fr-FR")} + {" • "} + {new Intl.NumberFormat("fr-FR", { + style: "currency", + currency: "EUR", + }).format(result.transaction.amount)} +

+
+ + + + {result.category.name} + +
+ ))} +
+
+ )} + +
+ +
+
+
); }