Files
F-r-ldraledigplannerare/frontend_polish.md
T
2026-06-14 09:58:30 +02:00

72 lines
5.2 KiB
Markdown

# Junior Developer — Frontend Polish TODO
**Owner:** Junior developer
**Status:** Ready to implement
**Goal:** Clean up the rough edges left after the MVP happy path — surface the data we already fetch, fix placeholder math, kill the duplicate heading, drop the `any` casts, and backfill tests for the new code.
**Do this first**, then move on to `frontend_mvp_complete.md`.
> Keep `npx tsc --noEmit`, `npm run lint`, and `npm test` green after every task. Don't redesign anything — this is tidy-up, not new features. CSS is still out of scope (MVP can look plain).
---
## P1 — Show the richer FK breakdown on the overview
**Problem:** The scraper fetches and persists a lot more than we display. The overview only shows three combined analytics numbers (Days Used / Days Left / Expiring at Age 4). The persisted `ParentalLeaveFetch` also has reserved vs. transferable days, dubbeldagar left, and the sjukpenning/lägstanivå tier split — all currently invisible.
**Do:**
- In `Dashboard.tsx`, use the existing `useParentalLeave(personalDataUuid, selectedChildId)` hook (both IDs come from `useWorkspace()` context) to load the latest snapshot for the selected child.
- Render a section showing: `reserved_days_left` / `reserved_days_total`, `transferable_days_left`, `dubbeldagar_left`, and the tier breakdown (`sjukpenning_left`, `lagsta_niva_left`). Reuse `DaysBreakdown` or a simple list — no new styling needed.
- Show data provenance + freshness per ARCHITECTURE §2.3: "Hämtad från Försäkringskassan {fetched_at}" vs "Manuellt angiven {fetched_at}" based on `source`.
- Handle the empty case gracefully: if there's no snapshot yet (new child, never fetched), show "Ingen data hämtad ännu — tryck på Hämta från Försäkringskassan." rather than blanks.
- After a successful FK fetch, refresh this too (the modal's `onDone` currently calls `refreshAnalytics()` — also call the parental-leave hook's `refresh()`).
**Acceptance:** After a fetch, the overview shows reserved/transferable/dubbeldagar/tier numbers and a "fetched on" line; before any fetch it shows a clear empty message.
---
## P2 — Remove the duplicate "Overview" heading
**Problem:** The dashboard renders `<h2>Overview</h2>` and then `OverviewMetrics` renders its *own* `<h2>Overview</h2>` (visible as two stacked "Overview" headings in the capture).
**Do:** Remove the redundant wrapper `<h2>` in `Dashboard.tsx` (keep the one inside `OverviewMetrics`, or pass a meaningful title). While you're there, make the section headings Swedish to match the rest of the app ("Översikt", "Planerade dagar", "Återstående till 4 års ålder") — small consistency win, the header already says "Översikt".
**Acceptance:** Exactly one "Översikt" heading for that section; headings are consistently Swedish.
---
## P3 — Fix the ProgressChart math (currently placeholder)
**Problem:** `Dashboard.tsx` feeds `ProgressChart` placeholder values: `currentWeeks={Math.floor(totalPlanned / 5)}` against a hardcoded `targetWeeks={50}`. That's not a real progress metric.
**Do:** Drive it from real data. The intent (per ARCHITECTURE) is progress toward the age-4 deadline. Use the analytics projection — e.g. days used (or planned) vs. total entitlement (`combinedDaysUsed` / `combinedDaysUsed + combinedDaysLeft`), or days elapsed vs. days until the child turns 4. Pick the interpretation that matches what `OverviewMetrics` already shows and label it honestly. Remove the hardcoded `50`.
**Acceptance:** The progress bar reflects a real ratio from analytics data; no hardcoded target weeks.
---
## P4 — Drop the `any` casts
**Problem:** `Dashboard.tsx` (and `Settings.tsx`) use `(d: any)` / `(period: any)` casts and an ESLint exception was added for pages. These hide type errors.
**Do:** Replace the casts with the real types from `@/types` (`PlannedLeaveDay`, `BreakPeriod`, etc.). Fix the field-name access to match the typed shape. Once the casts are gone, remove the temporary `@typescript-eslint/no-explicit-any` exception for `pages/` from `eslint.config.js` (keep the test-file exception if still needed).
**Acceptance:** No `any` in `pages/`; the pages-level ESLint exception is removed; `tsc`/lint green.
---
## P5 — Backfill tests for the new code
**Problem:** The happy-path round added real code with no new tests — the count stayed at 167 (`useScraperFetch`, `QRCodeModal`, the Dashboard empty-state add-child form, and the FK-fetch button are untested).
**Do:** Add focused tests following the existing patterns:
- `useScraperFetch` — start → poll transitions → done/error/cancel; timers mocked.
- `QRCodeModal` — renders QR when `awaiting_scan`, spinner on `authenticating`/`fetching`, result on `done`, message on `error`; close disabled while running.
- `Dashboard` — empty state (no children) shows the add-child form; populated state shows metrics + the FK button (disabled when no child selected).
**Acceptance:** New tests cover the above; full suite green and the test count goes up.
---
### Definition of done
Overview shows the full FK breakdown with a freshness line; one clean Swedish heading; a real progress metric; zero `any` in pages; new tests for the scraper hook/modal/dashboard. `tsc` + lint + tests all green.