Commit Graph

12 Commits

Author SHA1 Message Date
b25340644b refactor(nav): Today tab shortcut to week view; delete /today route
- Today nav link targets /week?week=<currentWeek>&day=<todayKey>
- Today tab active: route=/week AND ?day===todayKey() (not just pathname)
- Week tab active: route=/week AND today tab not active
- Root / redirect updated from /today to /week?week=…&day=…
- /today route hard-deleted (src/routes/today/ removed)
- +layout.svelte imports todayKey/currentWeekKey for link generation
2026-04-30 19:10:17 +02:00
4c2b220482 feat(week): day selection with URL-driven state
- weekKey and selectedDay driven by ?week=&?day= query params
- Bare /week canonicalizes via replaceState (adds week+day params)
- Chip clicks: replaceState (no history push, no scroll jump)
- Week prev/next: goto with history push (back/forward works)
- Default day when week changes: today if in week, else Monday
- Keyboard navigation: ArrowLeft/Right cycles through chips
- Selected chip scrolls into view on selection change
- DayDetail always rendered for selectedDay (not just today)
- detailCaps reactive on closedDaysMap — updates immediately after
  close/reopen/mark without extra load()
- Chips now wired: selected prop, onclick handler
- DayChip tabindex: 0 for selected chip, -1 for others (roving tabindex)
2026-04-30 19:08:11 +02:00
d0c1f41c13 refactor: extract DayDetail component; render today inside week view
- New DayDetail.svelte: self-contained day panel with full capability
  gating (canStartStop, canAddInterval, canEditEntries, canMarkKind,
  canCloseDay, canReopenDay)
- Closed-day state: banner + read-only entry list with 'Reopen day to
  edit' hint; mark-kind buttons still available
- Close Day button disabled (with tooltip) when running entry exists
- Timer only ticks when dayKey === todayKey() and entry is running;
  properly cleaned up on dayKey change and component destroy
- oninvalidate() callback: called after every mutation so parent
  (week view) can refetch and update the chip strip
- /today route: refactored to thin wrapper using DayDetail
- Week page: renders DayDetail below summary when today is in the
  displayed week; oninvalidate triggers full week reload
2026-04-30 19:06:55 +02:00
3e4e93a814 feat(week): add day strip with per-day progress bars and status
- New DayChip.svelte component: weekday label, date number, progress
  bar (worked/expected), kind badge (H/V/S), closed checkmark, today
  highlight, selected state, accessible role=tab/aria-selected
- Week page: replace days-grid with horizontal scroll-snap chip strip
- Per-day workedMs: uses closed_days.worked_ms when closed, else sums
  open entries for that day (so in-progress work shows immediately)
- dailyExpectedMs: evenly split hours_per_week across workdays; 0 for
  weekends (no progress bar rendered for non-workdays)
- Progress bar turns amber when worked > expected (overtime)
- weekEntries stored in state (was discarded after computing set);
  daysWithEntries now derived from weekEntries
2026-04-30 19:04:38 +02:00
6c4f78d101 chore(web): add Vitest; add dayCapabilities helper with full test coverage
- Install vitest + jsdom
- Add test/test:watch scripts to package.json
- Add test:web and test:all tasks to mise.toml
- Add dayCapabilities() to utils.ts — single source of truth for
  what actions are permitted per day (future/today/past, open/closed)
- Add DayCapabilities interface to utils.ts
- 11 unit tests: dayCapabilities (5 cases), weekDayKeys (3 cases),
  isWorkday (3 cases)
2026-04-30 19:03:04 +02:00
185bb0c6a9 revert: display closedWeek.delta_ms in closed-week banner 2026-04-30 18:17:19 +02:00
78c2c7c8a5 fix: show live delta in closed-week banner instead of stale frozen value
closedWeek.delta_ms is a snapshot taken at close time and goes stale
if entries are edited or days are re-closed afterward. The summary
rows above already use the live totalWorkedMs - expectedMs; the
closed-week banner now uses the same expression.
2026-04-30 18:12:34 +02:00
3fd1455704 fix: hide close-week button when a tracked day is still open
Fetch entries for the week alongside days/weeks in the week view.
canCloseWeek now mirrors the server rule: every past workday that
has at least one entry must have a closed_days record. Days with
no entries are still skipped (they count as 0h implicitly).
2026-04-30 18:10:44 +02:00
563784d5fb fix: show Close week button without requiring all workdays closed
The frontend was blocking week close until every workday had a
closed_days record, which no longer matches the backend's rules
(untracked days are implicitly 0h). Replace the all-workdays-closed
guard with a simple check: week has started (Monday ≤ today) and
is not already closed. The server returns a clear error if a day
with entries still needs closing.

Also fixes a pre-existing TS type narrowing error on currentSettings
and removes the now-unused .hint CSS rule.
2026-04-30 18:08:06 +02:00
9d6233b116 feat: add manual interval creation and inline entry editing
- Service: CreateInterval() validates same-day, end>start, day not closed
- Service: Update() now rejects edits on closed-day entries (ErrDayAlreadyClosed)
- Handler: POST /api/entries creates a completed interval with explicit times
- API client: entries.createInterval(startMs, endMs, note)
- Utils: parseTimeInput / toTimeInput helpers for HH:MM <-> unix ms
- Today page: '+ Add interval' form (time pickers + optional note)
- Today page: pencil button on each entry opens inline edit row (start/end/note)
- Tests: TestCreateInterval, TestCreateIntervalEndBeforeStart,
         TestCreateIntervalCrossesMidnight, TestUpdateRejectsClosedDay
2026-04-30 17:45:02 +02:00
4a328ad6cc feat(m5): PWA service worker, offline Dexie store, outbox, sync endpoints 2026-04-30 16:47:27 +02:00
df04d9d7a9 feat(m4): SvelteKit frontend - today, week, history, settings views 2026-04-30 16:45:00 +02:00