Commit graph

9 commits

Author SHA1 Message Date
Chris Parsons
ca2fd288ab
perf: fix draft room lag from excessive re-renders and listener leaks (#54)
Primary fix: setTeamTimers now bails out with `return prev` when the
value hasn't changed, preventing a full DraftRoom re-render on every
1-second timer tick (was 33% of profiler samples).

Memoization: wrap AvailableParticipantsSection, TeamsDraftedGrid,
QueueSection, SidebarRecentPicks, and DraftGridSection in React.memo
so timer ticks don't cascade into heavy components that don't use
timer state.

Stable refs: wrap nine action handlers in useCallback and extract two
inline arrow functions from props objects so memo() comparisons
actually bail out. Memoize the { numFlexPicks } object passed to
TeamsDraftedGrid.

socketVersion: expose an incrementing counter from useDraftSocket so
the socket handler effect re-registers on socket recreation.

Async cleanup: add abort flag + in-flight guard to the visibilitychange
JWT refresh handler to prevent concurrent executions and stale state
updates after unmount. Add abort flag to useDraftNotifications
permissions.query() to prevent dangling onchange if unmounted
mid-promise.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:18:47 -08:00
Chris Parsons
3343e7a405
fix: address code review issues from draft board scrolling and team creation changes (#35)
- DraftGrid: wrap header and rows in a single min-w-max container so
  column widths share a sizing context and can't desync
- Settings: wrap team + draft slot creation in a DB transaction so a
  slot insert failure can't leave orphaned teams with no slots
- Settings: replace Math.max(...spread) with reduce to avoid the JS
  argument limit (defensive, given the 6-16 team cap)
- Settings: remove now-unused createManyTeams import

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 10:01:27 -08:00
Chris Parsons
77e408cad8
Make draft room fully usable on mobile (#30)
- Add bottom nav bar (Lobby/Board/Roster/Controls) with 56px touch targets
- Add mobile card list view in AvailableParticipantsSection with 44px Draft/Queue buttons
- Add round labels and sticky header row to DraftGridSection grid
- Add mobile Sheet for commissioner actions in DraftGridSection (replaces right-click context menu)
- Use useMediaQuery to render a single layout tree, eliminating duplicate component
  instances (previously both desktop and mobile layouts were always in the DOM)
- Add compact header on mobile (text-lg vs text-3xl); hide commissioner buttons
  and Exit link in header on mobile — surfaced in Controls tab instead
- Add "On Clock" bar on mobile showing current team and timer during active draft
- Add "your turn" indicator dot on Lobby bottom nav tab
- Default mobile tab to "board" for commissioner-only viewers
- Fix sticky corner cell z-index in TeamsDraftedGrid (z-10 → z-20)
- Fix round column spacer in DraftGridSection header not being sticky-left
- Extract shared prop objects to eliminate copy-paste between layouts
- Extract getParticipantState() helper to deduplicate participant render logic
- Move MobileSheetData type and MOBILE_TABS array to module scope
- Remove unnecessary non-null assertions in DraftGridSection Sheet handlers

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 22:36:12 -08:00
Chris Parsons
ab3437cd73
Display team owner names instead of team names in draft UI (#24)
* Show manager username instead of team name on draft board

Both the read-only draft board and the active draft room now display
the manager's username (falling back to displayName if no username is
set, and to team name if the team is unassigned) in the column headers
of the draft grid.

https://claude.ai/code/session_01C97GauJaAB83NVWxdpNVh1

* Address code review: extract ownerMap helper, fix TeamsDraftedGrid

- Extract ownerMap building into app/lib/owner-map.ts to eliminate
  duplication across the two loaders
- Guard against null username AND displayName so the map only contains
  real string values
- Apply username display to TeamsDraftedGrid (the "Teams" tab in the
  active draft room), which was missed in the initial change

https://claude.ai/code/session_01C97GauJaAB83NVWxdpNVh1

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-22 16:56:07 -08:00
Chris Parsons
51cffe1762
Add commissioner time bank adjustment feature for draft (#22)
* Add commissioner time bank adjustment via right-click on draft board team headers

Commissioners can right-click any team header on the Draft Board tab to open
an "Adjust Time Bank..." dialog. The dialog supports adding or removing an
arbitrary amount of time in seconds, minutes, or hours. The change is applied
immediately to the database and broadcast to all clients via the existing
timer-update Socket.IO event so every participant sees the updated clock
in real time.

- New API route: POST /api/draft/adjust-time-bank (commissioner-only)
- DraftGridSection: wraps team headers in a ContextMenu for commissioners
- Draft room: dialog state, handler, and updated DraftGridSection props

https://claude.ai/code/session_013wxPKzLUCx3nC3LpxgjvQL

* Fix code review issues in commissioner time bank adjustment

- Wrap fetch in try/finally so isAdjustingTimeBank is always reset,
  even on network errors that cause fetch to throw
- Guard against totalSeconds rounding to 0 for tiny fractional inputs
- Reject API requests when the draft is not in 'draft' status (409)
- Set input min to 0.001 so the browser rejects zero in native validation

https://claude.ai/code/session_013wxPKzLUCx3nC3LpxgjvQL

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-22 16:16:51 -08:00
Chris Parsons
7a8ea60e77
Add draft clock UI, Fischer increment timer logic, and security fixes (#19)
- Add prominent clock badge to tab bar (lights up on your turn) with
  correct Fischer increment chess-clock model: bank starts at initialTime,
  += incrementTime after each pick, other teams' banks untouched
- Extract pure timer helpers to app/lib/draft-timer.ts and add 29 unit
  tests covering formatClockTime, calculateTimeAfterPick, getTimerColorClass,
  and full snake-draft lifecycle regression scenarios
- Fix make-pick.ts: add status !== 'draft' and draftPaused server guards
- Fix draft-utils.ts: replace (global as any).__socketIO with getSocketIO(),
  fix timeUsed to store actual timeRemaining at pick moment (not always 120),
  add null timer warning, move timer fetch before pick insert
- Fix draft.start.ts: batch timer inserts, guard against empty draftSlots
- Fix DraftGridSection: memoize currentTeamId, widen teamTimers type to
  Record<string, number | undefined>
- Fix duplicate animate-pulse (getTimerColorClass already includes it)
- Clamp negative seconds in formatClockTime to guard against timer drift

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 16:51:12 -08:00
Chris Parsons
41f3654956
Add commissioner replace pick and draft rollback features (#18)
Commissioners can now right-click any picked cell in the draft grid to
replace the drafted participant (available during and after draft) or
roll back the draft to that pick number (available during draft only).

Replace pick enforces sport eligibility with the replaced slot treated
as free, updates the pick in-place, and broadcasts a pick-replaced
socket event so all clients update in real time. Rollback deletes all
picks from the selected pick onward, resets the season pick number,
clears all timers, and creates a fresh timer for the team now on the
clock.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 22:47:29 -08:00
Chris Parsons
1584d34b89
Redesign to dark-mode-only with navy palette and accent colors (#13)
Removes light mode entirely in favour of a permanent dark theme with a
navy-tinted background and three signature accents (electric blue,
amber/gold, coral) exposed as CSS custom properties and Tailwind
utilities (bg-electric, text-amber-accent, text-coral-accent).

- Set class="dark" on <html> and apply Clerk dark base theme
- Rewrite app.css: single :root palette (oklch navy values), custom
  --electric / --amber-accent / --coral-accent variables, remove
  duplicate .dark block and light-mode bg-white/bg-gray-950 rule
- Install @clerk/themes for Clerk dark modal support
- Replace hardcoded Tailwind colors across 30+ files:
  - Draft grid cells: blue-50/blue-950 → electric/15, green-50/950 → emerald/10
  - Timer: green-600/yellow-600/red-600 → emerald-400/amber-accent/coral-accent
  - Status badges: blue-50/green-50/gray-50 → electric/emerald/muted variants
  - Success messages: green-500/15 text-green-700 dark:text-green-400 → emerald-500/15 text-emerald-400
  - Info cards: blue-50 dark:bg-blue-950 → electric/10
  - Warning cards: yellow-500 → amber-accent variants
  - Medal/placement badges: yellow-500/orange-600 → amber-accent/coral-accent
  - Movement indicators: green-600/red-600 → emerald-400/coral-accent
  - Connection dots: green-500/red-500 → emerald-500/coral-accent
- Remove dark:hidden/dark:block logo toggle in welcome.tsx (always dark)
- Update DraftGrid test assertions to match new class names

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 19:26:11 -08:00
Chris Parsons
2cd4096e70 feat: Implement draft room redesign with collapsible sidebar and tabbed content
- Added AvailableParticipantsSection for participant search and filtering.
- Created DraftGridSection for displaying the draft grid with team timers and context menu.
- Developed QueueSection for managing participant queue and autodraft settings.
- Introduced RecentPicksSection to show recent draft picks.
- Implemented TeamsDraftedGrid to visualize drafted participants by team and sport.
- Added collapsible UI components for better layout management.
- Established tabbed navigation for draft board, recent picks, and teams drafted.
- Enhanced responsiveness for mobile and desktop views.
- Updated styles for a cohesive design across components.
2025-10-25 03:23:41 -07:00