fix(card-sorting): lock correctly positioned prefix/suffix cards
Cards in the correct prefix or suffix are now locked and cannot be dragged, preventing state thrashing when trying to move them. **Changes:** 1. **Added isCardLocked() helper:** - Checks if a card is part of the correct prefix or suffix - Uses same logic as visual feedback (prefix/suffix detection) 2. **Updated handlePointerDown:** - Early return if isCardLocked(cardId) is true - Prevents drag initialization for locked cards 3. **Updated AnimatedCard component:** - Added isLocked prop - Cursor changes to 'not-allowed' for locked cards - Visual indication that cards cannot be moved **User experience:** - Locked cards show 'not-allowed' cursor on hover - Attempting to drag does nothing (no state changes) - Clear feedback that these cards are finalized - Prevents accidental disruption of correctly placed cards - No more state thrashing when clicking on arranged cards **Example:** With sequence [10, 20, 30, 50, 40] and correct order [10, 20, 30, 40, 50]: - Cards 10, 20, 30 are locked (correct prefix) - Only cards 50 and 40 can be dragged - Trying to drag card 10 shows 'not-allowed' cursor and does nothing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -732,6 +732,7 @@ function AnimatedCard({
|
||||
isSpectating,
|
||||
isCorrect,
|
||||
isCorrectPosition,
|
||||
isLocked,
|
||||
draggedByPlayerId,
|
||||
localPlayerId,
|
||||
players,
|
||||
@@ -748,6 +749,7 @@ function AnimatedCard({
|
||||
isSpectating: boolean
|
||||
isCorrect: boolean
|
||||
isCorrectPosition: boolean
|
||||
isLocked: boolean
|
||||
draggedByPlayerId?: string
|
||||
localPlayerId?: string
|
||||
players: Map<string, { id: string; name: string; emoji: string }>
|
||||
@@ -795,7 +797,7 @@ function AnimatedCard({
|
||||
position: 'absolute',
|
||||
width: '140px',
|
||||
height: '180px',
|
||||
cursor: isSpectating ? 'default' : 'grab',
|
||||
cursor: isLocked ? 'not-allowed' : isSpectating ? 'default' : 'grab',
|
||||
touchAction: 'none',
|
||||
userSelect: 'none',
|
||||
transition: 'box-shadow 0.2s ease',
|
||||
@@ -1310,9 +1312,39 @@ export function PlayingPhaseDrag() {
|
||||
return `${m}:${s.toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
// Check if a card is locked (in correct prefix or suffix and thus not draggable)
|
||||
const isCardLocked = (cardId: string): boolean => {
|
||||
const cardIndex = inferredSequence.findIndex((c) => c.id === cardId)
|
||||
if (cardIndex < 0) return false
|
||||
|
||||
// Check if card is in correct prefix
|
||||
let isInPrefix = true
|
||||
for (let i = 0; i <= cardIndex; i++) {
|
||||
if (inferredSequence[i]?.id !== state.correctOrder[i]?.id) {
|
||||
isInPrefix = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if (isInPrefix) return true
|
||||
|
||||
// Check if card is in correct suffix
|
||||
let isInSuffix = true
|
||||
const offsetFromEnd = inferredSequence.length - 1 - cardIndex
|
||||
for (let i = 0; i <= offsetFromEnd; i++) {
|
||||
const seqIdx = inferredSequence.length - 1 - i
|
||||
const correctIdx = state.correctOrder.length - 1 - i
|
||||
if (inferredSequence[seqIdx]?.id !== state.correctOrder[correctIdx]?.id) {
|
||||
isInSuffix = false
|
||||
break
|
||||
}
|
||||
}
|
||||
return isInSuffix
|
||||
}
|
||||
|
||||
// Handle pointer down (start drag)
|
||||
const handlePointerDown = (e: React.PointerEvent, cardId: string) => {
|
||||
if (isSpectating) return
|
||||
if (isCardLocked(cardId)) return // Don't allow dragging locked cards
|
||||
|
||||
const target = e.currentTarget as HTMLElement
|
||||
target.setPointerCapture(e.pointerId)
|
||||
@@ -2021,6 +2053,7 @@ export function PlayingPhaseDrag() {
|
||||
isSpectating={isSpectating}
|
||||
isCorrect={isCorrect}
|
||||
isCorrectPosition={isInCorrectPrefixOrSuffix}
|
||||
isLocked={isInCorrectPrefixOrSuffix}
|
||||
draggedByPlayerId={draggedByPlayerId}
|
||||
localPlayerId={localPlayerId}
|
||||
players={players}
|
||||
|
||||
Reference in New Issue
Block a user