Open benjstorlie opened 1 year ago
Some starter code. First, add const [move, setMove] = useState(0)
. Then, each time the user moves, setMove((move) => move+1)
. This gives a way to reference where in the game history you are. 'move' will also need to be added to the server. Or have gameData = JSON.stringify({move,gameArray})
, and make sure to parse retrieved gameData accordingly. Actually that's a better idea, since then there's the option of adding whatever to the gameData.
Make sure to install idb
A function to add to client/src/utils/GameContext.js. This would then be called right along saveGameState
. When using it after saveNewGame
, make sure to give it the new gameId.
import { openDB } from 'idb';
async function saveGameLocal(gameId, move, gameData) {
const dbName = 'sudoku-shuffle-db';
const dbVersion = 1; // You can update this when needed
// Open the database
const db = await openDB(dbName, dbVersion, {
upgrade(db) {
// Create a new store if it doesn't exist
if (!db.objectStoreNames.contains(gameId)) {
db.createObjectStore(gameId);
}
},
});
// Start a transaction and get the object store
const tx = db.transaction(gameId, 'readwrite');
const store = tx.objectStore(gameId);
// Save the gameData with the specified move number
await store.put(gameData, move);
// Delete entries with move numbers greater than the specified move
const keys = await store.getAllKeys();
for (const key of keys) {
if (key > move) {
await store.delete(key);
}
}
// Complete the transaction
await tx.complete;
// Close the database
db.close();
}
// Example usage
const gameId = 'exampleGame';
const move = 5;
const gameArray = { /* ... */ }
saveGameLocal(gameId, move, JSON.stringify({gameArray}));
Then, here's a component that holds the undo and redo buttons, plus the logic to figure out whether they should be disabled.
(I called it 'Undo', but it holds both buttons. Is there a word that refers to both?)
There might need to be some extra logic for whether undo is disabled or not, because maybe the user resumed a game from the database, but the game history is not in their local storage.
import React, { useState } from 'react';
import { useGameContext } from '../../utils/GameContext'
export default function Undo() {
const { gameId, gameData, setGameData, move, setMove } = useGameContext();
const [previousMove, setPreviousMove] = useState(-1);
const [redoAttempts, setRedoAttempts] = useState(0);
const canUndo = move > 0;
const canRedo = redoAttempts > 0;
const handleUndo = () => {
if (canUndo) {
setMove((move) => move - 1);
setRedoAttempts(redoAttempts + 1); // Increment redo attempts
setPreviousMove(move - 1); // Set the previous move
// Implement your undo logic here
}
};
const handleRedo = () => {
if (canRedo) {
setMove((move) => move + 1);
setRedoAttempts(redoAttempts - 1); // Decrement redo attempts
// Implement your redo logic here
}
};
// Disable redo if move increases without redo being pressed
if (move > previousMove && redoAttempts > 0) {
setRedoAttempts(0); // Reset redo attempts
}
return (
<div>
<button onClick={handleUndo} disabled={!canUndo}>
Undo
</button>
<button onClick={handleRedo} disabled={!canRedo}>
Redo
</button>
</div>
);
}
Then here would be the corresponding retrieveGameLocal
function that undo and redo will use.
import { openDB } from 'idb';
async function retrieveGameLocal(gameId, move) {
const dbName = 'sudoku-shuffle-db';
const dbVersion = 1; // You can update this when needed
// Open the database
const db = await openDB(dbName, dbVersion);
// Start a transaction and get the object store
const tx = db.transaction(gameId, 'readonly');
const store = tx.objectStore(gameId);
// Retrieve the gameData for the specified move number
const gameData = await store.get(move);
// Complete the transaction
await tx.complete;
// Close the database
db.close();
return gameData;
}
// Inside your React component
const handleUndo = async () => {
if (move > 0) {
setMove((move) => move - 1);
const updatedGameData = await retrieveGameLocal(gameId, move - 1);
setGameData(JSON.parse(updatedGameData).gameArray);
// Implement any additional undo logic
}
};
And redo
would be handled similarly.
Implement functions to save and retrieve game moves using IndexedDB.
Save each move as one entry, with each game getting its own store, so it can remember the history for several games.
Save each move auto-incrementing the id, to be able to retrieve the most recent.