diff --git a/frontend/src/components/analytics/BalanceChart.tsx b/frontend/src/components/analytics/BalanceChart.tsx index 9eba397..897a194 100644 --- a/frontend/src/components/analytics/BalanceChart.tsx +++ b/frontend/src/components/analytics/BalanceChart.tsx @@ -59,11 +59,11 @@ export default function BalanceChart({ data, accounts, className }: BalanceChart const chartData = data .filter((balance) => balance.balance_type === "closingBooked") .map((balance) => ({ - date: new Date(balance.reference_date).toLocaleDateString(), + date: new Date(balance.reference_date).toLocaleDateString('en-GB'), // DD/MM/YYYY format balance: balance.balance_amount, account_id: balance.account_id, })) - .sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); + .sort((a, b) => new Date(a.date.split('/').reverse().join('/')).getTime() - new Date(b.date.split('/').reverse().join('/')).getTime()); // Group by account and aggregate const accountBalances: { [key: string]: ChartDataPoint[] } = {}; @@ -86,7 +86,7 @@ export default function BalanceChart({ data, accounts, className }: BalanceChart }); const finalData = Object.values(aggregatedData).sort( - (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime() + (a, b) => new Date(a.date.split('/').reverse().join('/')).getTime() - new Date(b.date.split('/').reverse().join('/')).getTime() ); const colors = ["#3B82F6", "#10B981", "#F59E0B", "#EF4444", "#8B5CF6"]; @@ -117,8 +117,10 @@ export default function BalanceChart({ data, accounts, className }: BalanceChart dataKey="date" tick={{ fontSize: 12 }} tickFormatter={(value) => { - const date = new Date(value); - return date.toLocaleDateString(undefined, { + // Convert DD/MM/YYYY back to a proper date for formatting + const [day, month, year] = value.split('/'); + const date = new Date(year, month - 1, day); + return date.toLocaleDateString('en-GB', { month: "short", day: "numeric", }); diff --git a/frontend/src/components/analytics/MonthlyTrends.tsx b/frontend/src/components/analytics/MonthlyTrends.tsx index 800f0ec..7e88454 100644 --- a/frontend/src/components/analytics/MonthlyTrends.tsx +++ b/frontend/src/components/analytics/MonthlyTrends.tsx @@ -12,6 +12,7 @@ import apiClient from "../../lib/api"; interface MonthlyTrendsProps { className?: string; + days?: number; } interface MonthlyData { @@ -31,13 +32,12 @@ interface TooltipProps { label?: string; } -export default function MonthlyTrends({ className }: MonthlyTrendsProps) { - // Get transactions for the last 12 months using analytics endpoint +export default function MonthlyTrends({ className, days = 365 }: MonthlyTrendsProps) { + // Get transactions for the specified period using analytics endpoint const { data: transactions, isLoading } = useQuery({ - queryKey: ["transactions", "monthly-trends"], + queryKey: ["transactions", "monthly-trends", days], queryFn: async () => { - // Get last 365 days of transactions for monthly trends - return await apiClient.getTransactionsForAnalytics(365); + return await apiClient.getTransactionsForAnalytics(days); }, }); diff --git a/frontend/src/components/analytics/TimePeriodFilter.tsx b/frontend/src/components/analytics/TimePeriodFilter.tsx new file mode 100644 index 0000000..e9ecdec --- /dev/null +++ b/frontend/src/components/analytics/TimePeriodFilter.tsx @@ -0,0 +1,39 @@ +import { Calendar } from "lucide-react"; +import type { TimePeriod } from "../../lib/timePeriods"; +import { TIME_PERIODS } from "../../lib/timePeriods"; + +interface TimePeriodFilterProps { + selectedPeriod: TimePeriod; + onPeriodChange: (period: TimePeriod) => void; + className?: string; +} + +export default function TimePeriodFilter({ + selectedPeriod, + onPeriodChange, + className = "", +}: TimePeriodFilterProps) { + return ( +
+
+ + Time Period: +
+
+ {TIME_PERIODS.map((period) => ( + + ))} +
+
+ ); +} \ No newline at end of file diff --git a/frontend/src/lib/timePeriods.ts b/frontend/src/lib/timePeriods.ts new file mode 100644 index 0000000..d694a4e --- /dev/null +++ b/frontend/src/lib/timePeriods.ts @@ -0,0 +1,19 @@ +export type TimePeriod = { + label: string; + days: number; + value: string; +}; + +function getDaysFromYearStart(): number { + const now = new Date(); + const yearStart = new Date(now.getFullYear(), 0, 1); + const diffTime = now.getTime() - yearStart.getTime(); + return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); +} + +export const TIME_PERIODS: TimePeriod[] = [ + { label: "Last 30 days", days: 30, value: "30d" }, + { label: "Last 6 months", days: 180, value: "6m" }, + { label: "Year to Date", days: getDaysFromYearStart(), value: "ytd" }, + { label: "Last 365 days", days: 365, value: "365d" }, +]; \ No newline at end of file diff --git a/frontend/src/routes/analytics.tsx b/frontend/src/routes/analytics.tsx index 83366d2..1884242 100644 --- a/frontend/src/routes/analytics.tsx +++ b/frontend/src/routes/analytics.tsx @@ -1,5 +1,6 @@ import { createFileRoute } from "@tanstack/react-router"; import { useQuery } from "@tanstack/react-query"; +import { useState } from "react"; import { CreditCard, TrendingUp, @@ -13,12 +14,20 @@ import StatCard from "../components/analytics/StatCard"; import BalanceChart from "../components/analytics/BalanceChart"; import TransactionDistribution from "../components/analytics/TransactionDistribution"; import MonthlyTrends from "../components/analytics/MonthlyTrends"; +import TimePeriodFilter from "../components/analytics/TimePeriodFilter"; +import type { TimePeriod } from "../lib/timePeriods"; +import { TIME_PERIODS } from "../lib/timePeriods"; function AnalyticsDashboard() { + // Default to Last 365 days + const [selectedPeriod, setSelectedPeriod] = useState( + TIME_PERIODS.find((p) => p.value === "365d") || TIME_PERIODS[3] + ); + // Fetch analytics data const { data: stats, isLoading: statsLoading } = useQuery({ - queryKey: ["transaction-stats"], - queryFn: () => apiClient.getTransactionStats(365), // Last year + queryKey: ["transaction-stats", selectedPeriod.days], + queryFn: () => apiClient.getTransactionStats(selectedPeriod.days), }); const { data: accounts, isLoading: accountsLoading } = useQuery({ @@ -27,8 +36,8 @@ function AnalyticsDashboard() { }); const { data: balances, isLoading: balancesLoading } = useQuery({ - queryKey: ["historical-balances"], - queryFn: () => apiClient.getHistoricalBalances(365), // Get 1 year of history + queryKey: ["historical-balances", selectedPeriod.days], + queryFn: () => apiClient.getHistoricalBalances(selectedPeriod.days), }); const isLoading = statsLoading || accountsLoading || balancesLoading; @@ -66,6 +75,13 @@ function AnalyticsDashboard() {

+ {/* Time Period Filter */} + + {/* Stats Cards */}
- +
{/* Summary Section */}