calcuation fixes

This commit is contained in:
2026-04-04 22:35:17 +05:30
parent 6abed4e72a
commit 4eca3b7124
2 changed files with 75 additions and 65 deletions

View File

@@ -13,16 +13,28 @@ import LatestItemsList, { LatestItem } from "./components/LatestItemsList";
import HistoryChart from "./components/HistoryChart";
import {
fetchLatestExpenses,
fetchLatestTransactions,
fetchAggregatedExpenses,
fetchAggregatedIncome,
AggregatedDashboardData
} from "./utils/dashboardLoader";
export default function Dashboard() {
const [latest, setLatest] = React.useState<LatestItem[]>([]);
const [aggregated, setAggregated] =
React.useState<AggregatedDashboardData | null>(null);
const [latest, setLatest] = React.useState<{
expense: LatestItem[];
income: LatestItem[];
}>({
expense: [],
income: []
});
const [aggregated, setAggregated] = React.useState<{
expense: AggregatedDashboardData | null;
income: AggregatedDashboardData | null;
}>({
expense: null,
income: null
});
const [mode, setMode] =
React.useState<"expense" | "income">("expense");
@@ -30,21 +42,33 @@ export default function Dashboard() {
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState<string | null>(null);
// -------- LOAD DATA --------
// -------- LOAD ONCE --------
React.useEffect(() => {
async function loadData() {
try {
setLoading(true);
const latestData = await fetchLatestExpenses();
const [
latestExpense,
latestIncome,
expenseData,
incomeData
] = await Promise.all([
fetchLatestTransactions("expense"),
fetchLatestTransactions("income"),
fetchAggregatedExpenses(),
fetchAggregatedIncome()
]);
const aggData =
mode === "expense"
? await fetchAggregatedExpenses()
: await fetchAggregatedIncome();
setLatest({
expense: latestExpense,
income: latestIncome
});
setLatest(latestData);
setAggregated(aggData);
setAggregated({
expense: expenseData,
income: incomeData
});
} catch (err: any) {
console.error(err);
@@ -55,7 +79,10 @@ export default function Dashboard() {
}
loadData();
}, [mode]);
}, []);
const currentData = aggregated[mode];
const currentLatest = latest[mode];
// -------- UI STATES --------
if (loading) {
@@ -89,22 +116,22 @@ export default function Dashboard() {
</Box>
<Grid container spacing={4} direction="row">
{/* LEFT → 1/3 (4 cols) */}
{/* LEFT → 1/3 */}
<Grid size={4}>
<LatestItemsList
title="Recent Transactions"
items={latest}
title={`Recent ${mode === "expense" ? "Expenses" : "Income"}`}
items={currentLatest}
onViewAll={() => {}}
/>
</Grid>
{/* RIGHT → 2/3 (8 cols) */}
{/* RIGHT → 2/3 */}
<Grid size={8}>
<HistoryChart
header={`${mode === "expense" ? "Expense" : "Income"} Breakdown`}
summary="Interactive chronological tracking"
tabs={["Today", "Week", "Month", "Year"]}
data={aggregated?.chartData || {}}
tabs={["Week", "Month", "Year"]}
data={currentData?.chartData || {}}
/>
</Grid>
</Grid>

View File

@@ -10,32 +10,41 @@ const DEFAULT_ICON = React.createElement(MonetizationOnIcon, {
});
// ---------------- LATEST ----------------
export async function fetchLatestExpenses(): Promise<LatestItem[]> {
export async function fetchLatestTransactions(
type: "expense" | "income"
): Promise<LatestItem[]> {
const res = await api.get('/expenses', {
params: { limit: 10, sort: '-occurred_at' }
params: { limit: 100, sort: '-occurred_at' }
});
const items = res.data?.items || res.data || [];
return items.map((exp: any, index: number) => {
const time = new Date(
exp.occurred_at || exp.created_at || Date.now()
).getTime();
const isValid = (amt: number) =>
type === "expense" ? amt < 0 : amt > 0;
const diffDays = Math.floor(
Math.abs(Date.now() - time) / (1000 * 60 * 60 * 24)
);
return items
.filter((item: any) => isValid(Number(item.amount) || 0))
.slice(0, 10)
.map((exp: any, index: number) => {
const time = new Date(
exp.occurred_at || exp.created_at || Date.now()
).getTime();
return {
id: exp.id || index,
icon: DEFAULT_ICON,
iconBgColor: "#e8f5e9",
title: exp.payee?.name || exp.payee || "Unknown Payee",
subtitle: exp.category?.name || exp.account?.name || "Transaction",
amount: `Rs ${exp.amount || 0}`,
timeAgo: diffDays === 0 ? "Today" : `${diffDays} days ago`
};
});
const diffDays = Math.floor(
Math.abs(Date.now() - time) / (1000 * 60 * 60 * 24)
);
return {
id: exp.id || index,
icon: DEFAULT_ICON,
iconBgColor:
type === "expense" ? "#ffebee" : "#e8f5e9",
title: exp.payee?.name || exp.payee || "Unknown Payee",
subtitle: exp.category?.name || exp.account?.name || "Transaction",
amount: `Rs ${Math.abs(exp.amount || 0)}`,
timeAgo: diffDays === 0 ? "Today" : `${diffDays} days ago`
};
});
}
// ---------------- TYPES ----------------
@@ -62,12 +71,6 @@ export async function fetchAggregatedData(
const normalize = (amt: number) => Math.abs(amt);
// ---------------- BUCKETS ----------------
const todayBuckets: Record<string, number> = {
"12am":0,"3am":0,"6am":0,"9am":0,
"12pm":0,"3pm":0,"6pm":0,"9pm":0
};
const weekBuckets: Record<string, number> = {
"Mon":0,"Tue":0,"Wed":0,"Thu":0,
"Fri":0,"Sat":0,"Sun":0
@@ -134,25 +137,6 @@ export async function fetchAggregatedData(
const payee = item.payee?.name || item.payee || "Unknown";
payeeMap[payee] = (payeeMap[payee] || 0) + amt;
// ---- TODAY
if (
d.getDate() === now.getDate() &&
d.getMonth() === now.getMonth() &&
d.getFullYear() === now.getFullYear()
) {
const hr = d.getHours();
let label = "12am";
if (hr >= 3 && hr < 6) label = "3am";
else if (hr >= 6 && hr < 9) label = "6am";
else if (hr >= 9 && hr < 12) label = "9am";
else if (hr >= 12 && hr < 15) label = "12pm";
else if (hr >= 15 && hr < 18) label = "3pm";
else if (hr >= 18 && hr < 21) label = "6pm";
else if (hr >= 21) label = "9pm";
todayBuckets[label] += amt;
}
// ---- WEEK
if (d >= weekStart && d <= weekEnd) {
const day = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][d.getDay()];
@@ -192,7 +176,6 @@ export async function fetchAggregatedData(
}));
const chartData = {
today: toPoints(todayBuckets),
week: toPoints(weekBuckets),
month: toPoints(monthBuckets),
year: toPoints(yearBuckets)