calcuation fixes
This commit is contained in:
@@ -9,12 +9,35 @@ const DEFAULT_ICON = React.createElement(MonetizationOnIcon, {
|
||||
sx: { color: "#388e3c" }
|
||||
});
|
||||
|
||||
// ---------------- HELPERS ----------------
|
||||
const format = (d: Date) =>
|
||||
`${d.getDate()} ${d.toLocaleString("default", { month: "short" })}`;
|
||||
|
||||
const startOfDay = (d: Date) => {
|
||||
const x = new Date(d);
|
||||
x.setHours(0, 0, 0, 0);
|
||||
return x;
|
||||
};
|
||||
|
||||
const endOfDay = (d: Date) => {
|
||||
const x = new Date(d);
|
||||
x.setHours(23, 59, 59, 999);
|
||||
return x;
|
||||
};
|
||||
|
||||
const getStartOfWeek = (d: Date) => {
|
||||
const date = new Date(d);
|
||||
const day = date.getDay() || 7;
|
||||
if (day !== 1) date.setDate(date.getDate() - (day - 1));
|
||||
return startOfDay(date);
|
||||
};
|
||||
|
||||
// ---------------- LATEST ----------------
|
||||
export async function fetchLatestTransactions(
|
||||
type: "expense" | "income"
|
||||
): Promise<LatestItem[]> {
|
||||
const res = await api.get('/expenses', {
|
||||
params: { limit: 100, sort: '-occurred_at' }
|
||||
const res = await api.get("/expenses", {
|
||||
params: { limit: 100, sort: "-occurred_at" }
|
||||
});
|
||||
|
||||
const items = res.data?.items || res.data || [];
|
||||
@@ -54,11 +77,11 @@ export interface AggregatedDashboardData {
|
||||
topPayees: Array<{ payeeName: string; amount: number }>;
|
||||
}
|
||||
|
||||
// ---------------- GENERIC AGGREGATOR ----------------
|
||||
// ---------------- AGGREGATION ----------------
|
||||
export async function fetchAggregatedData(
|
||||
type: "expense" | "income"
|
||||
): Promise<AggregatedDashboardData> {
|
||||
const res = await api.get('/expenses', { params: { limit: 0 } });
|
||||
const res = await api.get("/expenses", { params: { limit: 0 } });
|
||||
const all: any[] = res.data?.items || res.data || [];
|
||||
|
||||
const now = new Date();
|
||||
@@ -71,56 +94,58 @@ export async function fetchAggregatedData(
|
||||
|
||||
const normalize = (amt: number) => Math.abs(amt);
|
||||
|
||||
// ---------------- WEEK ----------------
|
||||
const weekBuckets: Record<string, number> = {
|
||||
"Mon":0,"Tue":0,"Wed":0,"Thu":0,
|
||||
"Fri":0,"Sat":0,"Sun":0
|
||||
Mon: 0, Tue: 0, Wed: 0, Thu: 0,
|
||||
Fri: 0, Sat: 0, Sun: 0
|
||||
};
|
||||
|
||||
const monthBuckets: Record<string, { amount: number; range: string }> = {};
|
||||
const yearBuckets: Record<string, { amount: number; range: string }> = {};
|
||||
const weekStart = getStartOfWeek(now);
|
||||
const weekEnd = endOfDay(new Date(weekStart.getTime() + 6 * 86400000));
|
||||
|
||||
const getStartOfWeek = (d: Date) => {
|
||||
const date = new Date(d);
|
||||
const day = date.getDay() || 7;
|
||||
if (day !== 1) date.setDate(date.getDate() - (day - 1));
|
||||
date.setHours(0,0,0,0);
|
||||
return date;
|
||||
};
|
||||
// ---------------- MONTH (5 rolling weeks) ----------------
|
||||
const monthBuckets: {
|
||||
label: string;
|
||||
start: Date;
|
||||
end: Date;
|
||||
amount: number;
|
||||
}[] = [];
|
||||
|
||||
const format = (d: Date) =>
|
||||
`${d.getDate()} ${d.toLocaleString('default', { month: 'short' })}`;
|
||||
|
||||
// -------- MONTH (5 rolling weeks) --------
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const end = new Date(now);
|
||||
end.setDate(end.getDate() - i * 7);
|
||||
const end = endOfDay(new Date(now.getTime() - i * 7 * 86400000));
|
||||
const start = startOfDay(new Date(end.getTime() - 6 * 86400000));
|
||||
|
||||
const start = new Date(end);
|
||||
start.setDate(start.getDate() - 6);
|
||||
|
||||
const key = `${format(start)} - ${format(end)}`;
|
||||
|
||||
monthBuckets[key] = { amount: 0, range: key };
|
||||
monthBuckets.push({
|
||||
label: `${format(start)} - ${format(end)}`,
|
||||
start,
|
||||
end,
|
||||
amount: 0
|
||||
});
|
||||
}
|
||||
|
||||
// -------- YEAR (12 months rolling) --------
|
||||
// ---------------- YEAR (12 months) ----------------
|
||||
const yearBuckets: {
|
||||
label: string;
|
||||
start: Date;
|
||||
end: Date;
|
||||
amount: number;
|
||||
}[] = [];
|
||||
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const d = new Date(now);
|
||||
d.setMonth(d.getMonth() - i);
|
||||
|
||||
const start = new Date(d.getFullYear(), d.getMonth(), 1);
|
||||
const end = new Date(d.getFullYear(), d.getMonth() + 1, 0);
|
||||
const end = endOfDay(new Date(d.getFullYear(), d.getMonth() + 1, 0));
|
||||
|
||||
const label = d.toLocaleString('default', { month: 'short' });
|
||||
const range = `${format(start)} - ${format(end)}`;
|
||||
|
||||
yearBuckets[label] = { amount: 0, range };
|
||||
yearBuckets.push({
|
||||
label: d.toLocaleString("default", { month: "short" }),
|
||||
start,
|
||||
end,
|
||||
amount: 0
|
||||
});
|
||||
}
|
||||
|
||||
const weekStart = getStartOfWeek(now);
|
||||
const weekEnd = new Date(weekStart);
|
||||
weekEnd.setDate(weekStart.getDate() + 6);
|
||||
|
||||
// ---------------- LOOP ----------------
|
||||
for (const item of all) {
|
||||
const d = new Date(
|
||||
@@ -137,7 +162,7 @@ export async function fetchAggregatedData(
|
||||
const payee = item.payee?.name || item.payee || "Unknown";
|
||||
payeeMap[payee] = (payeeMap[payee] || 0) + amt;
|
||||
|
||||
// ---- WEEK
|
||||
// WEEK
|
||||
if (d >= weekStart && d <= weekEnd) {
|
||||
const day = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][d.getDay()];
|
||||
if (weekBuckets[day] !== undefined) {
|
||||
@@ -145,25 +170,17 @@ export async function fetchAggregatedData(
|
||||
}
|
||||
}
|
||||
|
||||
// ---- MONTH
|
||||
Object.entries(monthBuckets).forEach(([_, obj]) => {
|
||||
const [startStr, endStr] = obj.range.split(" - ");
|
||||
const start = new Date(startStr);
|
||||
const end = new Date(endStr);
|
||||
|
||||
if (d >= start && d <= end) {
|
||||
obj.amount += amt;
|
||||
// MONTH
|
||||
monthBuckets.forEach(b => {
|
||||
if (d >= b.start && d <= b.end) {
|
||||
b.amount += amt;
|
||||
}
|
||||
});
|
||||
|
||||
// ---- YEAR
|
||||
Object.entries(yearBuckets).forEach(([_, obj]) => {
|
||||
const [startStr, endStr] = obj.range.split(" - ");
|
||||
const start = new Date(startStr);
|
||||
const end = new Date(endStr);
|
||||
|
||||
if (d >= start && d <= end) {
|
||||
obj.amount += amt;
|
||||
// YEAR
|
||||
yearBuckets.forEach(b => {
|
||||
if (d >= b.start && d <= b.end) {
|
||||
b.amount += amt;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -184,7 +201,9 @@ export async function fetchAggregatedData(
|
||||
// highlight max
|
||||
Object.values(chartData).forEach(group => {
|
||||
let max = group[0];
|
||||
for (const g of group) if (g.amount > max.amount) max = g;
|
||||
for (const g of group) {
|
||||
if (g.amount > max.amount) max = g;
|
||||
}
|
||||
if (max.amount > 0) max.highlighted = true;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user