- A.1: fixed_expenses per month now threaded through to chart bucket - A.2: null = no data (forecast), 0 = real plotted zero — distinguishable - A.3: x-axis clipped to last actual month (IncomeAreaChart + IncomeBarChart + MachineLineChart) - A.4: chart hues as CSS vars (--color-chart-income/fixed/running) — deeper steps of same hues, validated for CVD - A.5: chart-type toggle (Lines / Cost stack / Profit) + localStorage persistence + dynamic legend - A.6: profit on charts page comes from computeProfit() - B.1: deleted /expenses/plant-overheads, /expenses/insurance, /expenses/tracking (all empty); added /expenses/vehicles; ExpenseSectionPage now has an empty state - B.2: captured R 157,200 Personnel block, R 100,000 Maintenance, R 10,000 Petty Cash; roll-up reconciles to R 675,162.93 (= sum of non-Plant non-Santam rows; workbook grand total R 1,110,486.87 is internally off by R 14,477.56 vs its own rows) - B.3: seed flags incl<excl, VAT>20%, broken VAT math — does NOT silently correct; 4 anomalies reported on Charl-CCS + Buildsmart - B.4: noted that workbook Vehicle Costs subtotal skips Santam (app R 9,673.87 is correct; workbook is wrong) - B.2 reconciliation assertion added to verify-cost-reconciliation.mjs - Sidebar updated: Vehicles added, Insurance/Tracking/Plant-Overheads removed
36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
import { getAssets, getActualMonthlyIncome, getRunningCosts } from "@/lib/data";
|
|
import { ChartsGrid } from "@/components/ChartsGrid";
|
|
import { buildIncomeRows } from "@/lib/rows";
|
|
|
|
export default async function ChartsPage() {
|
|
const [assets, incomeActual, running] = await Promise.all([
|
|
getAssets(),
|
|
getActualMonthlyIncome(),
|
|
getRunningCosts(),
|
|
]);
|
|
|
|
const rows = buildIncomeRows(assets, incomeActual, running);
|
|
|
|
const items = rows.map((r) => {
|
|
// r.months / r.fixedMonths / r.runningMonths already distinguish null (forecast) from 0 (Part A.2).
|
|
return {
|
|
id: r.id,
|
|
code: r.code,
|
|
name: r.name,
|
|
bucket: {
|
|
income: r.months, // includes 0 as a real plotted value (Part A.2)
|
|
fixed: r.fixedMonths, // Part A.1 — thread real fixed_expenses through
|
|
running: r.runningMonths,
|
|
},
|
|
totalIncome: r.income,
|
|
totalProfit: r.ytdProfit,
|
|
lastActualMonth: r.lastActualMonth,
|
|
};
|
|
});
|
|
|
|
return (
|
|
<div className="p-8 max-w-[1400px]">
|
|
<ChartsGrid items={items} />
|
|
</div>
|
|
);
|
|
}
|