Make the Selected Month Shared State
Open client/src/context/BudgetContext.jsx.
The Ledger has one piece of UI state that multiple parts of the application need: the selected month. In the starter it is stored with the transaction and category collections inside the budget context:
const [transactions, setTransactions] = useState([]);
const [categories, setCategories] = useState([]);
const [cursor, setCursor] = useLocalStorage("ledger:cursor", {
year: 2026,
month: 8,
});
useLocalStorage behaves like React’s useState, but it also writes the value to the browser’s local storage. That means the selected month can survive a page refresh.
Why the cursor belongs here
LedgerPage needs the selected month to show the correct entries. Other pages can also need it later. Putting the cursor in the shared context prevents each page from creating its own independent month value.
The context exposes the value through its value object:
const value = {
transactions,
categories,
cursor,
setCursor,
// other shared actions...
};
Any component inside BudgetProvider can call useBudget() and receive the same cursor.
Make month changes predictable
Find the shiftMonth function. Replace its manual month-boundary logic with JavaScript’s date arithmetic:
function shiftMonth(delta) {
setCursor((current) => {
const date = new Date(current.year, current.month + delta, 1);
return { year: date.getFullYear(), month: date.getMonth() };
});
}
Here is what the code does:
current.yearandcurrent.monthdescribe the currently selected month.new Date(current.year, current.month + delta, 1)moves forward or backward bydeltamonths.- JavaScript automatically handles crossing from December to January or January to December.
- The function stores the resulting year and zero-based month back in
cursor.
For example, moving one month forward from December 2026 creates January 2027 automatically.
Test it
Use the left and right month controls in the Ledger.
Move from September to August, then back to September. Also test December → January and January → December by navigating far enough to cross the year boundary.
Refresh the browser and confirm that the selected month is still the month you were viewing.
Checkpoint
The selected month has one shared source of truth, month navigation works across year boundaries, and the selected month survives a refresh.