Styling fix and scraper bug fix

This commit is contained in:
2026-06-14 18:39:55 +02:00
parent 6ed2a3ae0c
commit 566595984f
21 changed files with 2150 additions and 119 deletions
+82
View File
@@ -0,0 +1,82 @@
# TODO — Fix `GET /api/planned-days` 405 (planned-days router is incomplete)
**Status:** open · **Area:** backend · **Owner:** _unassigned_ · **Filed:** 2026-06-14
## Symptom
Loading the Dashboard and adding a day in the Calendar both log:
```
"GET /api/planned-days?child_id=3b9b6dad-... HTTP/1.1" 405 Method Not Allowed
```
Adding a day works (`POST /api/planned-days` → 201), but the follow-up refresh
(`GET /api/planned-days?child_id=…`) is rejected, so the calendar/dashboard never
show planned days.
## Root cause
`backend/app/routers/planned_days.py` defines `POST ""` but **no `GET ""`**. FastAPI
returns *405* (not 404) because the path exists for another verb. The list-by-child
endpoint was never finished — the `GET /range` handler (lines ~65–78) is a dead stub
(`pass` body, `= None` defaults on its `service`/`_current_user` deps) and `/range`
also collides with `GET /{planned_leave_day_id}`.
Same router has a second gap: `api.updatePlannedDay` issues `PUT /api/planned-days/{id}`
(used by Calendar edit, `frontend/src/pages/Calendar.tsx:99`), but there is **no PUT
handler** and no `PlanningService.update`. Editing an existing day will 405 once adding works.
## Fix
In `backend/app/services/planning_service.py`:
1. Add `list_by_child`:
```python
async def list_by_child(self, child_id: UUID) -> list[PlannedLeaveDay]:
return await self._repo.list(child_id=child_id)
```
(The SQLite `list()` already filters on `child_id` alone.)
2. Add `update(self, planned_leave_day_id: UUID, day_type: str | None, is_dubbeldag: bool | None) -> PlannedLeaveDay`
— load via `get_by_id` (raise `NotFoundError` if missing), apply provided fields, call `repo.update`.
In `backend/app/routers/planned_days.py`:
3. Add the list route **before** `GET /{planned_leave_day_id}`:
```python
@router.get("", response_model=list[PlannedLeaveDayResponse])
async def list_planned_days(
service: PlanningServiceDep,
_current_user: CurrentUserDep,
child_id: UUID = Query(...),
) -> list[PlannedLeaveDayResponse]:
return [_to_response(d) for d in await service.list_by_child(child_id)]
```
4. Delete the dead `GET /range` stub (lines ~65–78).
5. Add the `PUT /{planned_leave_day_id}` handler using the existing
`PlannedLeaveDayUpdate` model → `service.update(...)` → `_to_response`.
> Route ordering matters: declare `""`, `/workspace/...`, then `/{planned_leave_day_id}`
> last, so the UUID catch-all doesn't swallow the others.
## Verification
From `backend/`:
```bash
uv run ruff check . && uv run ruff format --check . && uv run pytest
```
Add tests:
- `GET /api/planned-days?child_id=…` → 200 with the seeded rows for that child.
- `PUT /api/planned-days/{id}` → 200, fields updated; unknown id → 404.
Manual: add a vacation day in the Calendar → `POST 201` then `GET 200` and the list
refreshes; edit an existing day → `PUT` succeeds.
After code changes: `graphify update .`
## Related
The 405 only blocks the *planned-days* list. The dashboard's empty **metrics /
parental-leave breakdown** is a separate snake_case↔camelCase issue —
see `DASHBOARD_EMPTY_DATA_TODO.md`.