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>
94 lines
3.0 KiB
Vue
94 lines
3.0 KiB
Vue
<template>
|
|
<div class="min-h-screen flex flex-col bg-gray-900">
|
|
<!-- Minimal Header for Game View -->
|
|
<header class="bg-gray-800 text-white shadow-lg sticky top-0 z-50">
|
|
<div class="container mx-auto px-4 py-3">
|
|
<div class="flex items-center justify-between">
|
|
<!-- Back to Games -->
|
|
<NuxtLink
|
|
to="/"
|
|
class="flex items-center space-x-2 hover:text-gray-300 transition text-sm"
|
|
>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
class="h-5 w-5"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
>
|
|
<path
|
|
fill-rule="evenodd"
|
|
d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z"
|
|
clip-rule="evenodd"
|
|
/>
|
|
</svg>
|
|
<span>Back to Games</span>
|
|
</NuxtLink>
|
|
|
|
<!-- Matchup -->
|
|
<div class="text-sm font-bold text-center truncate max-w-[200px] sm:max-w-none sm:text-lg">
|
|
{{ matchupText }}
|
|
</div>
|
|
|
|
<!-- Connection Status -->
|
|
<div class="flex items-center space-x-3">
|
|
<!-- WebSocket Connection Indicator -->
|
|
<div
|
|
v-if="isConnected"
|
|
class="flex items-center space-x-2 text-green-400 text-sm"
|
|
>
|
|
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"/>
|
|
<span class="hidden sm:inline">Connected</span>
|
|
</div>
|
|
<div
|
|
v-else
|
|
class="flex items-center space-x-2 text-red-400 text-sm"
|
|
>
|
|
<div class="w-2 h-2 bg-red-400 rounded-full"/>
|
|
<span class="hidden sm:inline">Disconnected</span>
|
|
</div>
|
|
|
|
<!-- User -->
|
|
<div class="text-sm text-gray-400 hidden md:block">
|
|
{{ authStore.currentUser?.username }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Game Content (Full Width, No Container) -->
|
|
<main class="flex-1">
|
|
<slot />
|
|
</main>
|
|
|
|
<!-- Modals/Toasts Container -->
|
|
<div id="modal-container" class="relative z-50"/>
|
|
<div id="toast-container" class="fixed top-20 right-4 z-50 space-y-2"/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useAuthStore } from '~/store/auth'
|
|
import { useGameStore } from '~/store/game'
|
|
import { useWebSocket } from '~/composables/useWebSocket'
|
|
|
|
const authStore = useAuthStore()
|
|
const gameStore = useGameStore()
|
|
|
|
// WebSocket connection status - use composable directly as source of truth
|
|
const { isConnected } = useWebSocket()
|
|
|
|
// Team names for header (from gameState, stored in DB at game creation)
|
|
const matchupText = computed(() => {
|
|
const gs = gameStore.gameState
|
|
if (gs?.away_team_name && gs?.home_team_name) {
|
|
return `${gs.away_team_name} @ ${gs.home_team_name}`
|
|
}
|
|
return 'SBA'
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Game layout specific styles */
|
|
</style>
|