fix: Undo button now properly truncates move history
- Added UNDO_TO_MOVE action that both navigates AND truncates history - Added undoToMove() function to OpeningTrainingContext - Updated handleUndoDeviation to use undoToMove instead of navigate Previously, the Undo button only navigated back but didn't remove the deviation moves, so the session remained in off-book state.
This commit is contained in:
@@ -52,6 +52,7 @@ export default function OpeningTrainer({
|
||||
currentFeedback,
|
||||
initializeSession,
|
||||
makeMove,
|
||||
undoToMove,
|
||||
navigateToMove,
|
||||
} = useOpeningTraining();
|
||||
|
||||
@@ -225,12 +226,12 @@ export default function OpeningTrainer({
|
||||
const handleUndoDeviation = () => {
|
||||
if (!session || session.deviationMoveIndex === null) return;
|
||||
|
||||
// Navigate back to the move before deviation
|
||||
navigateToMove(session.deviationMoveIndex - 1);
|
||||
setShowDeviationDialog(false);
|
||||
// Undo to the move before deviation (this truncates move history)
|
||||
const targetIndex = session.deviationMoveIndex - 1;
|
||||
undoToMove(targetIndex);
|
||||
|
||||
// After a brief delay, make another legal move to continue in theory
|
||||
// This allows the player to try again
|
||||
// Close the dialog
|
||||
setShowDeviationDialog(false);
|
||||
};
|
||||
|
||||
const handleStartGameFromPosition = () => {
|
||||
|
||||
@@ -38,6 +38,7 @@ interface OpeningTrainingContextType {
|
||||
// Actions
|
||||
initializeSession: (opening: OpeningMetadata, forceNew?: boolean) => Promise<void>;
|
||||
makeMove: (san: string) => Promise<void>;
|
||||
undoToMove: (index: number) => void;
|
||||
navigateToMove: (index: number) => void;
|
||||
resetSession: () => void;
|
||||
}
|
||||
@@ -294,6 +295,17 @@ export function OpeningTrainingProvider({
|
||||
}
|
||||
};
|
||||
|
||||
const undoToMove = (index: number) => {
|
||||
if (!session) return;
|
||||
|
||||
console.log('[OpeningTraining] Undoing to move index:', index);
|
||||
|
||||
dispatch({ type: 'UNDO_TO_MOVE', index });
|
||||
|
||||
// Clear feedback when undoing
|
||||
setCurrentFeedback(null);
|
||||
};
|
||||
|
||||
const navigateToMove = (index: number) => {
|
||||
if (!session) return;
|
||||
|
||||
@@ -355,6 +367,7 @@ export function OpeningTrainingProvider({
|
||||
currentFeedback,
|
||||
initializeSession,
|
||||
makeMove,
|
||||
undoToMove,
|
||||
navigateToMove,
|
||||
resetSession,
|
||||
};
|
||||
|
||||
@@ -93,6 +93,7 @@ export type SessionAction =
|
||||
| { type: 'NAVIGATE_PREVIOUS' }
|
||||
| { type: 'NAVIGATE_NEXT' }
|
||||
| { type: 'NAVIGATE_TO_CURRENT' } // Jump back to end of history
|
||||
| { type: 'UNDO_TO_MOVE'; index: number } // Navigate and truncate history
|
||||
|
||||
// Theory tracking
|
||||
| { type: 'DEVIATION_DETECTED'; moveIndex: number }
|
||||
@@ -348,6 +349,47 @@ export function sessionReducer(
|
||||
});
|
||||
}
|
||||
|
||||
case 'UNDO_TO_MOVE': {
|
||||
const { index } = action;
|
||||
|
||||
// Clamp index to valid range (-1 means start position, truncate all moves)
|
||||
const clampedIndex = Math.max(-1, Math.min(index, state.moveHistory.length - 1));
|
||||
|
||||
// Truncate move history to this point
|
||||
const newHistory = clampedIndex < 0 ? [] : state.moveHistory.slice(0, clampedIndex + 1);
|
||||
|
||||
// Build FEN at target index
|
||||
const newFEN = buildFenAtIndex(newHistory, newHistory.length);
|
||||
|
||||
// Reset deviation if we're now back in theory
|
||||
const isNowInTheory = isInTheory(state.opening, newHistory);
|
||||
const newDeviationIndex = isNowInTheory ? null : state.deviationMoveIndex;
|
||||
|
||||
// Determine phase
|
||||
let phase: SessionPhase;
|
||||
if (newDeviationIndex !== null) {
|
||||
phase = 'off_book';
|
||||
} else if (isEndOfRepertoire(state.opening, newHistory.length)) {
|
||||
phase = 'end_of_repertoire';
|
||||
} else if (isOpponentTurn(state.opening, newHistory)) {
|
||||
phase = 'opponent_turn';
|
||||
} else {
|
||||
phase = 'user_turn';
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
moveHistory: newHistory,
|
||||
currentMoveIndex: newHistory.length,
|
||||
currentFEN: newFEN,
|
||||
deviationMoveIndex: newDeviationIndex,
|
||||
isInTheory: isNowInTheory,
|
||||
phase,
|
||||
pendingOpponentMove: null,
|
||||
lastUpdatedAt: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
case 'NAVIGATE_TO_CURRENT': {
|
||||
// Jump to the end of history (current position)
|
||||
const atEnd = state.currentMoveIndex === state.moveHistory.length;
|
||||
|
||||
Reference in New Issue
Block a user