feat(shift): two-pane shift history — list + per-shift activity log, timeframe presets

Rework the shift screen into a master/detail view on /shift: the shift CONTROL
(open/close, drawer vouchers, X-report) on top, then a two-pane history below —
shift list on the LEFT, the selected shift's signed activity log on the RIGHT.

- Timeframe presets replace the bare from/to inputs: Yesterday / Last week /
  Last month / All / Custom (custom reveals the date pickers). Filters the shift
  list by start time.
- Activity log = every ledger event in the selected shift's [start, end] window
  (entries, exits, payments, vouchers, anomalies, the Z-report), rendered like the
  booth live feed (same EVENT_STYLE), with the shift's drawer reconciliation in the
  pane header.
- Scope unchanged + enforced SERVER-SIDE: an operator sees only their own shifts
  (no operator filter); an admin (shift:cash) sees all + the operator filter. The
  list auto-selects the newest shift.

API: /api/events gains an optional `until` (ISO) upper bound so a shift's window
can be fetched ([start,end]); fetchEvents passes it. Verified on live data: a
closed shift window returns just its 20 events out of 260.

Build+lint 12/12 (i18n parity). The same component also backs /setup/shifts.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-06-20 21:56:34 +02:00
parent f2734641b2
commit 1b54775b4d
6 changed files with 275 additions and 120 deletions
+8
View File
@@ -632,6 +632,14 @@ export const en: Catalog = {
allOperators: "All operators",
apply: "Apply",
clear: "Clear",
timeframe: "Timeframe",
preset_yesterday: "Yesterday",
preset_week: "Last week",
preset_month: "Last month",
preset_all: "All",
preset_custom: "Custom",
selectAShift: "Select a shift to see its activity log.",
noActivity: "No activity in this shift.",
drawerSection: "Drawer",
openingFloat: "Opening float",
cashTaken: "Cash taken",