Allow manual submit input after correction threshold
This commit is contained in:
parent
c0e63ff68b
commit
9f86077bef
|
|
@ -405,6 +405,35 @@ describe('useInteractionPhase', () => {
|
|||
}
|
||||
})
|
||||
|
||||
it('accepts any digit input once manual submit is required', async () => {
|
||||
const { result } = renderHook(() => useInteractionPhase())
|
||||
|
||||
act(() => {
|
||||
result.current.loadProblem(simpleProblem, 0, 0)
|
||||
})
|
||||
|
||||
// Force manual submit by exceeding the correction threshold
|
||||
for (let i = 0; i <= MANUAL_SUBMIT_THRESHOLD; i++) {
|
||||
act(() => {
|
||||
result.current.handleDigit('5') // invalid digit
|
||||
})
|
||||
await act(async () => {
|
||||
vi.advanceTimersByTime(301)
|
||||
})
|
||||
}
|
||||
|
||||
// Now that manual submit is required, any digit should be accepted
|
||||
act(() => {
|
||||
result.current.handleDigit('9')
|
||||
})
|
||||
|
||||
if (result.current.phase.phase === 'inputting') {
|
||||
expect(result.current.phase.attempt.manualSubmitRequired).toBe(true)
|
||||
expect(result.current.phase.attempt.userAnswer).toBe('9')
|
||||
expect(result.current.phase.attempt.rejectedDigit).toBeNull()
|
||||
}
|
||||
})
|
||||
|
||||
it('does nothing in non-input phases', () => {
|
||||
const { result } = renderHook(() => useInteractionPhase())
|
||||
|
||||
|
|
|
|||
|
|
@ -509,19 +509,26 @@ export function useInteractionPhase(
|
|||
// Timer already elapsed - transition to help mode immediately
|
||||
// Keep userAnswer during transition so it shows in answer boxes while fading out
|
||||
const helpContext = computeHelpContext(phase.attempt.problem.terms, ctx.helpTermIndex)
|
||||
setPhase({ phase: 'helpMode', attempt: phase.attempt, helpContext })
|
||||
setPhase({
|
||||
phase: 'helpMode',
|
||||
attempt: { ...phase.attempt, userAnswer: '' },
|
||||
helpContext,
|
||||
})
|
||||
} else {
|
||||
// Set timer for remaining time
|
||||
const remaining = AMBIGUOUS_HELP_DELAY_MS - elapsed
|
||||
disambiguationTimerRef.current = setTimeout(() => {
|
||||
setPhase((prev) => {
|
||||
if (prev.phase !== 'awaitingDisambiguation') return prev
|
||||
// Keep userAnswer during transition so it shows in answer boxes while fading out
|
||||
const helpContext = computeHelpContext(
|
||||
prev.attempt.problem.terms,
|
||||
prev.disambiguationContext.helpTermIndex
|
||||
)
|
||||
return { phase: 'helpMode', attempt: prev.attempt, helpContext }
|
||||
return {
|
||||
phase: 'helpMode',
|
||||
attempt: { ...prev.attempt, userAnswer: '' },
|
||||
helpContext,
|
||||
}
|
||||
})
|
||||
}, remaining)
|
||||
}
|
||||
|
|
@ -644,6 +651,16 @@ export function useInteractionPhase(
|
|||
const attempt = prev.attempt
|
||||
const sums = computePrefixSums(attempt.problem.terms)
|
||||
|
||||
// Once manual submit is required, accept any digit without validation
|
||||
if (attempt.manualSubmitRequired) {
|
||||
const updatedAttempt = {
|
||||
...attempt,
|
||||
userAnswer: attempt.userAnswer + digit,
|
||||
rejectedDigit: null,
|
||||
}
|
||||
return { phase: 'inputting', attempt: updatedAttempt }
|
||||
}
|
||||
|
||||
if (isDigitConsistent(attempt.userAnswer, digit, sums)) {
|
||||
const updatedAttempt = {
|
||||
...attempt,
|
||||
|
|
@ -673,13 +690,10 @@ export function useInteractionPhase(
|
|||
// Unambiguous intermediate prefix match (e.g., "03" for prefix sum 3)
|
||||
// Immediately enter help mode
|
||||
// Keep userAnswer during transition so it shows in answer boxes while fading out
|
||||
const helpContext = computeHelpContext(
|
||||
attempt.problem.terms,
|
||||
newPrefixMatch.helpTermIndex
|
||||
)
|
||||
const helpContext = computeHelpContext(attempt.problem.terms, newPrefixMatch.helpTermIndex)
|
||||
return {
|
||||
phase: 'helpMode',
|
||||
attempt: updatedAttempt,
|
||||
attempt: { ...updatedAttempt, userAnswer: '' },
|
||||
helpContext,
|
||||
}
|
||||
} else {
|
||||
|
|
@ -774,15 +788,25 @@ export function useInteractionPhase(
|
|||
|
||||
// Keep userAnswer during transition so it shows in answer boxes while fading out
|
||||
const helpContext = computeHelpContext(prev.attempt.problem.terms, termIndex)
|
||||
return { phase: 'helpMode', attempt: prev.attempt, helpContext }
|
||||
return {
|
||||
phase: 'helpMode',
|
||||
attempt: { ...prev.attempt, userAnswer: '' },
|
||||
helpContext,
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
const exitHelpMode = useCallback(() => {
|
||||
setPhase((prev) => {
|
||||
if (prev.phase !== 'helpMode') return prev
|
||||
const updatedAttempt = { ...prev.attempt, userAnswer: '' }
|
||||
return { phase: 'inputting', attempt: updatedAttempt }
|
||||
if (prev.phase === 'helpMode') {
|
||||
const updatedAttempt = { ...prev.attempt, userAnswer: '' }
|
||||
return { phase: 'inputting', attempt: updatedAttempt }
|
||||
}
|
||||
if (prev.phase === 'inputting') {
|
||||
const updatedAttempt = { ...prev.attempt, userAnswer: '' }
|
||||
return { phase: 'inputting', attempt: updatedAttempt }
|
||||
}
|
||||
return prev
|
||||
})
|
||||
}, [])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue