States, dialogs & parts
Everything the screens are built from, in one place: rejections as the user meets them, the four dialogs that guard the model, the day editor in both policies, the Quick Fill arithmetic, and the raw material (type, colour, badges) the other pages are made of.
Status, state and permission badges
Controls
Every rejection, as the user meets it
The four dialogs that guard the model
Restricted date
One confirmation, no reason field, stored per (timesheet, date). Three reasons share one dialog.
Amendment reason
Same component for Exported→Draft and Locked→Draft; one payload shape, so one path cannot skip it.
Export & its warnings
Reference, month and totals echoed back; a zero-entry month warns but is allowed.
Consequences elsewhere
Rejections that arrive mid-edit — the ones that would otherwise look like the app ignoring you.
Day editor — both policies, one record
Client without Clock Details
duration entered directlyClient with Clock Details
duration derived, never typedQuick Fill — the arithmetic behind D and H
Server-side derivation from the snapshot's working terms
the SPA never computes these| Snapshot working terms | Key | Stored | Displayed | What this case is for |
|---|
Empty, loading and transitional
No entries yet
March is empty
Press D on a working day to record a standard day, or open a date to enter a duration, clock times, a summary or overtime.
Loading
preferences load once at bootNothing is recomputed client-side, so a slow response shows a skeleton rather than a plausible-looking wrong total.
Banners in place of errors
A calendar cell, annotated
Anatomy
- Day number — the focus ring is the only selection affordance.
- Recorded duration for the regular side, always the persisted value, never a local guess.
- Day equivalent against this timesheet's standard day.
- Overtime as its own line with its own tag: never added into the number above.
- Summary preview, two lines max — the full text lives in the day editor.
- ✓ corner: a restricted-date confirmation is stored for this date; the flag underneath says why it was restricted.
Keyboard map
Phase 6 lives in one hook| Key | On a focused date (Draft) | Otherwise |
|---|---|---|
| D | Save one Standard Day, keep summary and overtime, advance focus | Inline “return to draft to edit”; no request sent |
| H | Save half a Standard Day (integer minutes: 450 → 225) | Same refusal |
| Enter | Open the day editor prefilled | Open read-only view |
| ↑ ↓ ← → | Move focus within the month — filler cells are never targets | — |
| Del | Clear the entry (history keeps the record) | Refused with the state name |
| Esc | Close the day editor; nothing written | — |