feat(phase6): Add sounds, team chat, reactions, monitor, settings, and CSV import/export
Sound System: - Add soundStore with volume/mute persistence - Add useSound hook with Web Audio API fallback - Add SoundControl component for in-game volume adjustment - Play sounds for correct/incorrect, steal, timer, victory/defeat Team Chat: - Add TeamChat component with collapsible panel - Add team_message WebSocket event (team-only visibility) - Store up to 50 messages per session Emoji Reactions: - Add EmojiReactions bar with 8 emojis - Add ReactionOverlay with floating animations (Framer Motion) - Add rate limiting (1 reaction per 3 seconds) - Broadcast reactions to all players in room Admin Monitor: - Add Monitor page showing active rooms from Redis - Display player counts, team composition, status - Add ability to close problematic rooms Admin Settings: - Add Settings page for game configuration - Configure points/times by difficulty, steal penalty, max players - Store config in JSON file with service helpers CSV Import/Export: - Add export endpoint with optional filters - Add import endpoint with validation and error reporting - Add UI buttons and import result modal in Questions page Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,23 @@
|
||||
import { create } from 'zustand'
|
||||
import type { GameRoom, Question, ChatMessage, Achievement } from '../types'
|
||||
|
||||
export interface Reaction {
|
||||
id: string
|
||||
player_name: string
|
||||
team: 'A' | 'B'
|
||||
emoji: string
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
export interface TeamMessage {
|
||||
player_name: string
|
||||
team: 'A' | 'B'
|
||||
message: string
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
const MAX_TEAM_MESSAGES = 50
|
||||
|
||||
interface GameState {
|
||||
// Room state
|
||||
room: GameRoom | null
|
||||
@@ -23,6 +40,11 @@ interface GameState {
|
||||
addMessage: (message: ChatMessage) => void
|
||||
clearMessages: () => void
|
||||
|
||||
// Team chat messages
|
||||
teamMessages: TeamMessage[]
|
||||
addTeamMessage: (message: TeamMessage) => void
|
||||
clearTeamMessages: () => void
|
||||
|
||||
// Achievements
|
||||
achievements: Achievement[]
|
||||
setAchievements: (achievements: Achievement[]) => void
|
||||
@@ -44,6 +66,12 @@ interface GameState {
|
||||
showStealPrompt: boolean
|
||||
setShowStealPrompt: (show: boolean) => void
|
||||
|
||||
// Reactions
|
||||
reactions: Reaction[]
|
||||
addReaction: (reaction: Omit<Reaction, 'id'>) => void
|
||||
removeReaction: (id: string) => void
|
||||
clearReactions: () => void
|
||||
|
||||
// Game result
|
||||
gameResult: {
|
||||
winner: 'A' | 'B' | null
|
||||
@@ -88,6 +116,13 @@ export const useGameStore = create<GameState>((set) => ({
|
||||
set((state) => ({ messages: [...state.messages, message].slice(-100) })),
|
||||
clearMessages: () => set({ messages: [] }),
|
||||
|
||||
teamMessages: [],
|
||||
addTeamMessage: (message) =>
|
||||
set((state) => ({
|
||||
teamMessages: [...state.teamMessages, message].slice(-MAX_TEAM_MESSAGES),
|
||||
})),
|
||||
clearTeamMessages: () => set({ teamMessages: [] }),
|
||||
|
||||
achievements: [],
|
||||
setAchievements: (achievements) => set({ achievements }),
|
||||
unlockAchievement: (id) =>
|
||||
@@ -105,6 +140,20 @@ export const useGameStore = create<GameState>((set) => ({
|
||||
showStealPrompt: false,
|
||||
setShowStealPrompt: (showStealPrompt) => set({ showStealPrompt }),
|
||||
|
||||
reactions: [],
|
||||
addReaction: (reaction) =>
|
||||
set((state) => ({
|
||||
reactions: [
|
||||
...state.reactions,
|
||||
{ ...reaction, id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}` },
|
||||
],
|
||||
})),
|
||||
removeReaction: (id) =>
|
||||
set((state) => ({
|
||||
reactions: state.reactions.filter((r) => r.id !== id),
|
||||
})),
|
||||
clearReactions: () => set({ reactions: [] }),
|
||||
|
||||
gameResult: null,
|
||||
setGameResult: (gameResult) => set({ gameResult }),
|
||||
|
||||
@@ -114,6 +163,8 @@ export const useGameStore = create<GameState>((set) => ({
|
||||
currentQuestion: null,
|
||||
timerEnd: null,
|
||||
messages: [],
|
||||
teamMessages: [],
|
||||
reactions: [],
|
||||
stats: initialStats,
|
||||
showStealPrompt: false,
|
||||
gameResult: null,
|
||||
|
||||
Reference in New Issue
Block a user