Complete implementation of pre-game setup flow allowing players to create games and submit lineups before gameplay starts. Backend Changes: - Extended games.py with create game, lineup submission, and game start endpoints - Added teams.py roster endpoint with season filtering - Enhanced SBA API client with player data fetching and caching - Comprehensive validation for lineup submission (position conflicts, DH rules) Frontend Changes: - Redesigned create.vue with improved team selection and game options - Enhanced index.vue with active/pending game filtering and navigation - Added lineup/[id].vue for interactive lineup builder with drag-and-drop - Implemented auth.client.ts plugin for client-side auth initialization - Added comprehensive TypeScript types for API contracts - Updated middleware for better auth handling Key Features: - Game creation with home/away team selection - Full lineup builder with position assignment and batting order - DH rule validation (pitcher can be excluded from batting order) - Season-based roster filtering (Season 3) - Auto-start game when both lineups submitted - Real-time game list updates Workflow: 1. Create game → select teams → set options 2. Submit home lineup → validate positions/order 3. Submit away lineup → validate positions/order 4. Game auto-starts → navigates to game page 5. WebSocket connection → loads game state Ready for Phase F4 - connecting gameplay UI to complete the at-bat loop. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
88 lines
2.4 KiB
Python
88 lines
2.4 KiB
Python
import logging
|
|
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from pydantic import BaseModel
|
|
|
|
from app.services.sba_api_client import sba_api_client
|
|
|
|
logger = logging.getLogger(f"{__name__}.teams")
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class TeamResponse(BaseModel):
|
|
"""Team information response"""
|
|
|
|
id: int
|
|
abbrev: str
|
|
sname: str
|
|
lname: str
|
|
color: str | None = None
|
|
manager_legacy: str | None = None
|
|
gmid: str | None = None
|
|
gmid2: str | None = None
|
|
division: dict | None = None
|
|
|
|
|
|
@router.get("/", response_model=list[TeamResponse])
|
|
async def get_teams(season: int = Query(..., description="Season number (e.g., 3)")):
|
|
"""
|
|
Get all active teams for a season from SBA API.
|
|
|
|
Args:
|
|
season: Season number to fetch teams for
|
|
|
|
Returns:
|
|
List of active teams (excludes IL teams)
|
|
"""
|
|
try:
|
|
logger.info(f"Fetching teams for season {season}")
|
|
teams = await sba_api_client.get_teams(season=season, active_only=True)
|
|
|
|
return [
|
|
TeamResponse(
|
|
id=team["id"],
|
|
abbrev=team["abbrev"],
|
|
sname=team["sname"],
|
|
lname=team["lname"],
|
|
color=team.get("color"),
|
|
manager_legacy=team.get("manager_legacy"),
|
|
gmid=team.get("gmid"),
|
|
gmid2=team.get("gmid2"),
|
|
division=team.get("division"),
|
|
)
|
|
for team in teams
|
|
]
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to fetch teams: {e}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail="Failed to fetch teams")
|
|
|
|
|
|
@router.get("/{team_id}/roster")
|
|
async def get_team_roster(
|
|
team_id: int,
|
|
season: int = Query(..., description="Season number (e.g., 3)"),
|
|
):
|
|
"""
|
|
Get roster for a specific team from SBA API.
|
|
|
|
Args:
|
|
team_id: Team ID
|
|
season: Season number to fetch roster for
|
|
|
|
Returns:
|
|
List of players on the team's roster
|
|
"""
|
|
try:
|
|
logger.info(f"Fetching roster for team {team_id}, season {season}")
|
|
roster = await sba_api_client.get_roster(team_id=team_id, season=season)
|
|
|
|
return {"count": len(roster), "players": roster}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to fetch roster for team {team_id}: {e}", exc_info=True)
|
|
raise HTTPException(
|
|
status_code=500, detail=f"Failed to fetch roster for team {team_id}"
|
|
)
|