feat : add games database
This commit is contained in:
87
src/hooks/useGameDatabase.ts
Normal file
87
src/hooks/useGameDatabase.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { Game, GameEval } from "@/types/game";
|
||||
import { openDB, DBSchema, IDBPDatabase } from "idb";
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
interface GameDatabaseSchema extends DBSchema {
|
||||
games: {
|
||||
value: Game;
|
||||
key: number;
|
||||
};
|
||||
}
|
||||
|
||||
const gamesAtom = atom<Game[]>([]);
|
||||
const fetchGamesAtom = atom<boolean>(false);
|
||||
|
||||
export const useGameDatabase = (shouldFetchGames?: boolean) => {
|
||||
const [db, setDb] = useState<IDBPDatabase<GameDatabaseSchema> | null>(null);
|
||||
const [games, setGames] = useAtom(gamesAtom);
|
||||
const [fetchGames, setFetchGames] = useAtom(fetchGamesAtom);
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldFetchGames !== undefined) {
|
||||
setFetchGames(shouldFetchGames);
|
||||
}
|
||||
}, [shouldFetchGames, setFetchGames]);
|
||||
|
||||
useEffect(() => {
|
||||
const initDatabase = async () => {
|
||||
const db = await openDB<GameDatabaseSchema>("games", 1, {
|
||||
upgrade(db) {
|
||||
db.createObjectStore("games", { keyPath: "id", autoIncrement: true });
|
||||
},
|
||||
});
|
||||
setDb(db);
|
||||
};
|
||||
|
||||
initDatabase();
|
||||
}, []);
|
||||
|
||||
const loadGames = useCallback(async () => {
|
||||
if (db && fetchGames) {
|
||||
const games = await db.getAll("games");
|
||||
setGames(games);
|
||||
}
|
||||
}, [db, fetchGames, setGames]);
|
||||
|
||||
useEffect(() => {
|
||||
loadGames();
|
||||
}, [loadGames]);
|
||||
|
||||
const addGame = async (game: Omit<Game, "id">) => {
|
||||
if (!db) throw new Error("Database not initialized");
|
||||
|
||||
await db.add("games", game as Game);
|
||||
|
||||
loadGames();
|
||||
};
|
||||
|
||||
const setGameEval = async (gameId: number, evaluation: GameEval) => {
|
||||
if (!db) throw new Error("Database not initialized");
|
||||
|
||||
const game = await db.get("games", gameId);
|
||||
if (!game) throw new Error("Game not found");
|
||||
|
||||
await db.put("games", { ...game, eval: evaluation });
|
||||
|
||||
loadGames();
|
||||
};
|
||||
|
||||
const getGame = async (gameId: number) => {
|
||||
if (!db) return undefined;
|
||||
|
||||
return db.get("games", gameId);
|
||||
};
|
||||
|
||||
const deleteGame = async (gameId: number) => {
|
||||
if (!db) throw new Error("Database not initialized");
|
||||
|
||||
await db.delete("games", gameId);
|
||||
|
||||
loadGames();
|
||||
};
|
||||
|
||||
const isReady = db !== null;
|
||||
|
||||
return { addGame, setGameEval, getGame, deleteGame, games, isReady };
|
||||
};
|
||||
@@ -5,17 +5,21 @@ type SetValue<T> = Dispatch<SetStateAction<T>>;
|
||||
export function useLocalStorage<T>(
|
||||
key: string,
|
||||
initialValue: T
|
||||
): [T, SetValue<T>] {
|
||||
const [storedValue, setStoredValue] = useState<T>(initialValue);
|
||||
): [T | null, SetValue<T>] {
|
||||
const [storedValue, setStoredValue] = useState<T | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const item = window.localStorage.getItem(key);
|
||||
if (item) {
|
||||
setStoredValue(parseJSON<T>(item));
|
||||
} else {
|
||||
setStoredValue(initialValue);
|
||||
}
|
||||
}, [key]);
|
||||
|
||||
const setValue: SetValue<T> = (value) => {
|
||||
if (storedValue === null)
|
||||
throw new Error("setLocalStorage value isn't ready yet");
|
||||
const newValue = value instanceof Function ? value(storedValue) : value;
|
||||
window.localStorage.setItem(key, JSON.stringify(newValue));
|
||||
setStoredValue(newValue);
|
||||
|
||||
Reference in New Issue
Block a user