refactor: split useReports into per-domain hooks + URL period (#70) #89

Merged
maximus merged 1 commit from issue-70-hooks-per-domain into main 2026-04-14 18:40:17 +00:00
Owner

Fixes #70

Refonte du hook monolithique useReports en hooks par domaine alimentés par une période partagée via query string.

Changements

useReportsPeriod (nouveau, partagé)

  • Lit/écrit ?from=YYYY-MM-DD&to=YYYY-MM-DD&period=... via useSearchParams
  • Défaut : année civile en cours (1er janvier → 31 décembre)
  • Pure resolver resolveReportsPeriod() exporté pour tests unitaires
  • Bookmarkable (copier-coller URL → même état)

Hooks par domaine (stubs)

  • useHighlights — reducer vide prêt pour reportService.getHighlights (#71)
  • useTrends — déjà câblé sur getMonthlyTrends + getCategoryOverTime, gère subView global/byCategory (#72 enrichira)
  • useCompare — gère le mode MoM/YoY/budget (#73)
  • useCategoryZoom — gère zoomedCategoryId + rollupChildren (#74)
  • Tous consomment useReportsPeriod

Legacy useReports

  • Marqué @deprecated (supprimé en #76)
  • Recâblé sur useReportsPeriod : plus d\état local pour period/customDateFrom/customDateTo
  • Shape retournée inchangée → ReportsPage existant ne régresse pas

Tests

  • npm run build
  • cargo check
  • npm test 37 tests (7 nouveaux pour resolveReportsPeriod : défauts, bookmarks, inputs invalides, presets, all)
Fixes #70 Refonte du hook monolithique `useReports` en hooks par domaine alimentés par une période partagée via query string. ## Changements ### `useReportsPeriod` (nouveau, partagé) - Lit/écrit `?from=YYYY-MM-DD&to=YYYY-MM-DD&period=...` via `useSearchParams` - Défaut : année civile en cours (1er janvier → 31 décembre) - Pure resolver `resolveReportsPeriod()` exporté pour tests unitaires - Bookmarkable (copier-coller URL → même état) ### Hooks par domaine (stubs) - `useHighlights` — reducer vide prêt pour `reportService.getHighlights` (#71) - `useTrends` — déjà câblé sur `getMonthlyTrends` + `getCategoryOverTime`, gère `subView` global/byCategory (#72 enrichira) - `useCompare` — gère le mode MoM/YoY/budget (#73) - `useCategoryZoom` — gère `zoomedCategoryId` + `rollupChildren` (#74) - Tous consomment `useReportsPeriod` ### Legacy `useReports` - Marqué `@deprecated` (supprimé en #76) - Recâblé sur `useReportsPeriod` : plus d\état local pour `period/customDateFrom/customDateTo` - Shape retournée inchangée → `ReportsPage` existant ne régresse pas ## Tests - `npm run build` ✅ - `cargo check` ✅ - `npm test` ✅ 37 tests (7 nouveaux pour `resolveReportsPeriod` : défauts, bookmarks, inputs invalides, presets, `all`)
maximus added 1 commit 2026-04-14 18:37:55 +00:00
refactor: split useReports into per-domain hooks + URL-bookmarked period (#70)
All checks were successful
PR Check / rust (push) Successful in 24m38s
PR Check / frontend (push) Successful in 2m22s
PR Check / rust (pull_request) Successful in 24m56s
PR Check / frontend (pull_request) Successful in 2m31s
6a6a196467
- New useReportsPeriod hook reads/writes period via ?from=&to=&period= URL params,
  default civil year, pure resolver exported for tests
- New per-domain hooks: useHighlights, useTrends, useCompare, useCategoryZoom
  (stubs wired to useReportsPeriod, to be fleshed out in #71-#74)
- Rewire legacy useReports to consume useReportsPeriod; keep backward-compat
  state shape (period/customDateFrom/customDateTo) so /reports tabs keep working
- Mark useReports @deprecated pending removal in #76
- Tests: 7 new cases covering resolveReportsPeriod defaults, bookmarks,
  invalid inputs, preset resolution

Fixes #70

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

Review — APPROVE

Verdict: APPROVE

Résumé : Refonte ciblée et non régressive. Le hook legacy reste fonctionnel grâce à un shim de shape, et les nouveaux hooks sont tous alimentés par useReportsPeriod partagé.

Sécurité

  • Aucun secret
  • Validation stricte des inputs URL (regex ISO ^\d{4}-\d{2}-\d{2}$, whitelist des périodes) — pas d injection dans les params
  • Pas de XSS (pas de rendu de chaîne utilisateur)

Correctness

  • Défaut civil year validé par test
  • Bookmarkable (from/to dans URL, replace mode → pas de pollution historique)
  • resolveReportsPeriod pure et testable (7 tests) — évite d avoir à mocker react-router
  • useReports legacy shim : state.period, state.customDateFrom, state.customDateTo réinjectés depuis useReportsPeriod → ReportsPage existant marche sans modif
  • Race condition protection via fetchIdRef préservée dans tous les nouveaux hooks

Qualité

  • npm run build
  • npm test 37/37
  • cargo check
  • Comment @deprecated sur useReports documente la sortie planifiée en #76

Suggestions non-bloquantes

  • Les stubs useHighlights/useCompare/useCategoryZoom seront complétés dans #71/#73/#74 (intentionnel selon la spec)
  • setPeriod(custom) sans from/to existants peut créer une période vide — #71 qui expose un PeriodSelector sur le hub devra s en assurer (pas bloquant pour #70)

Ready to merge.

## Review — APPROVE **Verdict**: APPROVE **Résumé** : Refonte ciblée et non régressive. Le hook legacy reste fonctionnel grâce à un shim de shape, et les nouveaux hooks sont tous alimentés par `useReportsPeriod` partagé. ### Sécurité ✅ - Aucun secret - Validation stricte des inputs URL (regex ISO `^\d{4}-\d{2}-\d{2}$`, whitelist des périodes) — pas d injection dans les params - Pas de XSS (pas de rendu de chaîne utilisateur) ### Correctness ✅ - Défaut civil year validé par test - Bookmarkable (from/to dans URL, replace mode → pas de pollution historique) - `resolveReportsPeriod` pure et testable (7 tests) — évite d avoir à mocker react-router - `useReports` legacy shim : `state.period`, `state.customDateFrom`, `state.customDateTo` réinjectés depuis `useReportsPeriod` → ReportsPage existant marche sans modif - Race condition protection via `fetchIdRef` préservée dans tous les nouveaux hooks ### Qualité ✅ - `npm run build` ✅ - `npm test` ✅ 37/37 - `cargo check` ✅ - Comment `@deprecated` sur `useReports` documente la sortie planifiée en #76 ### Suggestions non-bloquantes - Les stubs `useHighlights`/`useCompare`/`useCategoryZoom` seront complétés dans #71/#73/#74 (intentionnel selon la spec) - `setPeriod(custom)` sans from/to existants peut créer une période vide — #71 qui expose un PeriodSelector sur le hub devra s en assurer (pas bloquant pour #70) Ready to merge.
maximus merged commit a26d642b1b into main 2026-04-14 18:40:17 +00:00
maximus deleted branch issue-70-hooks-per-domain 2026-04-14 18:40:17 +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#89
No description provided.