Backend: - Add game_metadata to create_game() and quick_create_game() endpoints - Fetch team display info (lname, sname, abbrev, color, thumbnail) from SBA API at game creation time and store in DB - Populate GameState with team display fields from game_metadata - Fix submit_team_lineup to cache lineup in state_manager after DB write so auto-start correctly detects both teams ready Frontend: - Read team colors/names/thumbnails from gameState instead of useState - Remove useState approach that failed across SSR navigation - Fix create.vue redirect from legacy /games/lineup/[id] to /games/[id] - Update game.vue header to show team names from gameState Docs: - Update CLAUDE.md to note dev mode has broken auth, always use prod Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
224 lines
4.0 KiB
TypeScript
224 lines
4.0 KiB
TypeScript
/**
|
|
* REST API Types
|
|
*
|
|
* TypeScript definitions for HTTP API requests and responses.
|
|
* These complement the WebSocket events for non-real-time operations.
|
|
*/
|
|
|
|
import type { GameListItem, CreateGameRequest, CreateGameResponse } from './game'
|
|
|
|
/**
|
|
* API error response
|
|
*/
|
|
export interface ApiError {
|
|
message: string
|
|
code?: string
|
|
field?: string
|
|
errors?: Array<{
|
|
loc: string[]
|
|
msg: string
|
|
type: string
|
|
}>
|
|
}
|
|
|
|
/**
|
|
* Paginated response wrapper
|
|
*/
|
|
export interface PaginatedResponse<T> {
|
|
items: T[]
|
|
total: number
|
|
page: number
|
|
per_page: number
|
|
has_next: boolean
|
|
has_prev: boolean
|
|
}
|
|
|
|
/**
|
|
* Game filters for list queries
|
|
*/
|
|
export interface GameFilters {
|
|
status?: 'pending' | 'active' | 'completed'
|
|
league_id?: 'sba' | 'pd'
|
|
team_id?: number
|
|
date_from?: string
|
|
date_to?: string
|
|
page?: number
|
|
per_page?: number
|
|
}
|
|
|
|
/**
|
|
* Discord OAuth callback response
|
|
*/
|
|
export interface DiscordAuthResponse {
|
|
access_token: string
|
|
refresh_token: string
|
|
expires_in: number
|
|
user: DiscordUser
|
|
}
|
|
|
|
/**
|
|
* Discord user data
|
|
*/
|
|
export interface DiscordUser {
|
|
id: string // Discord snowflake ID (gmid)
|
|
username: string
|
|
discriminator: string
|
|
avatar: string | null
|
|
email?: string
|
|
}
|
|
|
|
/**
|
|
* JWT token payload
|
|
*/
|
|
export interface JwtPayload {
|
|
user_id: string
|
|
exp: number
|
|
iat: number
|
|
}
|
|
|
|
/**
|
|
* Team data (from league API)
|
|
*/
|
|
export interface Team {
|
|
id: number
|
|
name: string
|
|
owner_id: string
|
|
league_id: 'sba' | 'pd'
|
|
}
|
|
|
|
/**
|
|
* SBA Team data (from /api/teams endpoint)
|
|
*/
|
|
export interface SbaTeam {
|
|
id: number
|
|
abbrev: string
|
|
sname: string // Short name (e.g., "Geese")
|
|
lname: string // Long name (e.g., "Everett Geese")
|
|
color: string // Hex color code
|
|
thumbnail: string | null // Team logo URL
|
|
manager_legacy: string
|
|
gmid: string | null
|
|
gmid2: string | null
|
|
division: {
|
|
id: number
|
|
division_name: string
|
|
division_abbrev: string
|
|
league_name: string
|
|
league_abbrev: string
|
|
season: number
|
|
}
|
|
}
|
|
|
|
/**
|
|
* User's teams response
|
|
*/
|
|
export interface UserTeamsResponse {
|
|
teams: Team[]
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Endpoint Types
|
|
// ============================================================================
|
|
|
|
/**
|
|
* POST /api/games
|
|
*/
|
|
export type CreateGameRequestData = CreateGameRequest
|
|
export type CreateGameResponseData = CreateGameResponse
|
|
|
|
/**
|
|
* GET /api/games/:id
|
|
*/
|
|
export interface GetGameResponse {
|
|
game: GameListItem
|
|
}
|
|
|
|
/**
|
|
* GET /api/games/active
|
|
*/
|
|
export type GetActiveGamesResponse = PaginatedResponse<GameListItem>
|
|
|
|
/**
|
|
* GET /api/games/completed
|
|
*/
|
|
export type GetCompletedGamesResponse = PaginatedResponse<GameListItem>
|
|
|
|
/**
|
|
* GET /api/games/:id/history
|
|
*/
|
|
export interface PlayHistoryItem {
|
|
play_number: number
|
|
inning: number
|
|
half: 'top' | 'bottom'
|
|
outs_before: number
|
|
batter_id: number
|
|
pitcher_id: number
|
|
result_description: string
|
|
runs_scored: number
|
|
outs_recorded: number
|
|
created_at: string
|
|
}
|
|
|
|
export interface GetPlayHistoryResponse {
|
|
plays: PlayHistoryItem[]
|
|
total: number
|
|
}
|
|
|
|
/**
|
|
* DELETE /api/games/:id
|
|
*/
|
|
export interface DeleteGameResponse {
|
|
message: string
|
|
game_id: string
|
|
}
|
|
|
|
/**
|
|
* POST /api/auth/discord/callback
|
|
*/
|
|
export type DiscordCallbackRequest = {
|
|
code: string
|
|
state: string
|
|
}
|
|
export type DiscordCallbackResponse = DiscordAuthResponse
|
|
|
|
/**
|
|
* GET /api/auth/me
|
|
*/
|
|
export interface GetCurrentUserResponse {
|
|
user: DiscordUser
|
|
teams: Team[]
|
|
}
|
|
|
|
/**
|
|
* POST /api/auth/refresh
|
|
*/
|
|
export interface RefreshTokenRequest {
|
|
refresh_token: string
|
|
}
|
|
|
|
export interface RefreshTokenResponse {
|
|
access_token: string
|
|
expires_in: number
|
|
}
|
|
|
|
/**
|
|
* POST /api/games/:id/lineups
|
|
*/
|
|
export interface LineupPlayerRequest {
|
|
player_id: number
|
|
position: string
|
|
batting_order: number | null // null for pitcher in DH lineup
|
|
}
|
|
|
|
export interface SubmitLineupsRequest {
|
|
home_lineup: LineupPlayerRequest[] // 9-10 players
|
|
away_lineup: LineupPlayerRequest[] // 9-10 players
|
|
}
|
|
|
|
export interface SubmitLineupsResponse {
|
|
game_id: string
|
|
message: string
|
|
home_lineup_count: number
|
|
away_lineup_count: number
|
|
}
|