Fix MonthlyTrends dynamic title, remove Period Summary, convert BalanceChart to stacked area chart

Co-authored-by: elisiariocouto <818914+elisiariocouto@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-09-13 23:40:25 +00:00
committed by Elisiário Couto
parent c8f0a103c6
commit d51aa9429e
3 changed files with 32 additions and 49 deletions

View File

@@ -1,6 +1,6 @@
import {
LineChart,
Line,
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
@@ -111,7 +111,7 @@ export default function BalanceChart({ data, accounts, className }: BalanceChart
</h3>
<div className="h-80">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={finalData}>
<AreaChart data={finalData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="date"
@@ -131,25 +131,25 @@ export default function BalanceChart({ data, accounts, className }: BalanceChart
tickFormatter={(value) => `${value.toLocaleString()}`}
/>
<Tooltip
formatter={(value: number) => [
formatter={(value: number, name: string) => [
`${value.toLocaleString()}`,
"Balance",
getAccountDisplayName(name),
]}
labelFormatter={(label) => `Date: ${label}`}
/>
<Legend />
{Object.keys(accountBalances).map((accountId, index) => (
<Line
<Area
key={accountId}
type="monotone"
dataKey={accountId}
stackId="1"
fill={colors[index % colors.length]}
stroke={colors[index % colors.length]}
strokeWidth={2}
dot={{ r: 4 }}
name={getAccountDisplayName(accountId)}
/>
))}
</LineChart>
</AreaChart>
</ResponsiveContainer>
</div>
</div>

View File

@@ -53,7 +53,7 @@ export default function MonthlyTrends({ className, days = 365 }: MonthlyTrendsPr
if (!monthlyMap[monthKey]) {
monthlyMap[monthKey] = {
month: date.toLocaleDateString(undefined, {
month: date.toLocaleDateString('en-GB', {
year: 'numeric',
month: 'short'
}),
@@ -77,10 +77,20 @@ export default function MonthlyTrends({ className, days = 365 }: MonthlyTrendsPr
...Object.entries(monthlyMap)
.sort(([a], [b]) => a.localeCompare(b))
.map(([, data]) => data)
.slice(-12) // Last 12 months
);
}
// Calculate number of months to display based on days filter
const getMonthsToDisplay = (days: number): number => {
if (days <= 30) return 1;
if (days <= 180) return 6;
if (days <= 365) return 12;
return Math.ceil(days / 30);
};
const monthsToDisplay = getMonthsToDisplay(days);
const displayData = monthlyData.slice(-monthsToDisplay);
if (isLoading) {
return (
<div className={className}>
@@ -94,7 +104,7 @@ export default function MonthlyTrends({ className, days = 365 }: MonthlyTrendsPr
);
}
if (monthlyData.length === 0) {
if (displayData.length === 0) {
return (
<div className={className}>
<h3 className="text-lg font-medium text-gray-900 mb-4">
@@ -123,14 +133,22 @@ export default function MonthlyTrends({ className, days = 365 }: MonthlyTrendsPr
return null;
};
// Generate dynamic title based on time period
const getTitle = (days: number): string => {
if (days <= 30) return "Monthly Spending Trends (Last 30 Days)";
if (days <= 180) return "Monthly Spending Trends (Last 6 Months)";
if (days <= 365) return "Monthly Spending Trends (Last 12 Months)";
return `Monthly Spending Trends (Last ${Math.ceil(days / 30)} Months)`;
};
return (
<div className={className}>
<h3 className="text-lg font-medium text-gray-900 mb-4">
Monthly Spending Trends (Last 12 Months)
{getTitle(days)}
</h3>
<div className="h-80">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={monthlyData} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<BarChart data={displayData} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="month"

View File

@@ -144,41 +144,6 @@ function AnalyticsDashboard() {
<div className="bg-white rounded-lg shadow p-6 border border-gray-200">
<MonthlyTrends days={selectedPeriod.days} />
</div>
{/* Summary Section */}
{stats && (
<div className="bg-blue-50 rounded-lg p-6 border border-blue-200">
<h3 className="text-lg font-medium text-blue-900 mb-4">
Period Summary ({stats.period_days} days)
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 text-sm">
<div>
<p className="text-blue-700 font-medium">Booked Transactions</p>
<p className="text-blue-900">{stats.booked_transactions}</p>
</div>
<div>
<p className="text-blue-700 font-medium">Pending Transactions</p>
<p className="text-blue-900">{stats.pending_transactions}</p>
</div>
<div>
<p className="text-blue-700 font-medium">Transaction Ratio</p>
<p className="text-blue-900">
{stats.total_transactions > 0
? `${Math.round(
(stats.booked_transactions / stats.total_transactions) * 100
)}% booked`
: "No transactions"}
</p>
</div>
<div>
<p className="text-blue-700 font-medium">Spend Rate</p>
<p className="text-blue-900">
{((stats.total_expenses || 0) / stats.period_days).toFixed(2)}/day
</p>
</div>
</div>
</div>
)}
</div>
);
}