Commit graph

10 commits

Author SHA1 Message Date
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
5268e07365
Migrate auth from Clerk to BetterAuth (#354)
* Fix BetterAuth field mapping and add owner-prefixed team names

- Fix auth.server.ts: use camelCase Drizzle field names for BetterAuth
  adapter (was snake_case, causing user inserts to fail); add
  generateId: "uuid" so PostgreSQL UUID columns accept generated IDs
- Add prependOwnerToTeamName / stripOwnerFromTeamName utilities
- Invite join, league creation, and settings assign/remove all now
  manage the owner-prefix on team names atomically

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

* Complete BetterAuth migration: auth flows, rename, and cleanup

- Add /forgot-password and /reset-password pages (full password reset flow)
- Add 'Forgot password?' link on login page
- Fix register.tsx: add explicit window.location fallback after signUp
- Rename commissionerAuditLog.actorClerkId → actorUserId (migration 0084)
  and update all references in model, routes, components, and tests
- Rewrite docs/agents/auth.md to document BetterAuth (removes all Clerk refs)
- Update test fixtures and schema comments to remove Clerk ID references;
  use UUID-format IDs throughout test data
- Update docs/agents/domain-models.md ownerId description

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

* Fix BetterAuth ID generation, clean up review issues

- Set generateId: false so BetterAuth omits id from inserts; add
  $defaultFn(crypto.randomUUID) to accounts/sessions/verifications
  so Drizzle fills it in (fixes null id constraint violation on signup)
- Move renameTeam to static import; rename before removeTeamOwner so
  a failed rename leaves owner intact rather than leaving a stale prefix
- Clarify stripOwnerFromTeamName toTitleCase assumption in comment
- Annotate reset-password token fallback to explain loader guarantee

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 10:03:50 -07:00
Chris Parsons
2b680d7272
Replace isDraftable boolean with draftOn/draftOff date range (#263)
Fixes #262

* Replace isDraftable boolean with draftOn/draftOff date fields on sport seasons

Admins can now schedule when a sport season becomes available for drafting
by setting explicit open and close dates instead of a manual toggle.

https://claude.ai/code/session_01LHYgpyimF8v8odUB6kj8Qc

* Address code review feedback on draft window implementation

- sports-data-sync: use unambiguous past placeholder dates for synced seasons,
  with a comment explaining the intent
- sports-season model: remove redundant top-level lte/gte imports (callback
  form already supplies them)
- _journal.json: add missing trailing newline
- sports-season test: mock ~/database/schema instead of stubbing all drizzle
  builder functions, matching the established pattern in the codebase
- admin list: compute today once in component body instead of per-row

https://claude.ai/code/session_01LHYgpyimF8v8odUB6kj8Qc

* Fix: restore lte/gte imports removed in review cleanup

The relational query where-callback in this version of Drizzle does not
expose lte/gte as helper args, so they must be imported from drizzle-orm.
Removing them broke CI TypeScript.

https://claude.ai/code/session_01LHYgpyimF8v8odUB6kj8Qc

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-05 22:09:52 -04:00
Chris Parsons
e2b178221a
Add oxlint linting setup with zero errors (#194)
* Add oxlint and fix all lint errors

- Install oxlint, add .oxlintrc.json with rules for TypeScript/React
- Add npm run lint / lint:fix scripts
- Add Claude PostToolUse hook to run oxlint on every edited file
- Fix 101 errors: unused vars/imports, eqeqeq, prefer-const, no-new-array
- Fix no-array-index-key (use stable keys or suppress positional cases)
- Fix exhaustive-deps missing dependency in useEffect
- Promote exhaustive-deps and no-array-index-key to errors
- Fix Map.get() !== null bug in $leagueId.server.ts (should be !== undefined)

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

* Fix no-explicit-any warnings and upgrade tsconfig to ES2023

- Replace all `any` types with proper types or `unknown` across ~20 files
- Add typed socket payload interfaces in draft route and useDraftSocket
- Use any[] with eslint-disable for socket.io callbacks (legitimate escape hatch)
- Bump all tsconfigs from ES2022 → ES2023 to support toSorted/toReversed
- Fix cascading type errors uncovered by removing any: Map.get narrowing,
  participant relation types, ChartDataPoint, Partial<NewSeason> indexing
- Add ParticipantResultWithParticipant type to participant-result model
- Fix test fixtures to match updated interfaces (DraftCell, ParticipantResult)
- Fix duplicate getQPStandings import in sportsSeasonId.server.ts

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

* Promote no-explicit-any to error

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-21 09:44:05 -07:00
Chris Parsons
9ae00a8385
Add Zod validation and expand export/import for EV and results data (#14)
* Include participant EV/futures data in data sync export/import

The export now includes the full participantExpectedValues records
(placement probabilities, source, sourceOdds) alongside participants.
On import, EV records are upserted in merge mode and created fresh in
replace mode (cascade handles cleanup). Backward-compatible with older
exports that lack the participantExpectedValues field.

https://claude.ai/code/session_01TVzuuDR7jPtmihaXTrsX7B

* Address all data-sync code review findings

- Wrap importSportsDataFromJSON in a db.transaction() so any mid-import
  failure rolls back cleanly instead of leaving partial data
- Add zod validation of imported JSON before any DB writes, giving a
  clear error on malformed/incompatible files
- Fix N+1 queries: build participantIdMap during participant import so
  the EV and results sections resolve IDs from memory, not extra queries
- Fix merge mode silently skipping existing participants — now updates
  shortName, externalId, and expectedValue
- Add participantResults to export/import (was deleted in replace mode
  but never exported, so results were permanently lost)
- Restore calculatedAt timestamp on EV import instead of defaulting to
  now(); stored as ISO string in the export for portability
- Document that onDelete:cascade covers participantExpectedValues and
  participantResults when participants is deleted; remove the now-
  redundant explicit participantResults delete from replace mode
- Bump export version to 1.1; old v1.0 files still import cleanly since
  participantExpectedValues, participantResults, and calculatedAt are
  all optional in the zod schema
- Collapse all six DB fetches in exportSportsDataToJSON into one
  Promise.all for parallel execution
- Add countAllParticipants() and countAllParticipantEVs() model funcs
- Show Participants and EV Records counts on the dashboard stat cards
- Replace raw DOM form creation/submit in handleImport with useFetcher,
  giving proper loading state, no full-page reload, and type-safe data
- Remove dead export intent handler from the action function

https://claude.ai/code/session_01TVzuuDR7jPtmihaXTrsX7B

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 20:25:25 -08:00
Chris Parsons
3210ab265f
Change participant expectedValue from integer to decimal (#1)
* feat: sync odds-based EV to participants table for draft room ranking

When admin enters futures odds or manual probabilities, the calculated EV
is now synced from participantExpectedValues to participants.expectedValue.
This closes the gap where EVs were calculated but never reflected in the
draft room ranking. Also changes expectedValue from integer to decimal(10,2)
for better precision, and displays "—" for participants with no odds data.

https://claude.ai/code/session_01JWG2zg2EMzCn6RgEufPC1T

* fix: correct expectedValue type to string in participants route

Missed instance of `expectedValue: 0` (number) that failed typecheck
after schema change from integer to decimal.

https://claude.ai/code/session_01JWG2zg2EMzCn6RgEufPC1T

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 11:26:40 -08:00
Chris Parsons
0e68bd2037 feat: add bulk participant creation and expected value field 2025-10-15 21:21:33 -07:00
Chris Parsons
8c5a611b4b feat: add random team name generation and improve league exit flow 2025-10-14 22:45:24 -07:00
Chris Parsons
94586564e2 refactor: remove isRequired field from season sports and templates 2025-10-13 15:00:59 -07:00
Chris Parsons
37de6787bf feat: add admin routes and checkbox component for sports management 2025-10-12 21:54:49 -07:00