Goal
Allow users to select quiz answers on mobile devices without triggering anti-cheat violation.
Problem
On mobile phones, users could not select quiz answers. Instead, anti-cheat showed "context menu" violation message.
Root cause:
- Long-press on mobile triggers
contextmenu event
- Anti-cheat handler called
e.preventDefault() and recorded violation
- This blocked normal touch interaction on mobile
Solution
1. useAntiCheat.ts — Detect touch vs mouse input
- Added
lastInteractionWasTouch ref
- Track
touchstart → flag = true
- Track
mousedown → flag = false
- In
contextmenu handler: skip violation if touch-triggered
const handleContextMenu = (e: MouseEvent) => {
e.preventDefault();
if (!lastInteractionWasTouch.current) {
addViolation('context-menu');
}
};
2. QuizQuestion.tsx — Prevent text selection
- Added
select-none class (CSS user-select: none)
- Added
[-webkit-touch-callout:none] for iOS Safari
- Prevents long-press text selection on protected content
3. CountdownTimer.tsx — Fix progress bar jump on mount
- Changed initial state from
Date.now() calculation to timeLimitSeconds
- Added
isSynced state, set to true on first interval tick
- Transition enabled only after sync (prevents visual "jump")
Why this fix:
useState with Date.now() causes hydration mismatch (SSR vs client)
- Progress bar animated from wrong position on page navigation
- Now: initial render shows 100%, then syncs without transition
4. page.tsx (quiz/[slug]) — TypeScript fix
- Fixed
description metadata type error
quiz.description ?? t('fallback', { title: quiz.title ?? '' })
Files Changed
| File |
Change |
hooks/useAntiCheat.ts |
Touch detection for contextmenu |
components/quiz/QuizQuestion.tsx |
select-none + webkit-touch-callout |
components/quiz/CountdownTimer.tsx |
isSynced state for transition |
app/[locale]/quiz/[slug]/page.tsx |
TypeScript metadata fix |
Testing
- Mobile: long-press no longer triggers violation
- Mobile: text selection disabled on quiz content
- Desktop: right-click still blocked with violation
- Timer: no visual jump on page navigation
UX Behavior After Fix
| Platform |
Contextmenu |
Text Selection |
Violation |
| Desktop |
Blocked |
Blocked (CSS) |
Yes |
| Mobile |
Blocked |
Blocked (CSS) |
No |
Goal
Allow users to select quiz answers on mobile devices without triggering anti-cheat violation.
Problem
On mobile phones, users could not select quiz answers. Instead, anti-cheat showed "context menu" violation message.
Root cause:
contextmenuevente.preventDefault()and recorded violationSolution
1. useAntiCheat.ts — Detect touch vs mouse input
lastInteractionWasTouchreftouchstart→ flag = truemousedown→ flag = falsecontextmenuhandler: skip violation if touch-triggered2. QuizQuestion.tsx — Prevent text selection
select-noneclass (CSSuser-select: none)[-webkit-touch-callout:none]for iOS Safari3. CountdownTimer.tsx — Fix progress bar jump on mount
Date.now()calculation totimeLimitSecondsisSyncedstate, set totrueon first interval tickWhy this fix:
useStatewithDate.now()causes hydration mismatch (SSR vs client)4. page.tsx (quiz/[slug]) — TypeScript fix
descriptionmetadata type errorquiz.description ?? t('fallback', { title: quiz.title ?? '' })Files Changed
hooks/useAntiCheat.tscomponents/quiz/QuizQuestion.tsxcomponents/quiz/CountdownTimer.tsxapp/[locale]/quiz/[slug]/page.tsxTesting
UX Behavior After Fix