removed client data massaging with backend report using feature/report

This commit is contained in:
2026-04-24 14:27:20 +05:30
parent 49bdb85088
commit 1fe44abfde
7 changed files with 244 additions and 345 deletions

View File

@@ -0,0 +1,9 @@
import { api } from "../../../react-openapi";
export async function fetchReport(params: {
period: "weekly" | "monthly" | "yearly" | "fyly";
rolling?: boolean;
}) {
const res = await api.get("/reports", { params });
return res.data;
}

View File

@@ -0,0 +1,96 @@
import {
AggregatedDashboardData,
ChartData,
ChartDataPoint,
} from "../../components/HistoryChart";
type ReportBucket = any;
const sumBucket = (bucket: ReportBucket, flow: "expenses" | "incomes") =>
bucket.groups.reduce(
(acc: number, g: any) => acc + (g?.[flow]?.sum || 0),
0
);
const toLabel = (start: string, end: string, type: "weekly" | "monthly") => {
const s = new Date(start);
const e = new Date(end);
if (type === "monthly") {
return s.toLocaleString("default", { month: "short" });
}
return `${s.getDate()}${e.getDate()} ${e.toLocaleString("default", {
month: "short",
})}`;
};
const toPoints = (
buckets: ReportBucket[],
type: "weekly" | "monthly",
flow: "expenses" | "incomes"
): ChartDataPoint[] => {
return buckets.map((b, i) => {
const amount = sumBucket(b, flow);
const prev = buckets[i - 1];
return {
id: toLabel(b.start, b.end, type),
amount,
compare: prev
? {
id: toLabel(prev.start, prev.end, type),
amount: sumBucket(prev, flow),
}
: undefined,
};
});
};
export function mapReportToDashboard(
weekly: ReportBucket[],
monthly: ReportBucket[],
type: "expense" | "income"
): AggregatedDashboardData {
const flow = type === "expense" ? "expenses" : "incomes";
const chartData: ChartData = {
daily: [],
weekly: {
rolling: toPoints(weekly, "weekly", flow),
calendar: toPoints(weekly, "weekly", flow),
},
monthly: {
rolling: toPoints(monthly, "monthly", flow),
calendar: toPoints(monthly, "monthly", flow),
},
};
const totalAmount = weekly.reduce(
(acc, b) => acc + sumBucket(b, flow),
0
);
const payeeMap: Record<string, number> = {};
for (const b of weekly) {
for (const g of b.groups) {
const key = g.group_key || "Unknown";
const amt = g?.[flow]?.sum || 0;
payeeMap[key] = (payeeMap[key] || 0) + amt;
}
}
const topPayees = Object.entries(payeeMap)
.map(([payeeName, amount]) => ({ payeeName, amount }))
.sort((a, b) => b.amount - a.amount)
.slice(0, 5);
return {
chartData,
totalAmount,
topPayees,
};
}

View File

@@ -0,0 +1,114 @@
import { fetchReport } from "./report.api";
import {
AggregatedDashboardData,
ChartData,
ChartDataPoint,
} from "../components/HistoryChart";
type ReportBucket = any; // replace with generated type if available
function sumBucket(bucket: ReportBucket, flow: "expenses" | "incomes") {
return bucket.groups.reduce(
(acc: number, g: any) => acc + (g?.[flow]?.sum || 0),
0
);
}
function toLabel(start: string, end: string, type: "weekly" | "monthly") {
const s = new Date(start);
const e = new Date(end);
if (type === "monthly") {
return s.toLocaleString("default", { month: "short" });
}
const sd = s.getDate();
const ed = e.getDate();
const m = e.toLocaleString("default", { month: "short" });
return `${sd}${ed} ${m}`;
}
function toChartPoints(
buckets: ReportBucket[],
type: "weekly" | "monthly",
flow: "expenses" | "incomes"
): ChartDataPoint[] {
return buckets.map((b, i) => {
const amount = sumBucket(b, flow);
const prev = buckets[i - 1];
const compareAmount = prev ? sumBucket(prev, flow) : 0;
return {
id: toLabel(b.start, b.end, type),
amount,
compare: prev
? {
id: toLabel(prev.start, prev.end, type),
amount: compareAmount,
}
: undefined,
};
});
}
function buildChartData(
weekly: ReportBucket[],
monthly: ReportBucket[],
flow: "expenses" | "incomes"
): ChartData {
return {
daily: [], // not supported by /reports → keep empty or drop
weekly: {
rolling: toChartPoints(weekly, "weekly", flow),
calendar: toChartPoints(weekly, "weekly", flow), // same unless backend differentiates
},
monthly: {
rolling: toChartPoints(monthly, "monthly", flow),
calendar: toChartPoints(monthly, "monthly", flow),
},
};
}
function getTopPayees(buckets: ReportBucket[], flow: "expenses" | "incomes") {
const map: Record<string, number> = {};
for (const b of buckets) {
for (const g of b.groups) {
const key = g.group_key || "Unknown";
const amt = g?.[flow]?.sum || 0;
map[key] = (map[key] || 0) + amt;
}
}
return Object.entries(map)
.map(([payeeName, amount]) => ({ payeeName, amount }))
.sort((a, b) => b.amount - a.amount)
.slice(0, 5);
}
export async function getDashboardData(
type: "expense" | "income"
): Promise<AggregatedDashboardData> {
const flow = type === "expense" ? "expenses" : "incomes";
const [weeklyBuckets, monthlyBuckets] = await Promise.all([
fetchReport({ period: "weekly", rolling: true }),
fetchReport({ period: "monthly", rolling: true }),
]);
const chartData = buildChartData(weeklyBuckets, monthlyBuckets, flow);
const totalAmount = weeklyBuckets.reduce(
(acc: number, b: any) => acc + sumBucket(b, flow),
0
);
const topPayees = getTopPayees(weeklyBuckets, flow);
return {
chartData,
totalAmount,
topPayees,
};
}

View File

@@ -0,0 +1,17 @@
import { useQuery } from "@tanstack/react-query";
import { fetchReport } from "./report.api";
export interface ReportParams {
period: "weekly" | "monthly" | "yearly" | "fyly";
rolling?: boolean;
report_date?: string;
group_by?: ("flow" | "payee" | "tags")[];
ignore_self?: boolean;
}
export function useReport(params: ReportParams) {
return useQuery({
queryKey: ["report", params],
queryFn: () => fetchReport(params),
});
}