import { h } from 'preact'; import { useEffect, useCallback } from 'preact/hooks'; import { useGameState } from '../hooks/useGameState'; import { useNavigation, useNewGameWizard } from '../hooks/useNavigation'; import { useModal, useValidationModal, useCompletionModal } from '../hooks/useModal'; import { GameService } from '../services/gameService'; import type { StandardGame, Game, EndlosGame } from '../types/game'; import { Layout } from './ui/Layout'; import GameListScreen from './screens/GameListScreen'; import NewGameScreen from './screens/NewGameScreen'; import GameDetailScreen from './screens/GameDetailScreen'; import Modal from './Modal'; import ValidationModal from './ValidationModal'; import GameCompletionModal from './GameCompletionModal'; import FullscreenToggle from './FullscreenToggle'; /** * Main App component for BSC Score */ export default function App() { // State management hooks const gameState = useGameState(); const navigation = useNavigation(); const newGameWizard = useNewGameWizard(); const modal = useModal(); const validationModal = useValidationModal(); const completionModal = useCompletionModal(); // Game lifecycle handlers const handleCreateGame = useCallback(async (gameData: any) => { try { const gameId = await gameState.addGame(gameData); newGameWizard.resetWizard(); navigation.showGameDetail(gameId); } catch (error) { console.error('Failed to create game:', error); validationModal.showValidation('Failed to create game. Please try again.'); } }, [gameState.addGame, newGameWizard.resetWizard, navigation.showGameDetail, validationModal.showValidation]); const handleUpdateScore = useCallback(async (player: number, change: number) => { if (!navigation.currentGameId) return; const game = gameState.getGameById(navigation.currentGameId); if (!game || game.status === 'completed') return; try { const updatedGame = GameService.updateGameScore(game as StandardGame, player, change); // Add undo state for standard games const gameWithHistory = { ...updatedGame, undoStack: [...(game.undoStack || []), game], updatedAt: new Date().toISOString(), }; await gameState.updateGame(navigation.currentGameId, gameWithHistory); // Check for completion if (GameService.isGameCompleted(gameWithHistory)) { completionModal.openCompletionModal(gameWithHistory); } } catch (error) { console.error('Failed to update score:', error); validationModal.showValidation('Failed to update score. Please try again.'); } }, [navigation.currentGameId, gameState.getGameById, gameState.updateGame, completionModal.openCompletionModal, validationModal.showValidation]); const handleUndo = useCallback(async () => { if (!navigation.currentGameId) return; const game = gameState.getGameById(navigation.currentGameId); if (!game?.undoStack?.length) return; try { const lastState = game.undoStack[game.undoStack.length - 1]; const newUndoStack = game.undoStack.slice(0, -1); await gameState.updateGame(navigation.currentGameId, { ...lastState, undoStack: newUndoStack, } as Game); } catch (error) { console.error('Failed to undo:', error); validationModal.showValidation('Failed to undo. Please try again.'); } }, [navigation.currentGameId, gameState.getGameById, gameState.updateGame, validationModal.showValidation]); const handleForfeit = async () => { if (!navigation.currentGameId) return; const game = gameState.getGameById(navigation.currentGameId); if (!game || !('players' in game)) return; try { const currentPlayerIndex = game.currentPlayer; if (currentPlayerIndex === null) return; const winner = game.players.find((_, idx) => idx !== currentPlayerIndex); const forfeitedGame = { ...game, status: 'completed' as const, winner: winner?.name, forfeitedBy: game.players[currentPlayerIndex].name, updatedAt: new Date().toISOString(), }; await gameState.updateGame(navigation.currentGameId, forfeitedGame); completionModal.openCompletionModal(forfeitedGame); } catch (error) { console.error('Failed to forfeit game:', error); validationModal.showValidation('Failed to forfeit game. Please try again.'); } }; const handleFinishGame = () => { if (!navigation.currentGameId) return; const game = gameState.getGameById(navigation.currentGameId); if (!game) return; completionModal.openCompletionModal(game); }; const handleConfirmCompletion = async () => { if (!navigation.currentGameId) return; try { await gameState.updateGame(navigation.currentGameId, { ...gameState.getGameById(navigation.currentGameId)!, status: 'completed', updatedAt: new Date().toISOString(), }); completionModal.closeCompletionModal(); } catch (error) { console.error('Failed to complete game:', error); validationModal.showValidation('Failed to complete game. Please try again.'); } }; const handleRematch = async () => { if (!navigation.currentGameId) return; const completedGame = gameState.getGameById(navigation.currentGameId); if (!completedGame) return; let gameData; if ('players' in completedGame) { gameData = { player1: completedGame.players[0]?.name || '', player2: completedGame.players[1]?.name || '', player3: completedGame.players[2]?.name || '', gameType: completedGame.gameType, raceTo: completedGame.raceTo.toString(), }; } else { gameData = { player1: completedGame.player1, player2: completedGame.player2, player3: completedGame.player3 || '', gameType: completedGame.gameType, raceTo: completedGame.raceTo.toString(), }; } try { const newGameId = await gameState.addGame(gameData); completionModal.closeCompletionModal(); navigation.showGameDetail(newGameId); } catch (error) { console.error('Failed to create rematch:', error); validationModal.showValidation('Failed to create rematch. Please try again.'); } }; const handleDeleteGame = (gameId: number) => { modal.openModal(gameId); }; const handleConfirmDelete = async () => { if (modal.modal.gameId) { try { await gameState.deleteGame(modal.modal.gameId); modal.closeModal(); navigation.showGameList(); } catch (error) { console.error('Failed to delete game:', error); validationModal.showValidation('Failed to delete game. Please try again.'); } } }; return ( {navigation.screen === 'game-list' && ( { newGameWizard.startWizard(); navigation.showNewGame(); }} /> )} {navigation.screen === 'new-game' && ( { newGameWizard.resetWizard(); navigation.showGameList(); }} onShowValidation={validationModal.showValidation} /> )} {navigation.screen === 'game-detail' && navigation.currentGameId && ( { try { await gameState.updateGame(navigation.currentGameId!, game); } catch (error) { console.error('Failed to update game:', error); validationModal.showValidation('Failed to update game. Please try again.'); } }} onUndo={handleUndo} onForfeit={handleForfeit} onBack={navigation.showGameList} /> )} ); }