feat: remove Try Again button - allow immediate retries like Chess.com

When a user makes an incorrect move, they can now immediately try again
without clicking Try Again. The wrong move is undone, error sound plays,
and the user can make another attempt right away.

Changes:
- Remove setFeedback(incorrect) on wrong moves
- Remove handleTryAgain function (no longer needed)
- Simplify button logic: Show Next when correct, Skip otherwise
- Skip button now always visible during puzzle solving

This matches Chess.com UX where incorrect moves just play a sound
and let you retry instantly.
This commit is contained in:
Stefan
2026-01-04 10:17:15 +01:00
parent e08cd3e4d6
commit 71eb30bd89
+6 -36
View File
@@ -275,9 +275,8 @@ export default function TacticalPracticePage() {
})); }));
} else { } else {
errorSound.current?.play().catch(e => console.error("Audio play failed", e)); errorSound.current?.play().catch(e => console.error("Audio play failed", e));
setFeedback('incorrect'); // Don't set feedback to 'incorrect' - just play error sound and undo
// Undo the wrong move instead of resetting to start position // This allows the user to immediately try again without clicking "Try Again"
// This allows the user to try again from the same position (like chess.com)
gameRef.current.undo(); gameRef.current.undo();
setFen(gameRef.current.fen()); setFen(gameRef.current.fen());
@@ -315,9 +314,8 @@ export default function TacticalPracticePage() {
if (!isCorrect) { if (!isCorrect) {
errorSound.current?.play().catch(e => console.error("Audio play failed", e)); errorSound.current?.play().catch(e => console.error("Audio play failed", e));
setFeedback('incorrect'); // Don't set feedback to 'incorrect' - just play error sound and undo
// Undo the wrong move instead of resetting to start position // This allows the user to immediately try again without clicking "Try Again"
// This allows the user to try again from the same position (like chess.com)
// The currentMoveIndex stays the same since we're still waiting for the same move // The currentMoveIndex stays the same since we're still waiting for the same move
gameRef.current.undo(); gameRef.current.undo();
setFen(gameRef.current.fen()); setFen(gameRef.current.fen());
@@ -385,15 +383,6 @@ export default function TacticalPracticePage() {
} }
}; };
const handleTryAgain = () => {
// Since we now undo the wrong move immediately when it's made,
// the board is already in the correct position (before the error).
// We just need to reset the feedback state to allow the user to try again.
setFeedback('none');
// Don't reset userMove - keep the chat context
// The Tutor will know the user tried again because feedback changed to 'none'
};
const handleSkipPuzzle = () => { const handleSkipPuzzle = () => {
// Skip counts as incorrect for stats // Skip counts as incorrect for stats
setStats(prev => ({ setStats(prev => ({
@@ -637,7 +626,7 @@ export default function TacticalPracticePage() {
{/* Action Buttons */} {/* Action Buttons */}
<div className="mt-4 space-y-3"> <div className="mt-4 space-y-3">
{feedback === 'correct' && ( {feedback === 'correct' ? (
<button <button
onClick={handleNextExercise} onClick={handleNextExercise}
className="w-full py-3 px-4 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-semibold shadow-lg transition-all flex items-center justify-center gap-2" className="w-full py-3 px-4 bg-blue-600 text-white rounded-lg hover:bg-blue-700 font-semibold shadow-lg transition-all flex items-center justify-center gap-2"
@@ -645,26 +634,7 @@ export default function TacticalPracticePage() {
<RefreshCw size={18} /> <RefreshCw size={18} />
{t.learning.practice.nextExercise} {t.learning.practice.nextExercise}
</button> </button>
)} ) : (
{feedback === 'incorrect' && (
<>
<button
onClick={handleTryAgain}
className="w-full py-3 px-4 bg-orange-600 text-white rounded-lg hover:bg-orange-700 font-semibold shadow-lg transition-all flex items-center justify-center gap-2"
>
<RefreshCw size={18} />
{t.learning.practice.tryAgain}
</button>
<button
onClick={handleSkipPuzzle}
className="w-full py-2 px-4 bg-gray-500 text-white rounded-lg hover:bg-gray-600 font-medium transition-all flex items-center justify-center gap-2"
>
<SkipForward size={18} />
Skip Puzzle
</button>
</>
)}
{feedback === 'none' && (
<button <button
onClick={handleSkipPuzzle} onClick={handleSkipPuzzle}
className="w-full py-2 px-4 bg-gray-500 text-white rounded-lg hover:bg-gray-600 font-medium transition-all flex items-center justify-center gap-2" className="w-full py-2 px-4 bg-gray-500 text-white rounded-lg hover:bg-gray-600 font-medium transition-all flex items-center justify-center gap-2"