Commit graph

10 commits

Author SHA1 Message Date
Chris Parsons
46f8552f60 Fix draft timer bugs: broadcasts, increments, reconnect sync, and overnight pause
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 2m39s
🚀 Deploy / ʦ🔍 Typecheck & Lint (pull_request) Successful in 1m24s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
- Broadcast timer-bank-updated after every pick so all connected clients
  immediately see the updated time bank (was only visible on next timer-pick-started)
- Capture pickMadeAt at route entry (before auth/DB overhead) and use Math.ceil
  so credited seconds always match the client countdown display
- Clear picksExpiresAt on every pick so _schedulePickForSeason starts fresh
- Hold schedulingInProgress lock for full timer callback to prevent the recovery
  interval from scheduling a duplicate timeout mid-pick
- Fix force-autopick route: call rescheduleTimer so the next team's clock
  starts immediately instead of waiting for the old timeout to fire naturally
- Fix draft.adjust-time-bank for on-clock teams: shift picksExpiresAt by the
  adjustment and reschedule, so the client countdown updates; block adjustments
  that would reduce the bank to zero
- Add timer-pick-started / timer-overnight-paused / timer-bank-updated socket
  events with full type definitions; replace dead timer-update event
- Fix draft-state-sync to include expiresAt for the active timer and
  isOvernightPause state so reconnecting clients see accurate countdown and
  pause banner immediately
- Fix room-closure countdown: capture client-side timestamp when draft completes
  so countdown runs even before the loader revalidates with draftCompletedAt
- Run countdown interval at 500ms with Math.ceil to prevent skipped seconds
- Add draft-started socket handler to transition pre-draft UI without a refresh
- Fix overnight pause: canPick only blocks on commissioner pause, not overnight
  pause (timer freezes but player can still pick early)
- Extract checkOvernightPause to server/overnight-pause-check.ts, breaking the
  timer↔socket circular import and ensuring the timezone cache is shared and
  evicted correctly across both callers
- Fix PostgreSQL varchar=uuid type mismatch in getTeamTimezone join

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 22:42:19 -07:00
Claude
f36480c828
Phase 1: Replace per-second timer tick with event-driven scheduler
Eliminates the setInterval(1s) + per-second DB write by storing picksExpiresAt
in draft_timers and using a targeted setTimeout per pick. Clients count down
locally from the expiresAt timestamp, removing server-pushed timer-update events.

Key changes:
- database/schema.ts: add picksExpiresAt and picksStartedAt to draft_timers
- server/timer.ts: full rewrite — schedulePickForSeason, rescheduleTimer,
  30s recovery interval instead of 1s tick, overnight-pause resume scheduling
- server/socket.ts: new timer-pick-started / timer-overnight-paused events,
  updated draft-state-sync to include expiresAt for reconnect recovery
- draft.make-pick / draft.force-manual-pick: compute actual remaining from
  picksExpiresAt at pick time; call rescheduleTimer after the autodraft chain
- useDraftSocketEvents: handle new timer events, restore countdown on reconnect
- $leagueId.draft.$seasonId: client-side countdown useEffect from expiresAt
- plans/zero-downtime-scaling.md: full 4-phase scaling plan for future reference

Resolves 2351 unit tests (all passing).

https://claude.ai/code/session_019k5J6Ty7uP5HxSx6CsbiBK
2026-06-03 03:04:46 +00:00
Chris Parsons
e3a7a1a9b1 Fix autodraft settings panel not reflecting auto-disable after pick
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 1m24s
🚀 Deploy / ʦ TypeScript (pull_request) Successful in 1m13s
🚀 Deploy / 🔍 Lint (pull_request) Successful in 45s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
When next_queue autodraft fires and turns itself off, two bugs prevented
the UI from behaving correctly:

1. After reconnect, useDraftAuthRecovery synced autodraftStatus (draft
   grid) but not userAutodraft (settings panel), leaving the settings
   badge stale until the next page load.

2. Toast notifications for autodraft auto-disable were unreliable: the
   condition checked prev.mode rather than why the server disabled it,
   causing the wrong toast for manual disables and queue-empty events.

Fix the reconnect sync by calling setUserAutodraft in the revalidation
effect alongside setAutodraftStatus. Fix the toast logic by adding a
reason field ("pick_complete" | "queue_empty") to the server's
autodraft-updated emit, so the client can show the right message without
guessing from local state. Also removes the now-unused userAutodraftRef.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 18:29:13 -07:00
Chris Parsons
190a6e1fe7
Add electric flash + fade animation for draft picks, fixes #381 (#407)
When a pick is made the picked player's row flashes teal (--electric)
then fades out over 750ms. Works correctly with the TanStack Virtual
list by keeping the row in filteredParticipants during the animation
via animatingOutParticipantIds, then removing it after 650ms.

Key design decisions:
- Animation state lives in AvailableParticipantsSection (internal
  useState + timers); the draft room passes a pickAnimationSignal
  {id, seq} rather than the Set, so memo only breaks on each pick,
  not on the 650ms cleanup
- displayDrafted freezes row content (badges, buttons) during the
  animation to prevent height shifts
- Per-ID independent timers via Map ref support rapid autodraft picks
  running concurrently without cancellation
- Timers are cleared on unmount in both the draft room and component
- prefers-reduced-motion: skips the color flash, plain opacity fade only
- Removes "Draft Grid" heading from DraftGridSection (visual cleanup)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 23:17:29 -07:00
Chris Parsons
5b03b22267
Add Brackt as a league-private meta-sport (#200) (#377)
Commissioners can add Brackt to any league. Each team drafts one manager
from their own league; at season end, that manager's final overall fantasy
ranking earns placement points. Resolution fires automatically when all
other sports finalize.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 20:31:44 -07:00
Chris Parsons
3611f5620e
Show "Syncing Draft State..." overlay during draft reconnection (#361)
* Show "Syncing Draft State..." overlay during draft reconnection

When a user reconnects to a draft room (socket reconnect, tab visibility
return, etc.), there was a gap between when the socket connected and when
the full draft state sync arrived. The ConnectionOverlay vanished instantly
on reconnect, showing potentially stale data.

Add an isSyncing flag that keeps the overlay visible with "Syncing Draft
State..." messaging until the actual data arrives via socket or HTTP
revalidation. A 5-second safety timeout prevents the overlay from getting
stuck.

Fixes #78

* Add team names utility tests
2026-04-30 20:33:00 -07:00
Chris Parsons
437ac2ce24
Add draft room closure after completion (#359)
* Add draft room closure: redirect to draft board 5 min after completion

* Fix lint: use nowForPauseCheck instead of Date.now() in room closure countdown

Fixes #253
2026-04-30 10:14:14 -07:00
Chris Parsons
380b0786ca
Mobile draft room improvements: watchlist, collapsible picks feed, autodraft controls (#355)
- Add watchlist feature: eye icon per participant, "Watched Only" filter, DB
  table + migration, toggle API route, socket sync on reconnect
- Make RecentPicksFeed collapsible on mobile participants tab (chevron toggle,
  defaults expanded)
- Add AutodraftSettings to mobile controls tab (was desktop-only)
- Pin Pause/Resume Draft and Exit Draft Room buttons to the bottom of the
  mobile controls tab

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 11:49:26 -07:00
Chris Parsons
dbc23f14ce
Add overnight pause for draft timers (#335)
* Add overnight pause feature for draft timers

Protects players from having their pick timer expire while asleep.
Admins configure a nightly window (league-wide or per-user timezone);
the timer freezes during that window while autodraft can still fire.

Fixes #66

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix TS error: guard getUserDisplayName against undefined user

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 22:31:52 -07:00
Chris Parsons
01dacbce27
Add Storybook stories for new components from staged changes (#321) 2026-04-23 22:09:25 -07:00