Skip to content

feat(pwa): add ledger category expense drill-in#13

Merged
sergdort merged 3 commits intomainfrom
feat/categories-make-over
Mar 8, 2026
Merged

feat(pwa): add ledger category expense drill-in#13
sergdort merged 3 commits intomainfrom
feat/categories-make-over

Conversation

@sergdort
Copy link
Owner

@sergdort sergdort commented Mar 7, 2026

Summary

  • add ledger expense-category drill-in route under Expenses (/expenses/category/:categoryId?month=YYYY-MM)
  • make Home month URL-backed and preserve month on drill-in/back navigation
  • keep Expenses tab active on detail routes and add top-bar back affordance in mobile shell
  • refactor expenses rendering into a shared list component reused by generic Expenses page and drill-in detail page
  • add filtered expense list support in the PWA API client (from, to, categoryId, limit)
  • document the new PWA behavior in README and AGENTS

Testing

  • pnpm --filter @tithe/pwa lint
  • pnpm --filter @tithe/pwa typecheck
  • pnpm --filter @tithe/tests typecheck
  • pnpm --filter @tithe/tests test:pwa -- pwa/mobile.spec.ts

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an expense-category “drill-in” experience from the Home monthly ledger into an Expenses-tab detail route, with month selection persisted via the URL for consistent navigation (including a mobile top-bar back affordance).

Changes:

  • Added /expenses/category/:categoryId?month=YYYY-MM detail page and wiring from Home monthly ledger expense rows.
  • Made Home’s selected month URL-backed (?month=YYYY-MM) and preserved month across drill-in/back navigation.
  • Refactored Expenses rendering into a shared ExpensesList component, and enhanced ledger/category list styling with category icon/color accents.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/pwa/mobile.spec.ts Adds E2E coverage for month-scoped category drill-in + back navigation; adjusts sync-range capture.
apps/pwa/src/pages/HomePage.tsx Syncs Home month cursor with ?month= and navigates to category detail with month preserved.
apps/pwa/src/pages/ExpensesPage.tsx Replaces inline list rendering with shared ExpensesList.
apps/pwa/src/pages/ExpenseCategoryDetailPage.tsx New month-scoped category detail page that loads filtered expenses.
apps/pwa/src/lib/date/month.ts Adds formatMonthParam/parseMonthParam helpers for URL month handling.
apps/pwa/src/features/home/hooks/useHomeMonthCursor.ts Adds initialMonthCursor option for URL-driven initialization.
apps/pwa/src/features/home/components/MonthlyLedgerCard.tsx Makes expense rows tappable (drill-in), adds category icon/color accents.
apps/pwa/src/features/expenses/components/ExpensesList.tsx New shared list component (grouping, avatars, reimbursement actions).
apps/pwa/src/features/categories/components/CategoriesListCard.tsx Groups categories into sections and adds color-accented rows.
apps/pwa/src/components/MobileShell.tsx Keeps Expenses tab active on subroutes and adds optional top-bar back button.
apps/pwa/src/api.ts Adds filtered expenses list support (from, to, categoryId, limit).
apps/pwa/src/App.tsx Registers new route and implements back behavior for detail route.
README.md Documents new drill-in behavior and styling updates.
AGENTS.md Updates agent-facing behavior notes for the new flows.
.agents/notes.md Adds implementation note about category list grouping/color accents.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const CategoryRowIcon =
CATEGORY_ICON_COMPONENTS[category.icon || 'category'] ?? CategoryIcon;
}: CategoriesListCardProps) => {
const incomeCategories = categories.filter((category) => category.kind !== 'expense');
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incomeCategories currently includes both income and transfer kinds (kind !== 'expense'), but the UI section is labeled "Income". This will place transfer categories under an "Income" header, which is misleading and makes transfer categories harder to find/edit. Consider either filtering this section to kind === 'income' and adding a separate "Transfers" section, or renaming the section to something like "Income & transfers" (and updating the empty-state copy accordingly).

Suggested change
const incomeCategories = categories.filter((category) => category.kind !== 'expense');
const incomeCategories = categories.filter((category) => category.kind === 'income');

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +40
if (typeof window !== 'undefined' && window.history.length > 1) {
navigate(-1);
return;
}
navigate(backToHomeHref);
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The back handler uses window.history.length > 1 to decide whether to navigate(-1). In practice, history.length can be >1 even when the user deep-linked into the PWA from another site, so the in-app back button may exit the app instead of returning to the intended Home/month context. Consider tracking the in-app origin (e.g., router location.state) and only using navigate(-1) when the previous entry is within the app; otherwise always navigate to the computed backToHomeHref (optionally with replace).

Suggested change
if (typeof window !== 'undefined' && window.history.length > 1) {
navigate(-1);
return;
}
navigate(backToHomeHref);
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
try {
const referrer = document.referrer;
if (referrer) {
const referrerUrl = new URL(referrer);
if (referrerUrl.origin === window.location.origin) {
navigate(-1);
return;
}
}
} catch {
// If parsing referrer fails, fall through to backToHomeHref
}
}
navigate(backToHomeHref, { replace: true });

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

@LogenNineFingersIsAlive LogenNineFingersIsAlive left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work — the drill-in flow and tab-state handling look solid, and the Playwright coverage is strong.

One thing to double-check: api.expenses.list defaults to limit=100, and ExpenseCategoryDetailPage calls it without overriding that limit. For very active categories/months this could silently truncate the detail list.

If intentional, all good; if not, consider paging or requesting a higher/unbounded limit for this route.

@sergdort
Copy link
Owner Author

sergdort commented Mar 8, 2026

Addressed the review feedback in follow-up commit 7ace4f6:\n\n- switched detail back behavior to use in-app navigation state () and fall back to with for deep links\n- increased ledger drill-in fetch limit to to avoid silent truncation in busy months (and added assertion in Playwright)\n- clarified categories section label to with updated empty-state copy\n\nValidation rerun after changes:\n-

@tithe/pwa@0.1.0 lint /Users/sergiishulga/Developer/tithe/apps/pwa
biome check src

Checked 43 files in 14ms. No fixes applied.\n-

@tithe/pwa@0.1.0 typecheck /Users/sergiishulga/Developer/tithe/apps/pwa
tsc --noEmit -p tsconfig.json\n-
@tithe/tests@0.1.0 typecheck /Users/sergiishulga/Developer/tithe/tests
tsc --noEmit -p tsconfig.json\n-
@tithe/tests@0.1.0 test:pwa /Users/sergiishulga/Developer/tithe/tests
playwright test -- pwa/mobile.spec.ts

Running 5 tests using 1 worker

✓ 1 pwa/mobile.spec.ts:3:1 › home screen renders mobile navigation without horizontal overflow (649ms)
✓ 2 pwa/mobile.spec.ts:13:1 › expenses list avatar prefers logo, then emoji, then initials and shows pending badge (424ms)
✓ 3 pwa/mobile.spec.ts:138:1 › home shows monthly ledger and transfer direction in add transaction flow (833ms)
✓ 4 pwa/mobile.spec.ts:338:1 › ledger expense category drills into month-scoped detail and back preserves home month (668ms)
✓ 5 pwa/mobile.spec.ts:567:1 › monthly ledger sync posts current month range with overwrite and shows result summary (632ms)

5 passed (4.4s)

@sergdort
Copy link
Owner Author

sergdort commented Mar 8, 2026

Addressed the review feedback in follow-up commit 7ace4f6:

  • switched detail back behavior to use in-app navigation state (inAppBackTarget) and fall back to /?month=... with replace for deep links
  • increased ledger drill-in fetch limit to 1000 to reduce silent truncation risk in busy months (and added assertion in Playwright)
  • clarified categories section label to Income & Transfers with updated empty-state copy

Validation rerun after changes:

  • pnpm --filter @tithe/pwa lint
  • pnpm --filter @tithe/pwa typecheck
  • pnpm --filter @tithe/tests typecheck
  • pnpm --filter @tithe/tests test:pwa -- pwa/mobile.spec.ts

@sergdort sergdort merged commit d9a3f8d into main Mar 8, 2026
1 check passed
@sergdort sergdort deleted the feat/categories-make-over branch March 8, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants