fix(card-sorting): preserve card positions on pause/resume

Fix card positions getting randomized when pausing and resuming game:
- Add cardPositions to pausedGameState type in types.ts
- Save cardPositions in GO_TO_SETUP validator and Provider optimistic update
- Restore cardPositions in RESUME_GAME validator and Provider optimistic update
- Fix React hooks rule violation: move useSpring call before early return

Now when you go to setup and resume the game, all cards return to their
exact positions instead of being randomly scattered.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-10-23 14:37:01 -05:00
parent 3e8dbad979
commit 0d8af09517
4 changed files with 8 additions and 3 deletions

View File

@ -233,6 +233,7 @@ function applyMoveOptimistically(state: CardSortingState, move: GameMove): CardS
selectedCards: state.selectedCards,
availableCards: state.availableCards,
placedCards: state.placedCards,
cardPositions: state.cardPositions,
gameStartTime: state.gameStartTime || Date.now(),
numbersRevealed: state.numbersRevealed,
}
@ -276,6 +277,7 @@ function applyMoveOptimistically(state: CardSortingState, move: GameMove): CardS
correctOrder,
availableCards: state.pausedGameState.availableCards,
placedCards: state.pausedGameState.placedCards,
cardPositions: state.pausedGameState.cardPositions,
gameStartTime: state.pausedGameState.gameStartTime,
numbersRevealed: state.pausedGameState.numbersRevealed,
pausedGamePhase: undefined,

View File

@ -334,6 +334,7 @@ export class CardSortingValidator implements GameValidator<CardSortingState, Car
selectedCards: state.selectedCards,
availableCards: state.availableCards,
placedCards: state.placedCards,
cardPositions: state.cardPositions,
gameStartTime: state.gameStartTime || Date.now(),
numbersRevealed: state.numbersRevealed,
},
@ -439,6 +440,7 @@ export class CardSortingValidator implements GameValidator<CardSortingState, Car
correctOrder: [...state.pausedGameState.selectedCards].sort((a, b) => a.number - b.number),
availableCards: state.pausedGameState.availableCards,
placedCards: state.pausedGameState.placedCards,
cardPositions: state.pausedGameState.cardPositions,
gameStartTime: state.pausedGameState.gameStartTime,
numbersRevealed: state.pausedGameState.numbersRevealed,
pausedGamePhase: undefined,

View File

@ -176,9 +176,6 @@ function AnimatedArrow({
const angle = Math.atan2(dy, dx) * (180 / Math.PI)
const distance = Math.sqrt(dx * dx + dy * dy)
// Don't draw arrow if cards are too close
if (distance < 80) return null
// Use spring animation for arrow position and size
// Disable animation when dragging or resizing
const springProps = useSpring({
@ -193,6 +190,9 @@ function AnimatedArrow({
},
})
// Don't draw arrow if cards are too close
if (distance < 80) return null
return (
<animated.div
style={{

View File

@ -98,6 +98,7 @@ export interface CardSortingState extends GameState {
selectedCards: SortingCard[]
availableCards: SortingCard[]
placedCards: (SortingCard | null)[]
cardPositions: CardPosition[]
gameStartTime: number
numbersRevealed: boolean
}