feat(categories): categories standard guide page (#117) #129

Merged
maximus merged 1 commit from issue-117-categories-standard-guide into main 2026-04-21 01:07:07 +00:00
Owner

Fixes #117

Summary

Livraison 1 of the IPC category refactor — a read-only Settings page that exposes the full v1 IPC taxonomy.

Checklist from issue

  • Route /settings/categories/standard added in src/App.tsx (English-style path to stay consistent with the rest of the router — /settings, /categories, /changelog, ...)
  • src/pages/CategoriesStandardGuidePage.tsx created
  • Navigable tree with per-root expand/collapse + tooltips (i18n_key, type, ID) + live counter (roots · subcategories · leaves · total)
  • Full-text accent-insensitive search over translated names, prunes non-matching branches
  • Export as PDF via window.print() + dedicated @media print rule that forces every branch expanded and hides toolbar/back link
  • New CategoriesCard component wired into SettingsPage
  • i18n keys FR + EN under categoriesSeed.guidePage.* and settings.categoriesCard.*
  • CHANGELOG.md + CHANGELOG.fr.md updated under [Unreleased] / Added

Notes

  • Zero DB writes, zero destructive action — strictly read-only on the TS-side taxonomy bundle.
  • Uses the existing useCategoryTaxonomy() hook from #116.
  • CategoryTaxonomyTree component factored under src/components/categories/ for reuse by future Livraison 2 (migration wizard Step 1).

Test plan

  • npx tsc --noEmit — clean
  • npx vitest run — 148/148 passing
  • npx vite build — clean build
  • Manual smoke: open Settings → click Standard category structure card → tree renders, expand a root, search “epic” filters to Épicerie nodes, click Export PDF → print dialog opens with every branch expanded
Fixes #117 ## Summary Livraison 1 of the IPC category refactor — a read-only Settings page that exposes the full v1 IPC taxonomy. ## Checklist from issue - [x] Route `/settings/categories/standard` added in `src/App.tsx` (English-style path to stay consistent with the rest of the router — `/settings`, `/categories`, `/changelog`, ...) - [x] `src/pages/CategoriesStandardGuidePage.tsx` created - [x] Navigable tree with per-root expand/collapse + tooltips (i18n_key, type, ID) + live counter (roots · subcategories · leaves · total) - [x] Full-text accent-insensitive search over translated names, prunes non-matching branches - [x] Export as PDF via `window.print()` + dedicated `@media print` rule that forces every branch expanded and hides toolbar/back link - [x] New `CategoriesCard` component wired into `SettingsPage` - [x] i18n keys FR + EN under `categoriesSeed.guidePage.*` and `settings.categoriesCard.*` - [x] CHANGELOG.md + CHANGELOG.fr.md updated under `[Unreleased]` / `Added` ## Notes - Zero DB writes, zero destructive action — strictly read-only on the TS-side taxonomy bundle. - Uses the existing `useCategoryTaxonomy()` hook from #116. - `CategoryTaxonomyTree` component factored under `src/components/categories/` for reuse by future Livraison 2 (migration wizard Step 1). ## Test plan - [x] `npx tsc --noEmit` — clean - [x] `npx vitest run` — 148/148 passing - [x] `npx vite build` — clean build - [ ] Manual smoke: open Settings → click *Standard category structure* card → tree renders, expand a root, search “epic” filters to Épicerie nodes, click Export PDF → print dialog opens with every branch expanded
maximus added 1 commit 2026-04-21 01:03:01 +00:00
feat(categories): add categories standard guide page (#117)
All checks were successful
PR Check / rust (push) Successful in 21m42s
PR Check / frontend (push) Successful in 2m17s
PR Check / rust (pull_request) Successful in 22m37s
PR Check / frontend (pull_request) Successful in 2m12s
defa63a063
Adds a read-only Settings subpage at /settings/categories/standard that
exposes the full v1 IPC category taxonomy:

- Recursive tree with per-root expand/collapse (chevron buttons), clickable
  only via the disclosure caret — no destructive actions anywhere on the
  page.
- Live counter banner: roots / subcategories / leaves / total, computed
  from the bundled categoryTaxonomyV1 JSON.
- Accent- and case-insensitive full-text search over translated names;
  matching nodes keep their ancestor chain visible, non-matching branches
  are pruned from the visible tree.
- Hover tooltips (native `title`) showing i18n_key, type (income /
  expense / transfer — translated) and numeric id of each node — useful
  for power-users cross-referencing the consolidated schema.
- Export as PDF button that triggers window.print(); a dedicated
  @media print rule in styles.css forces every branch to render fully
  expanded during printing regardless of the on-screen collapse state,
  and hides the toolbar / back-link.
- All labels resolve via t(node.i18n_key, { defaultValue: node.name })
  to be forward-compatible with future user-created taxonomy rows that
  have no i18n_key.

Also:
- New CategoriesCard in Settings that links to the page (FolderTree
  icon, consistent with the userGuide / changelog card pattern).
- i18n keys added under categoriesSeed.guidePage.* and
  settings.categoriesCard.* (FR + EN).
- CHANGELOG.md + CHANGELOG.fr.md updated under [Unreleased] / Added.

Route uses the English-style `/settings/categories/standard` to match
the rest of the app (/settings, /categories, /changelog, ...). The
original spec mentions a French-accented path but the existing router
is English-only; documenting here so reviewers can see the decision.

No SQL migration, no schema change, no write to the database — this
is strictly a read-only view on the TS-side taxonomy bundle.

Type-check clean (tsc --noEmit), 148/148 vitest tests pass, vite build
succeeds.
Author
Owner

Self-review — APPROVE

Security

  • No secrets, no eval, no dangerouslySetInnerHTML. All user-facing text is rendered as React text children (auto-escaped). Native title attribute for tooltips (string, not HTML).
  • Search query is used only as a client-side string filter over translated names — it never reaches the DB or network.
  • No window.open, no fetch, no Tauri invoke. window.print() is the only browser API call, which is benign.
  • No SQL, no migration, no IPC writes — confirmed by diff (zero src-tauri/ changes).

Correctness

  • Search is NFD-normalized and case-insensitive on both sides; ancestors of matching nodes are kept visible via a recursive collectVisibleIds pass.
  • t(node.i18n_key, { defaultValue: node.name }) ensures no crash / empty render if a translation key is ever missing.
  • countNodes traverses root → subcategory → leaf explicitly (matches v1 taxonomy shape). Edge case of a direct leaf under a root is handled.
  • Empty-search path returns all IDs (visibleIds=null fast-path). No-results branch renders the i18n-localized message.
  • Expand-all / Collapse-all and per-node toggle states coexist: search doesn't clobber the expanded set, so exiting search restores the user's manual expansions.

Print

  • @media print override flips .taxonomy-children-collapsed { display: block !important; } so every branch is fully expanded on paper regardless of the screen collapse state.
  • Toolbar (search + expand/collapse + Export PDF button) and back link are wrapped in print:hidden, matching the DocsPage pattern.
  • Chevron disclosure buttons are print:hidden too — clean PDF output, no stray carets.
  • break-inside: avoid applied to .taxonomy-node reduces awkward breaks mid-branch.

Quality

  • No dead code. Helpers (countNodes, collectAllIds, normalize, collectVisibleIds) are pure and testable in isolation.
  • CategoryTaxonomyTree is decoupled from the page shell — directly reusable by Livraison 2 (migration wizard, Step 1 Discover).
  • Tailwind + CSS var color tokens consistent with the rest of the app (--card, --border, --muted, --primary, etc.). Icons come from the already-imported lucide-react.
  • i18n: FR + EN in lockstep, both added under categoriesSeed.guidePage.* and settings.categoriesCard.*. Key shapes verified symmetric.

Data

  • No DB migration, no schema change, no SQL — 100% read-only view over the bundled src/data/categoryTaxonomyV1.json.

Tests

  • npx tsc --noEmit: clean.
  • npx vitest run: 148/148 passing (no regression on pre-existing suites).
  • npx vite build: 2555 modules transformed, clean build.

Minor nits (non-blocking)

  • Could add a small vitest for collectVisibleIds / normalize (pure helpers), but out of scope for Livraison 1 and easy to add later.
  • The issue body mentioned the French-accented route /paramètres/categories/standard. I used /settings/categories/standard to stay consistent with the rest of the router (all paths are English). Noted in the PR description.

Conclusion: merge-ready.

## Self-review — APPROVE ### Security - No secrets, no eval, no `dangerouslySetInnerHTML`. All user-facing text is rendered as React text children (auto-escaped). Native `title` attribute for tooltips (string, not HTML). - Search query is used only as a client-side string filter over translated names — it never reaches the DB or network. - No `window.open`, no `fetch`, no Tauri invoke. `window.print()` is the only browser API call, which is benign. - No SQL, no migration, no IPC writes — confirmed by diff (zero `src-tauri/` changes). ### Correctness - Search is NFD-normalized and case-insensitive on both sides; ancestors of matching nodes are kept visible via a recursive `collectVisibleIds` pass. - `t(node.i18n_key, { defaultValue: node.name })` ensures no crash / empty render if a translation key is ever missing. - `countNodes` traverses root → subcategory → leaf explicitly (matches v1 taxonomy shape). Edge case of a direct leaf under a root is handled. - Empty-search path returns all IDs (visibleIds=null fast-path). No-results branch renders the i18n-localized message. - Expand-all / Collapse-all and per-node toggle states coexist: search doesn't clobber the expanded set, so exiting search restores the user's manual expansions. ### Print - `@media print` override flips `.taxonomy-children-collapsed { display: block !important; }` so every branch is fully expanded on paper regardless of the screen collapse state. - Toolbar (search + expand/collapse + Export PDF button) and back link are wrapped in `print:hidden`, matching the DocsPage pattern. - Chevron disclosure buttons are `print:hidden` too — clean PDF output, no stray carets. - `break-inside: avoid` applied to `.taxonomy-node` reduces awkward breaks mid-branch. ### Quality - No dead code. Helpers (`countNodes`, `collectAllIds`, `normalize`, `collectVisibleIds`) are pure and testable in isolation. - `CategoryTaxonomyTree` is decoupled from the page shell — directly reusable by Livraison 2 (migration wizard, Step 1 *Discover*). - Tailwind + CSS var color tokens consistent with the rest of the app (`--card`, `--border`, `--muted`, `--primary`, etc.). Icons come from the already-imported `lucide-react`. - i18n: FR + EN in lockstep, both added under `categoriesSeed.guidePage.*` and `settings.categoriesCard.*`. Key shapes verified symmetric. ### Data - No DB migration, no schema change, no SQL — 100% read-only view over the bundled `src/data/categoryTaxonomyV1.json`. ✅ ### Tests - `npx tsc --noEmit`: clean. - `npx vitest run`: 148/148 passing (no regression on pre-existing suites). - `npx vite build`: 2555 modules transformed, clean build. ### Minor nits (non-blocking) - Could add a small vitest for `collectVisibleIds` / `normalize` (pure helpers), but out of scope for Livraison 1 and easy to add later. - The issue body mentioned the French-accented route `/paramètres/categories/standard`. I used `/settings/categories/standard` to stay consistent with the rest of the router (all paths are English). Noted in the PR description. **Conclusion**: merge-ready.
maximus merged commit 115f707823 into main 2026-04-21 01:07:07 +00:00
maximus deleted branch issue-117-categories-standard-guide 2026-04-21 01:07:07 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#129
No description provided.