feat(phase4): Complete frontend with themes, replay, and results
Visual Effects: - Add effects.css with neon glow, CRT scanlines, glitch, sparkles, RGB shift - Animations work with all 5 themes (DRRR, Retro, Minimal, RGB, Anime) Game Finished Handler: - Add gameResult state to gameStore (winner, scores, replay, achievements) - Handle game_finished WebSocket event in useSocket - Store achievements unlocked by all players Results Page: - Show winner with animation (or tie) - Display final scores with staggered animation - List achievements unlocked per player - Buttons for replay and new game Replay Player: - Fetch replay from API by code - Auto-playback with configurable speed (1x, 2x, 4x) - Play/Pause and timeline controls - Events sidebar for navigation - Animated event transitions Lobby Updates: - Load categories from API on mount - Display available categories with icons - Backend generates board (no hardcoded data) TypeScript Fixes: - Add vite-env.d.ts for import.meta.env types - Fix ringColor style issues - Remove unused imports Build verified: npm run build succeeds Phase 4 tasks completed: - F4.1: CSS effects for themes - F4.2: Results page with achievements - F4.3: Replay player - F4.4: game_finished handler - F4.5: Lobby API integration - F4.6: Build verification and fixes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import { useEffect, useRef, useCallback } from 'react'
|
||||
import { io, Socket } from 'socket.io-client'
|
||||
import { useGameStore } from '../stores/gameStore'
|
||||
import type { GameRoom, ChatMessage, AnswerResult } from '../types'
|
||||
import type { GameRoom, ChatMessage, AnswerResult, Achievement } from '../types'
|
||||
|
||||
const SOCKET_URL = import.meta.env.VITE_WS_URL || 'http://localhost:8000'
|
||||
|
||||
export function useSocket() {
|
||||
const socketRef = useRef<Socket | null>(null)
|
||||
const { setRoom, addMessage, setShowStealPrompt, setCurrentQuestion, setTimerEnd } =
|
||||
const { setRoom, addMessage, setShowStealPrompt, setCurrentQuestion, setTimerEnd, setGameResult } =
|
||||
useGameStore()
|
||||
|
||||
useEffect(() => {
|
||||
@@ -95,10 +95,34 @@ export function useSocket() {
|
||||
console.log(`${data.player_name} reacted with ${data.emoji}`)
|
||||
})
|
||||
|
||||
socket.on('game_finished', (data: {
|
||||
room: GameRoom
|
||||
winner: 'A' | 'B' | null
|
||||
final_scores: { A: number; B: number }
|
||||
replay_code: string | null
|
||||
achievements_unlocked: Array<{
|
||||
player_name: string
|
||||
team: 'A' | 'B'
|
||||
achievement: unknown
|
||||
}>
|
||||
}) => {
|
||||
setRoom(data.room)
|
||||
setGameResult({
|
||||
winner: data.winner,
|
||||
finalScores: data.final_scores,
|
||||
replayCode: data.replay_code,
|
||||
achievementsUnlocked: data.achievements_unlocked.map(a => ({
|
||||
player_name: a.player_name,
|
||||
team: a.team,
|
||||
achievement: a.achievement as Achievement
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
return () => {
|
||||
socket.disconnect()
|
||||
}
|
||||
}, [setRoom, addMessage, setShowStealPrompt, setCurrentQuestion, setTimerEnd])
|
||||
}, [setRoom, addMessage, setShowStealPrompt, setCurrentQuestion, setTimerEnd, setGameResult])
|
||||
|
||||
// Socket methods
|
||||
const createRoom = useCallback((playerName: string) => {
|
||||
|
||||
Reference in New Issue
Block a user