rolling and calender toggle

This commit is contained in:
2026-04-06 18:07:38 +05:30
parent 8a866566ba
commit 787324260c
3 changed files with 97 additions and 50 deletions

View File

@@ -36,8 +36,8 @@ export default function Dashboard() {
income: null
});
const [mode, setMode] =
React.useState<"expense" | "income">("expense");
const [mode, setMode] = React.useState<"expense" | "income">("expense");
const [period, setPeriod] = React.useState<"rolling" | "calendar">("rolling");
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState<string | null>(null);
@@ -56,8 +56,8 @@ export default function Dashboard() {
] = await Promise.all([
fetchLatestTransactions("expense"),
fetchLatestTransactions("income"),
fetchAggregatedExpenses(),
fetchAggregatedIncome()
fetchAggregatedExpenses(period),
fetchAggregatedIncome(period)
]);
setLatest({
@@ -79,7 +79,7 @@ export default function Dashboard() {
}
loadData();
}, []);
}, [period]);
const currentData = aggregated[mode];
const currentLatest = latest[mode];
@@ -132,6 +132,8 @@ export default function Dashboard() {
summary="Interactive chronological tracking"
tabs={["Daily", "Weekly", "Monthly"]}
data={currentData?.chartData || {}}
period={period}
onPeriodChange={setPeriod}
/>
</Grid>
</Grid>

View File

@@ -13,6 +13,8 @@ export interface HistoryChartProps {
summary?: string;
tabs: string[];
data: Record<string, ChartDataPoint[]>;
period: "rolling" | "calendar",
onPeriodChange: (mode: "rolling" | "calendar") => void;
}
export default function HistoryChart({
@@ -20,6 +22,8 @@ export default function HistoryChart({
summary,
tabs,
data,
period,
onPeriodChange,
}: HistoryChartProps) {
const [activeTab, setActiveTab] = React.useState<string>(tabs[0] || "");
@@ -102,6 +106,22 @@ export default function HistoryChart({
))}
</ToggleButtonGroup>
<ToggleButtonGroup
value={period}
exclusive
onChange={(_, v) => v && onPeriodChange(v)}
size="small"
sx={{ mb: 2 }}
>
<ToggleButton value="rolling">Rolling</ToggleButton>
<ToggleButton
value="calendar"
disabled={activeTab.toLowerCase() === "daily"}
>
Calendar
</ToggleButton>
</ToggleButtonGroup>
{/* Chart Area */}
{currentData.length > 0 ? (
<Box sx={{ display: "flex", alignItems: "flex-end", height: 200, mt: 4, position: 'relative' }}>

View File

@@ -80,7 +80,8 @@ export interface AggregatedDashboardData {
// ---------------- AGGREGATION ----------------
// ---------------- AGGREGATION ----------------
export async function fetchAggregatedData(
type: "expense" | "income"
type: "expense" | "income",
mode: "rolling" | "calendar" = "rolling"
): Promise<AggregatedDashboardData> {
const res = await api.get("/expenses", { params: { limit: 0 } });
const all: any[] = res.data?.items || res.data || [];
@@ -105,13 +106,9 @@ export async function fetchAggregatedData(
const weekEnd = endOfDay(new Date(weekStart.getTime() + 6 * 86400000));
// ---------------- MONTH (rolling 5 weeks, MonSun aligned) ----------------
const weeklyBuckets: {
label: string;
start: Date;
end: Date;
amount: number;
}[] = [];
const weeklyBuckets = [];
if (mode === "rolling") {
const currentWeekStart = getStartOfWeek(now);
for (let i = 0; i < 5; i++) {
@@ -125,15 +122,30 @@ export async function fetchAggregatedData(
amount: 0
});
}
} else {
// calendar weeks within current month
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
let cursor = getStartOfWeek(startOfMonth);
while (cursor <= now) {
const start = new Date(cursor);
const end = endOfDay(new Date(start.getTime() + 6 * 86400000));
weeklyBuckets.push({
label: `${format(start)} - ${format(end)}`,
start,
end,
amount: 0
});
cursor = new Date(cursor.getTime() + 7 * 86400000);
}
}
// ---------------- YEAR (rolling 12 months) ----------------
const monthlyBuckets: {
label: string;
start: Date;
end: Date;
amount: number;
}[] = [];
const monthlyBuckets = [];
if (mode === "rolling") {
for (let i = 0; i < 12; i++) {
const d = new Date(now);
d.setMonth(d.getMonth() - i);
@@ -144,18 +156,27 @@ export async function fetchAggregatedData(
i === 0
? endOfDay(now) // current month → till now
: endOfDay(new Date(d.getFullYear(), d.getMonth() + 1, 0));
const label = `${d.toLocaleString("default", {
month: "short"
})}-${String(d.getFullYear()).slice(2)}`;
monthlyBuckets.push({
label,
label: `${d.toLocaleString("default", { month: "short" })}-${String(d.getFullYear()).slice(2)}`,
start,
end,
amount: 0
});
}
} else {
// calendar year (Jan → current month)
for (let i = 0; i <= now.getMonth(); i++) {
const start = new Date(now.getFullYear(), i, 1);
const end = endOfDay(new Date(now.getFullYear(), i + 1, 0));
monthlyBuckets.push({
label: `${start.toLocaleString("default", { month: "short" })}-${String(start.getFullYear()).slice(2)}`,
start,
end,
amount: 0
});
}
}
// ---------------- LOOP ----------------
for (const item of all) {
@@ -231,8 +252,12 @@ export async function fetchAggregatedData(
}
// ---------------- EXPORTS ----------------
export const fetchAggregatedExpenses = () =>
fetchAggregatedData("expense");
export const fetchAggregatedExpenses = (
mode: "rolling" | "calendar"
) =>
fetchAggregatedData("expense", mode);
export const fetchAggregatedIncome = () =>
fetchAggregatedData("income");
export const fetchAggregatedIncome = (
mode: "rolling" | "calendar"
) =>
fetchAggregatedData("income", mode);