refactor: extract reusable library
- move reusable domain, data, state, ui code into src/lib - update host screens to consume new library exports - document architecture and configure path aliases - bump astro integration dependencies for compatibility Refs #30
This commit is contained in:
121
src/lib/state/useGameState.ts
Normal file
121
src/lib/state/useGameState.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { useState, useEffect, useCallback } from 'preact/hooks';
|
||||
import type { Game, NewGameData, GameFilter } from '@lib/domain/types';
|
||||
import { GameService } from '@lib/data/gameService';
|
||||
|
||||
export function useGameState() {
|
||||
const [games, setGames] = useState<Game[]>([]);
|
||||
const [filter, setFilter] = useState<GameFilter>('all');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Load games from IndexedDB on mount
|
||||
useEffect(() => {
|
||||
const loadGames = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const savedGames = await GameService.loadGames();
|
||||
setGames(savedGames);
|
||||
} catch (err) {
|
||||
console.error('Failed to load games:', err);
|
||||
setError('Failed to load games from storage');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadGames();
|
||||
}, []);
|
||||
|
||||
const addGame = useCallback(async (gameData: NewGameData): Promise<number> => {
|
||||
try {
|
||||
const newGame = GameService.createGame(gameData);
|
||||
await GameService.saveGame(newGame);
|
||||
setGames(prevGames => [newGame, ...prevGames]);
|
||||
return newGame.id;
|
||||
} catch (err) {
|
||||
console.error('Failed to add game:', err);
|
||||
setError('Failed to save new game');
|
||||
throw err;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const updateGame = useCallback(async (gameId: number, updatedGame: Game) => {
|
||||
try {
|
||||
await GameService.saveGame(updatedGame);
|
||||
setGames(prevGames =>
|
||||
prevGames.map(game => game.id === gameId ? updatedGame : game)
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('Failed to update game:', err);
|
||||
setError('Failed to save game changes');
|
||||
throw err;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const deleteGame = useCallback(async (gameId: number) => {
|
||||
try {
|
||||
await GameService.deleteGame(gameId);
|
||||
setGames(prevGames => prevGames.filter(game => game.id !== gameId));
|
||||
} catch (err) {
|
||||
console.error('Failed to delete game:', err);
|
||||
setError('Failed to delete game');
|
||||
throw err;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getGameById = useCallback((gameId: number): Game | undefined => {
|
||||
return games.find(game => game.id === gameId);
|
||||
}, [games]);
|
||||
|
||||
const getFilteredGames = useCallback(async (): Promise<Game[]> => {
|
||||
try {
|
||||
return await GameService.getGamesByFilter(filter);
|
||||
} catch (err) {
|
||||
console.error('Failed to get filtered games:', err);
|
||||
setError('Failed to load filtered games');
|
||||
return games.filter(game => {
|
||||
if (filter === 'active') return game.status === 'active';
|
||||
if (filter === 'completed') return game.status === 'completed';
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}, [filter, games]);
|
||||
|
||||
const getPlayerNameHistory = useCallback((): string[] => {
|
||||
// Extract player names from current games for immediate UI use
|
||||
const nameLastUsed: Record<string, number> = {};
|
||||
|
||||
games.forEach(game => {
|
||||
const timestamp = new Date(game.updatedAt).getTime();
|
||||
|
||||
if ('players' in game) {
|
||||
// EndlosGame
|
||||
game.players.forEach(player => {
|
||||
nameLastUsed[player.name] = Math.max(nameLastUsed[player.name] || 0, timestamp);
|
||||
});
|
||||
} else {
|
||||
// StandardGame
|
||||
if (game.player1) nameLastUsed[game.player1] = Math.max(nameLastUsed[game.player1] || 0, timestamp);
|
||||
if (game.player2) nameLastUsed[game.player2] = Math.max(nameLastUsed[game.player2] || 0, timestamp);
|
||||
if (game.player3) nameLastUsed[game.player3] = Math.max(nameLastUsed[game.player3] || 0, timestamp);
|
||||
}
|
||||
});
|
||||
|
||||
return [...new Set(Object.keys(nameLastUsed))].sort((a, b) => nameLastUsed[b] - nameLastUsed[a]);
|
||||
}, [games]);
|
||||
|
||||
return {
|
||||
games,
|
||||
filter,
|
||||
setFilter,
|
||||
loading,
|
||||
error,
|
||||
addGame,
|
||||
updateGame,
|
||||
deleteGame,
|
||||
getGameById,
|
||||
getFilteredGames,
|
||||
getPlayerNameHistory,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user