Skip to content

feat(web,api): lobby signage, speaker view polish, force-stop reliability#6

Merged
jeroenniesen merged 1 commit into
mainfrom
feat/lobby-signage-and-polish
May 13, 2026
Merged

feat(web,api): lobby signage, speaker view polish, force-stop reliability#6
jeroenniesen merged 1 commit into
mainfrom
feat/lobby-signage-and-polish

Conversation

@jeroenniesen
Copy link
Copy Markdown
Contributor

Summary

  • Lobby as state-driven signageLobbyView rewritten: 1 live → big hero, 2-3 live → grid, 0 live + upcoming → next-up hero, 0 live + nothing → quiet "Programme has ended". No countdown digits on the public screen — only scheduled times and a progress bar (capped at 100% on overrun; host stops the session). Lobby info endpoint now returns the event window + per-room schedule items; auth handler + hub updated so the lobby code is recognised on the negotiate path and can resync any room in its event.
  • Speaker view polish — display state machine (idle / pre-roll / running / final / overrun), options via query params (chrome / contrast / progress / scale / margin), calm IdleState, ring/line progress modes, larger message overlay. Countdown gains scale / label / pulse props plus length-aware sizing so long "+HH:MM:SS" overruns no longer overflow.
  • Force-stop reliabilityuseEventRoomSnapshots retries the initial hub.start() once (covers the StrictMode double-mount race that left the dashboard hub permanently disconnected) and stopRoom waits up to 3s for reconnect before failing. EventDashboardPage.onForceStop goes through the shared hub.
  • Operator dashboard polish — a live room now trumps the configured event window in EventIdentity's status pill; stale nextItem whose start is in the past is dropped from the idle-upcoming tile view; linked programme-slot chip on schedule items.
  • Audit + theming — humanised audit verbs (lib/auditHumanise.ts); speaker display logic extracted to lib/speakerDisplay.ts with unit tests; .countdown-pulse-once one-shot emphasis replaces the continuous alarm; theme default --primary is near-white — colour is reserved for state.

Test plan

  • dotnet test (Docker-backed integration tests)
  • npm run build — passes locally (1927 modules, 0 errors)
  • Open /e/<code>/lobby on a wide display: 1 live → big hero card; stop the live session → switches to "Next" hero; verify progress bar caps at 100% on overrun, scheduled times stay correct in the event timezone
  • Open /r/<code>/speaker?chrome=minimal&progress=ring and verify the minimal speaker variant
  • On the operator dashboard, with a live room, click Force stop in the room slide-in panel — session ends without "Not connected" errors after a fresh tab load (StrictMode double-mount)
  • Verify "Ended 18h ago" status pill no longer appears in EventIdentity while a room is still live
  • Audit page renders humanised verb labels

🤖 Generated with Claude Code

…lity

Lobby (audience-facing signage)
- Rewrite LobbyView as a state-driven layout: 1 live → big hero card;
  2-3 live → grid; 0 live + upcoming → next-up hero; 0 live + nothing →
  quiet "Programme has ended" / "No sessions yet". No countdown digits
  on the public screen — only scheduled times and a capped progress
  bar (overrun caps at 100%; host stops the session). Up Next list is
  chronological, filters out items whose scheduled start has passed
  (between-session buffer is invisible to the audience). 24h wall
  clock + date in the event timezone, minutes only.
- PublicInfoController.GetLobby now returns the event window
  (start/end/timezone) plus the per-room schedule items needed to
  build the upcoming list. publicInfo.ts types updated to match.
- PublicAccessCodeAuthHandler accepts a `surface=lobby` query param
  and falls back to lobby-code lookup so the lobby's hub negotiate
  is authorised without a room context. TimerHub rehydrates the
  PublicAccessContext from connection claims and lets a lobby code
  resync any room in its own event.

Speaker view polish
- Adopt a speaker display state machine (idle / pre-roll / running /
  final / overrun) with options driven by query params (chrome,
  contrast, progress, scale, margin). Adds ring/line progress modes,
  a calm IdleState ("Standing by" / "Up next ..."), and a re-styled
  message overlay. Countdown gains `scale`, `label`, and `pulse` props
  so the parent can drive emphasis without the timer guessing.
- Message overlay: anchored at the bottom, full-bleed-ish width,
  large readable type for the back of the room.

Force-stop reliability
- useEventRoomSnapshots wraps the initial hub.start() in a single
  short-delay retry. SignalR's auto-reconnect only fires after an
  *established* connection drops; if the initial start races with
  StrictMode's double-mount the hub stays disconnected forever
  otherwise. `stopRoom` throws if the hub isn't connected and gives
  the dashboard a 3s grace window during reconnect.
- EventDashboardPage wires the new `onForceStop` on the room panel
  through the shared hub instead of opening a new connection.

Operator dashboard
- EventIdentity: a live room trumps the configured event window in
  the status pill, so the header no longer says "Ended 18h ago" while
  a room tile next to it is still live.
- RoomTile: drop `nextItem` from the idle-upcoming view when its
  scheduled start is in the past — fixes the "Up next 10:15 ·
  starting now" line on stale snapshots.
- ScheduleEditor: linked programme-slot label rendered as a chip on
  schedule items bound to a programme slot.

Audit + theming
- New `lib/auditHumanise.ts` maps verbs to human-readable labels for
  the audit log; AuditPage uses it. Speaker display options + state
  derivation extracted to `lib/speakerDisplay.ts` with unit tests.
- Countdown: per-variant sizing now scales by string length so long
  overrun strings ("+HH:MM:SS") no longer overflow the viewport or
  the compact tile.
- globals.css: `.countdown-pulse-once` one-shot emphasis (replaces
  the continuous alarm); new `.speaker-stage` background + high-
  contrast modifier. Theme default `--primary` is now near-white
  (`#f5f5f7`) — color is reserved for state, normal time is calm.

Verification
- dotnet build: clean (8 pre-existing dependency warnings).
- web build: clean, 1927 modules.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jeroenniesen jeroenniesen merged commit 8f3d5c1 into main May 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant