* Fix custom chess-clock timer detection and save settings blocker
- Extract getInitialDraftSpeed() helper so both useState init and
resetSettingsFormState use the same logic; unrecognized presets
now produce a "custom:{bank}:{incr}" string instead of falling
back to "standard", so the custom section auto-expands correctly
(e.g. 8 hr bank + 30 min increment is no longer shown as Standard)
- resetSettingsFormState was not resetting draftSpeed at all; fixed
- Clear hasUnsavedSettingsChanges in the Form's onSubmit so the
useBlocker check is false at the moment the save navigation starts,
preventing the "Leave without saving?" dialog from firing on save
- Replace the cleared-on-success useEffect with one that re-marks
dirty when the action returns an error, so the warning reappears
after a failed save
https://claude.ai/code/session_01DgHNkvJXGizx41CE2tkVS1
* Address code review: single source of truth for presets, useEffect guard, tests
- Extract CHESS_CLOCK_PRESETS (pure data) into draft-timer.ts as the
canonical source of truth; DraftSpeedPicker.tsx now spreads those
values into CHESS_PRESETS rather than duplicating the numbers
- getInitialDraftSpeed moved to draft-timer.ts and rewritten to use
CHESS_CLOCK_PRESETS.find() — no more hardcoded bankSec/incrSec values
in three separate places
- parseDraftSpeed switch replaced with CHESS_CLOCK_PRESETS.find() and
an explicit fallback comment; eliminates the silent default-handles-
"standard" fragility called out in review
- useEffect that re-marks settings dirty now guards against non-settings
errors (draft-order, commissioner actions) which carry a `section`
field — previously any error actionData would spuriously set
hasUnsavedSettingsChanges=true
- Add parseDraftSpeed and getInitialDraftSpeed test suites to
draft-timer.test.ts, including parametrised preset coverage via
it.each(CHESS_CLOCK_PRESETS)
https://claude.ai/code/session_01DgHNkvJXGizx41CE2tkVS1
* Fix lint: use !== null/undefined instead of != null
oxlint enforces eqeqeq; the null check in getInitialDraftSpeed used
!= which triggered two errors.
https://claude.ai/code/session_01DgHNkvJXGizx41CE2tkVS1
---------
Co-authored-by: Claude <noreply@anthropic.com>
- 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>