diff --git a/src/hooks/useDashboard.ts b/src/hooks/useDashboard.ts index 3fac45f..00dccd1 100644 --- a/src/hooks/useDashboard.ts +++ b/src/hooks/useDashboard.ts @@ -3,18 +3,21 @@ import type { DashboardPeriod, DashboardSummary, CategoryBreakdownItem, - RecentTransaction, + CategoryOverTimeData, + BudgetVsActualRow, } from "../shared/types"; import { getDashboardSummary, getExpensesByCategory, - getRecentTransactions, } from "../services/dashboardService"; +import { getCategoryOverTime } from "../services/reportService"; +import { getBudgetVsActualData } from "../services/budgetService"; interface DashboardState { summary: DashboardSummary; categoryBreakdown: CategoryBreakdownItem[]; - recentTransactions: RecentTransaction[]; + categoryOverTime: CategoryOverTimeData; + budgetVsActual: BudgetVsActualRow[]; period: DashboardPeriod; customDateFrom: string; customDateTo: string; @@ -30,7 +33,8 @@ type DashboardAction = payload: { summary: DashboardSummary; categoryBreakdown: CategoryBreakdownItem[]; - recentTransactions: RecentTransaction[]; + categoryOverTime: CategoryOverTimeData; + budgetVsActual: BudgetVsActualRow[]; }; } | { type: "SET_PERIOD"; payload: DashboardPeriod } @@ -38,14 +42,15 @@ type DashboardAction = const now = new Date(); const todayStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`; -const monthStartStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-01`; +const yearStartStr = `${now.getFullYear()}-01-01`; const initialState: DashboardState = { summary: { totalCount: 0, totalAmount: 0, incomeTotal: 0, expenseTotal: 0 }, categoryBreakdown: [], - recentTransactions: [], - period: "month", - customDateFrom: monthStartStr, + categoryOverTime: { categories: [], data: [], colors: {}, categoryIds: {} }, + budgetVsActual: [], + period: "year", + customDateFrom: yearStartStr, customDateTo: todayStr, isLoading: false, error: null, @@ -62,7 +67,8 @@ function reducer(state: DashboardState, action: DashboardAction): DashboardState ...state, summary: action.payload.summary, categoryBreakdown: action.payload.categoryBreakdown, - recentTransactions: action.payload.recentTransactions, + categoryOverTime: action.payload.categoryOverTime, + budgetVsActual: action.payload.budgetVsActual, isLoading: false, }; case "SET_PERIOD": @@ -129,14 +135,17 @@ export function useDashboard() { try { const { dateFrom, dateTo } = computeDateRange(period, customFrom, customTo); - const [summary, categoryBreakdown, recentTransactions] = await Promise.all([ + const currentMonth = new Date().getMonth() + 1; + const currentYear = new Date().getFullYear(); + const [summary, categoryBreakdown, categoryOverTime, budgetVsActual] = await Promise.all([ getDashboardSummary(dateFrom, dateTo), getExpensesByCategory(dateFrom, dateTo), - getRecentTransactions(10), + getCategoryOverTime(dateFrom, dateTo), + getBudgetVsActualData(currentYear, currentMonth), ]); if (fetchId !== fetchIdRef.current) return; - dispatch({ type: "SET_DATA", payload: { summary, categoryBreakdown, recentTransactions } }); + dispatch({ type: "SET_DATA", payload: { summary, categoryBreakdown, categoryOverTime, budgetVsActual } }); } catch (e) { if (fetchId !== fetchIdRef.current) return; dispatch({ diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 069bf54..38fb1da 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -26,6 +26,8 @@ "noData": "No data available. Start by importing your bank statements.", "expensesByCategory": "Expenses by Category", "recentTransactions": "Recent Transactions", + "budgetVsActual": "Budget vs Actual", + "expensesOverTime": "Expenses Over Time", "period": { "month": "This month", "3months": "3 months", diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index d7e07d3..94b5446 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -26,6 +26,8 @@ "noData": "Aucune donnée disponible. Commencez par importer vos relevés bancaires.", "expensesByCategory": "Dépenses par catégorie", "recentTransactions": "Transactions récentes", + "budgetVsActual": "Budget vs Réel", + "expensesOverTime": "Dépenses dans le temps", "period": { "month": "Ce mois", "3months": "3 mois", diff --git a/src/pages/DashboardPage.tsx b/src/pages/DashboardPage.tsx index f8d32f4..fa80d92 100644 --- a/src/pages/DashboardPage.tsx +++ b/src/pages/DashboardPage.tsx @@ -5,7 +5,8 @@ import { useDashboard } from "../hooks/useDashboard"; import { PageHelp } from "../components/shared/PageHelp"; import PeriodSelector from "../components/dashboard/PeriodSelector"; import CategoryPieChart from "../components/dashboard/CategoryPieChart"; -import RecentTransactionsList from "../components/dashboard/RecentTransactionsList"; +import CategoryOverTimeChart from "../components/reports/CategoryOverTimeChart"; +import BudgetVsActualTable from "../components/reports/BudgetVsActualTable"; import TransactionDetailModal from "../components/shared/TransactionDetailModal"; import type { CategoryBreakdownItem, DashboardPeriod } from "../shared/types"; @@ -41,7 +42,7 @@ function computeDateRange( export default function DashboardPage() { const { t } = useTranslation(); const { state, setPeriod, setCustomDates } = useDashboard(); - const { summary, categoryBreakdown, recentTransactions, period, isLoading } = state; + const { summary, categoryBreakdown, categoryOverTime, budgetVsActual, period, isLoading } = state; const [hiddenCategories, setHiddenCategories] = useState>(new Set()); const [detailModal, setDetailModal] = useState(null); @@ -108,7 +109,7 @@ export default function DashboardPage() { /> -
+
{cards.map((card) => (
-
+
- +
+

{t("dashboard.budgetVsActual")}

+ +
+
+ +
+

{t("dashboard.expensesOverTime")}

+
{detailModal && (