111 lines
8.8 KiB
Markdown
111 lines
8.8 KiB
Markdown
# Junior Developer — Frontend MVP Completion TODO
|
||
|
||
**Owner:** Junior developer
|
||
**Status:** Ready to implement (tackle **after** `frontend_polish.md`)
|
||
**Goal:** Close the gap between the bare happy path and the app described in `ARCHITECTURE.md` — a usable shell with navigation, a working settings page, calendar planning, the manual-data fallback, and partner planning.
|
||
|
||
> **Why this plan exists:** the current dashboard has no header nav, no logged-in user, no child indicator, no logout, and no reachable settings — so features that already exist in code (Calendar, Tips, Settings, manual entry) are stranded. The backend endpoints for all of this already exist; this is almost entirely **frontend wiring**.
|
||
>
|
||
> Work in tiers, top to bottom. **Tier 1 is the highest value** (it's what makes the app feel like an app). Keep `tsc`/lint/tests green per task. CSS stays optional — structure and function over looks.
|
||
|
||
---
|
||
|
||
## TIER 1 — App shell: navigation, identity, working settings
|
||
|
||
### T1.1 — Real header (user, current child + switcher, nav, logout)
|
||
|
||
**Problem:** `components/layout/Header.tsx` already accepts `onLogout` / `onWorkspaceSelect`, but pages only pass `{ title }`, so the nav is empty. There's no way to log out, switch pages, or see who/which child you're viewing.
|
||
|
||
**Do — extend `Header` and wire it via `Layout` on every page:**
|
||
- **Logged-in identity:** show the current parent's name. ⚠️ `GET /api/auth/context` does **not** currently return the parent's display name (only `personal_data_uuid`, `workspace_id`, `children`). Either show the email from `GET /api/auth/me`, or **ask the senior to add `name` to the `/auth/context` payload** (small, preferred). Don't hardcode.
|
||
- **Current child + switcher:** `useWorkspace()` exposes `children`, `selectedChildId`, `selectChild()`. Render a `<select>` of children; changing it calls `selectChild(id)`. Show the selected child's name in the header. (If only one child, a static label is fine.)
|
||
- **Nav links:** Översikt (`/`), Kalender (`/calendar`), Tips (`/tips`), Inställningar (`/settings`) using `react-router` `<Link>`/`NavLink`. These routes already exist in `App.tsx`.
|
||
- **Logout:** a "Logga ut" button → `useAuth().logout()` then `navigate('/auth', { replace: true })`.
|
||
- Apply the header consistently: pass the nav/user/logout props through `Layout` so every page gets the same shell (Dashboard, Calendar, Tips, Settings).
|
||
|
||
**Acceptance:** Every authenticated page shows a header with the parent's name, a child selector reflecting/affecting `selectedChildId`, working nav links to all four pages, and a logout button that returns you to `/auth`.
|
||
|
||
---
|
||
|
||
### T1.2 — Make Settings reachable and actually save
|
||
|
||
**Problem:** `pages/Settings.tsx` renders the right inputs but most saves are no-ops or broken. Notably `handleSaveVacationDays` sends `personalDataUuid: 'current-user'` (a hardcoded string, not a UUID); the **parent profile** (salary_type / employment_status) and **planning goal** have no save handlers at all; child birth/preschool date in settings doesn't persist. The page is also unreachable (fixed by T1.1 nav).
|
||
|
||
**Do — wire each section to its real endpoint** (all exist; use the IDs from `useWorkspace()` context — `personalDataUuid`, `workspace.id`, `selectedChildId`):
|
||
|
||
| Setting | Endpoint | Notes |
|
||
|---|---|---|
|
||
| Parent profile (salary_type, employment_status) | `PUT /api/settings/parent/{personal_data_uuid}` | Drives the salary-gated tips (§6). Add a save handler — currently local state only. |
|
||
| Planning goal (max_time / max_money / balanced) | `PUT /api/workspace/{workspace_id}` | Add a save handler. Note the value strings the backend expects (check `WorkspaceUpdate` schema) — the page currently defaults to `'balance'`, confirm it's `'balanced'`. |
|
||
| Vacation days / year | `POST /api/vacation-days` | **Fix the `'current-user'` bug** → pass the real `personalDataUuid`. |
|
||
| Child birth date + **preschool start date** | `PUT /api/settings/child/{child_id}` | Preschool date powers the studiedagar tip. |
|
||
| Break periods | `POST/PUT/DELETE /api/break-periods` | Mostly wired already — verify add/remove persist and reload. |
|
||
|
||
- Load current values into the form (don't always default to 25 vacation days / `'balance'` — read from the fetched workspace/parent/vacation data).
|
||
- Give each section its own save button + success/error message, and re-fetch after save so the UI reflects persisted state.
|
||
|
||
**Acceptance:** From Inställningar you can set salary type, employment status, planning goal, annual vacation days, and the child's birth/preschool dates; each persists (survives reload) and shows a success message. No `'current-user'` placeholder.
|
||
|
||
---
|
||
|
||
## TIER 2 — Planning & data entry
|
||
|
||
### T2.1 — Calendar: add / edit / delete planned days
|
||
|
||
**Problem:** `pages/Calendar.tsx` renders a month grid but day clicks do nothing (per the round-3 report). Planning days is the core of the app.
|
||
|
||
**Do:**
|
||
- Clicking a day opens a small day-planner (reuse/extend the existing inputs): choose **day type** (sjukpenning / lägstanivå / vacation), and for two-parent workspaces, which parent + whether it's a dubbeldag.
|
||
- Persist via `POST /api/planned-days`; allow delete via `DELETE /api/planned-days/{id}`; edit via the PUT route.
|
||
- **Validate against remaining days** before saving (ARCHITECTURE feature): don't let planned FP exceed `days_left` from the latest snapshot; surface the analytics/validation error (the backend has dubbeldagar validation — show its message).
|
||
- Refresh the calendar + the dashboard breakdown after changes.
|
||
|
||
**Acceptance:** You can add, edit, and delete planned days from the calendar; the day shows its type; over-planning is blocked with a clear message; the dashboard's "Planerade dagar" reflects changes.
|
||
|
||
---
|
||
|
||
### T2.2 — Manual data-entry fallback
|
||
|
||
**Problem:** ARCHITECTURE §2.3 mandates a manual-entry path that *always works* even if scraping is unavailable. The backend has it (`POST /api/parental-leave/manual`, `api.saveManualFetch`), but there's no UI — the only way to get data in is the scraper.
|
||
|
||
**Do:**
|
||
- Add a "Ange uppgifter manuellt" form (near the FK fetch button or in Settings) collecting the same fields the user sees on FK: `total_days`, `days_used`, reserved total/left, transferable left, dubbeldagar left, and the tier breakdown. Use the field bounds from the backend schema (`total_days` 0–480, `dubbeldagar_left` 0–60, etc.).
|
||
- Save via `api.saveManualFetch` (`source='manual'`), then refresh the overview. The provenance line from P1 will then show "Manuellt angiven …".
|
||
|
||
**Acceptance:** A user can enter their FK numbers by hand and see the overview populate, with no scraper involved.
|
||
|
||
---
|
||
|
||
## TIER 3 — Partner planning & tips (rounds it out)
|
||
|
||
### T3.1 — Add a partner (solo planning path)
|
||
|
||
**Problem:** The product premise is planning *with a partner*, but there's no UI to add a second parent. The backend supports the no-login "solo planning" path: `POST /api/workspace/{workspace_id}/parents` adds a placeholder parent profile (just a name).
|
||
|
||
**Do:**
|
||
- In Settings, add "Lägg till partner" → creates a placeholder `PersonalData` via that endpoint, then re-fetch context so the second parent appears.
|
||
- Let per-parent settings (T1.2) and calendar planning (T2.1) target either parent.
|
||
- **Optional / stretch:** collaborative planning via invitations (`POST /api/workspace/{id}/invitations`, `POST /api/invitations/redeem`) — list it but defer unless time allows.
|
||
|
||
**Acceptance:** A user can add a partner profile and plan/configure days for both parents in one workspace.
|
||
|
||
### T3.2 — Verify Tips end-to-end
|
||
|
||
**Problem:** `pages/Tips.tsx` + `TipCard` exist and the backend tips engine is implemented, but the page was unreachable.
|
||
|
||
**Do:** Now reachable via T1.1 nav — verify it loads tips for the selected workspace/child (`GET /api/tips/{workspace_id}`), renders severity badges, and that the salary-/goal-gated tips actually appear once T1.2 lets users set salary type and planning goal. Fix any contract mismatches you find.
|
||
|
||
**Acceptance:** Tips page shows real tips driven by the user's configured settings.
|
||
|
||
---
|
||
|
||
## Suggested order & notes
|
||
1. **T1.1 → T1.2** first: navigation + working settings unlock everything else and deliver the most visible improvement.
|
||
2. Then **T2.1 (calendar)** — the biggest single chunk; budget accordingly.
|
||
3. **T2.2 (manual fallback)** is small and satisfies an architectural must-have — good quick win.
|
||
4. **Tier 3** rounds out the partner story; invitations are optional.
|
||
|
||
**One backend dependency to flag to the senior:** the parent display name isn't in `GET /api/auth/context` (T1.1). Everything else uses endpoints that already exist — read each router's actual `@router` decorator and request/response schema before wiring, and don't invent paths (see the path-mismatch lesson from the last round).
|
||
|
||
**Out of scope:** real CSS/visual design, responsive/mobile, accessibility audit, real-time updates — separate passes once the functionality is complete.
|