CodingNic

Categories and Summary

Build the All-Time Summary Calculations

Categories and Summary 24 min read

Build the All-Time Summary Calculations

Open:

text
client/src/pages/SummaryPage.jsx
client/src/lib/finance.js

The Ledger page summarizes the selected month. The Summary page answers the broader question: what has happened across all transactions recorded so far?

Keep the arithmetic outside the JSX. A named calculation can be reused by multiple views and tested without rendering the page.

First calculate total income and expenses from the complete transaction collection:

javascript
const totals = useMemo(() => {
  return transactions.reduce(
    (result, transaction) => {
      if (transaction.type === "income") {
        result.income += transaction.amount;
      }

      if (transaction.type === "expense") {
        result.expense += transaction.amount;
      }

      return result;
    },
    { income: 0, expense: 0 }
  );
}, [transactions]);

reduce() visits each transaction and carries two running totals. useMemo() tells React to keep the calculated result until transactions changes.

Derive the net balance separately:

javascript
const balance = totals.income - totals.expense;

Keeping the balance formula separate makes the relationship obvious:

text
balance = income − expenses

Now calculate savings rate only when there is income to divide by:

javascript
const savingsRate =
  totals.income > 0
    ? (balance / totals.income) * 100
    : null;

For example, $5,200 of income and $1,366.50 of expenses produce a balance of $3,833.50 and a savings rate of about 73.7%.

Use the existing helpers for historical information instead of rebuilding grouping logic in the component:

javascript
const months = useMemo(
  () => computeMonthlyTotals(transactions),
  [transactions]
);

const categoryTotals = useMemo(
  () => computeCategoryTotals(transactions, categories),
  [transactions, categories]
);

The first value gives the page month-by-month totals. The second gives category totals and ordering. The component should consume those values and render them; it should not create a second set of financial rules.

Test it

Open Summary and compare total income, total expenses, and balance with the records in server/data/db.json.

Add a transaction on the Ledger, return to Summary, and confirm that the all-time values update automatically.

Checkpoint

The Summary page derives all-time financial values from shared transaction data and keeps reusable calculations out of the presentation markup.