strat-gameplay-webapp/frontend-sba/components/CLAUDE.md
Cal Corum cbdd8cf903 CLAUDE: Fix critical game engine issues and refactor CLAUDE.md docs
Critical fixes in game_engine.py:
- Fix silent error swallowing in _batch_save_inning_rolls (re-raise)
- Add per-game asyncio.Lock for race condition prevention
- Add _cleanup_game_resources() for memory leak prevention
- All 739 tests passing

Documentation refactoring:
- Created CODE_REVIEW_GAME_ENGINE.md documenting 24 identified issues
- Trimmed backend/app/core/CLAUDE.md from 1371 to 143 lines
- Trimmed frontend-sba/CLAUDE.md from 696 to 110 lines
- Created focused subdirectory CLAUDE.md files:
  - frontend-sba/components/CLAUDE.md (105 lines)
  - frontend-sba/composables/CLAUDE.md (79 lines)
  - frontend-sba/store/CLAUDE.md (116 lines)
  - frontend-sba/types/CLAUDE.md (95 lines)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 16:05:26 -06:00

105 lines
3.1 KiB
Markdown

# Components Directory
Vue 3 components organized by feature domain. All use `<script setup lang="ts">` with Composition API.
## Directory Structure
### Game/ - Core Game Display
| Component | Purpose | Key Props |
|-----------|---------|-----------|
| `ScoreBoard.vue` | Sticky header with inning/score/count | gameState |
| `GameBoard.vue` | Baseball diamond with runners | gameState |
| `CurrentSituation.vue` | Pitcher vs Batter cards | currentPitcher, currentBatter |
| `PlayByPlay.vue` | Animated play history feed | plays |
**Data Pattern**: These receive `LineupPlayerState` from gameStore, then use `findPlayerInLineup()` to get full player data (name, headshot).
### Decisions/ - Strategic Decision Input
| Component | Purpose | Emits |
|-----------|---------|-------|
| `DecisionPanel.vue` | Container for decision workflow | - |
| `DefensiveSetup.vue` | Infield/outfield positioning | submit |
| `OffensiveApproach.vue` | Batting action selection | submit |
| `StolenBaseInputs.vue` | Per-runner steal attempts | submit |
**Data Pattern**: Read `currentDecisionPrompt` from store, emit decisions to parent which calls `useGameActions`.
### Substitutions/ - Player Replacement
| Component | Purpose | Emits |
|-----------|---------|-------|
| `SubstitutionPanel.vue` | Main substitution container | close |
| `PinchHitterSelector.vue` | Replace batter | substitute |
| `PitchingChangeSelector.vue` | Replace pitcher | substitute |
| `DefensiveReplacementSelector.vue` | Position switch | substitute |
**Data Pattern**: Filter `homeLineup`/`awayLineup` for active vs bench players.
### UI/ - Reusable Primitives
| Component | Purpose |
|-----------|---------|
| `ActionButton.vue` | Styled action button with loading state |
| `ButtonGroup.vue` | Radio-button style group selector |
| `ToggleSwitch.vue` | Boolean toggle with labels |
## Component Standards
```vue
<template>
<!-- Always wrap in single root -->
<div class="component-name">
<!-- Content -->
</div>
</template>
<script setup lang="ts">
// 1. Imports
import { computed } from 'vue'
import { useGameStore } from '~/store/game'
// 2. Props/Emits with TypeScript
interface Props {
gameId: string
}
const props = defineProps<Props>()
const emit = defineEmits<{
submit: [data: SomeType]
}>()
// 3. Store access
const gameStore = useGameStore()
// 4. Computed/methods
</script>
<style scoped>
/* Tailwind @apply preferred */
</style>
```
## Common Patterns
### Two-Step Player Lookup
```typescript
// GameState has LineupPlayerState (minimal)
const batterState = computed(() => gameStore.currentBatter)
// Get full Lineup with player details
const batterLineup = computed(() => {
if (!batterState.value) return null
return gameStore.findPlayerInLineup(batterState.value.lineup_id)
})
// Access player data
const batterName = computed(() => batterLineup.value?.player.name ?? 'Unknown')
const batterHeadshot = computed(() => batterLineup.value?.player.headshot)
```
### Conditional Rendering by Team
```typescript
const isMyTurn = computed(() => {
// Check if current user's team needs to act
return gameStore.battingTeamId === myTeamId
})
```