"use client"; import { useMemo } from "react"; import { useTransactions } from "@/lib/hooks"; import { useBankingMetadata } from "@/lib/hooks"; import type { TransactionsPaginatedParams } from "@/services/banking.service"; import type { Category } from "@/lib/types"; interface MonthlyChartData { month: string; revenus: number; depenses: number; solde: number; } interface CategoryChartData { name: string; value: number; color: string; icon: string; categoryId: string | null; } interface UseTransactionsChartDataParams { selectedAccounts: string[]; selectedCategories: string[]; period: "1month" | "3months" | "6months" | "12months" | "custom" | "all"; customStartDate?: Date; customEndDate?: Date; showReconciled: string; searchQuery: string; } export function useTransactionsChartData({ selectedAccounts, selectedCategories, period, customStartDate, customEndDate, showReconciled, searchQuery, }: UseTransactionsChartDataParams) { const { data: metadata } = useBankingMetadata(); // Calculate start date based on period const startDate = useMemo(() => { const now = new Date(); switch (period) { case "1month": return new Date(now.getFullYear(), now.getMonth() - 1, 1); case "3months": return new Date(now.getFullYear(), now.getMonth() - 3, 1); case "6months": return new Date(now.getFullYear(), now.getMonth() - 6, 1); case "12months": return new Date(now.getFullYear(), now.getMonth() - 12, 1); case "custom": return customStartDate || new Date(0); default: return new Date(0); } }, [period, customStartDate]); // Calculate end date (only for custom period) const endDate = useMemo(() => { if (period === "custom" && customEndDate) { return customEndDate; } return undefined; }, [period, customEndDate]); // Build params for fetching all transactions (no pagination) const chartParams = useMemo(() => { const params: TransactionsPaginatedParams = { limit: 10000, // Large limit to get all transactions offset: 0, sortField: "date", sortOrder: "asc", }; if (startDate && period !== "all") { params.startDate = startDate.toISOString().split("T")[0]; } if (endDate) { params.endDate = endDate.toISOString().split("T")[0]; } if (!selectedAccounts.includes("all")) { params.accountIds = selectedAccounts; } if (!selectedCategories.includes("all")) { if (selectedCategories.includes("uncategorized")) { params.includeUncategorized = true; } else { params.categoryIds = selectedCategories; } } if (searchQuery) { params.search = searchQuery; } if (showReconciled !== "all") { params.isReconciled = showReconciled === "reconciled"; } return params; }, [ startDate, endDate, selectedAccounts, selectedCategories, searchQuery, showReconciled, period, ]); // Fetch all filtered transactions for chart const { data: transactionsData, isLoading } = useTransactions( chartParams, !!metadata ); // Calculate monthly chart data const monthlyData = useMemo(() => { if (!transactionsData || !metadata) { return []; } const transactions = transactionsData.transactions; // Monthly breakdown const monthlyMap = new Map(); transactions.forEach((t) => { const monthKey = t.date.substring(0, 7); const current = monthlyMap.get(monthKey) || { income: 0, expenses: 0 }; if (t.amount >= 0) { current.income += t.amount; } else { current.expenses += Math.abs(t.amount); } monthlyMap.set(monthKey, current); }); // Format months with year: use short format for better readability const sortedMonths = Array.from(monthlyMap.entries()).sort((a, b) => a[0].localeCompare(b[0]) ); const monthlyChartData: MonthlyChartData[] = sortedMonths.map( ([monthKey, values]) => { const date = new Date(monthKey + "-01"); // Format: "janv. 24" instead of "janv. 2024" for compactness const monthLabel = date.toLocaleDateString("fr-FR", { month: "short", }); const yearShort = date.getFullYear().toString().slice(-2); return { month: `${monthLabel} ${yearShort}`, revenus: values.income, depenses: values.expenses, solde: values.income - values.expenses, }; } ); return monthlyChartData; }, [transactionsData]); // Calculate category chart data (expenses only) const categoryData = useMemo(() => { if (!transactionsData || !metadata) { return []; } const transactions = transactionsData.transactions; const categoryTotals = new Map(); transactions .filter((t) => t.amount < 0) .forEach((t) => { const catId = t.categoryId || "uncategorized"; const current = categoryTotals.get(catId) || 0; categoryTotals.set(catId, current + Math.abs(t.amount)); }); const categoryChartData: CategoryChartData[] = Array.from( categoryTotals.entries() ) .map(([categoryId, total]) => { const category = metadata.categories.find((c: Category) => c.id === categoryId); return { name: category?.name || "Non catégorisé", value: Math.round(total), color: category?.color || "#94a3b8", icon: category?.icon || "HelpCircle", categoryId: categoryId === "uncategorized" ? null : categoryId, }; }) .sort((a, b) => b.value - a.value); return categoryChartData; }, [transactionsData, metadata]); // Calculate total amount and count from all filtered transactions const totalAmount = useMemo(() => { if (!transactionsData) return 0; return transactionsData.transactions.reduce( (sum, t) => sum + t.amount, 0 ); }, [transactionsData]); const totalCount = useMemo(() => { return transactionsData?.total || 0; }, [transactionsData?.total]); return { monthlyData, categoryData, isLoading, totalAmount, totalCount, }; }