-
Notifications
You must be signed in to change notification settings - Fork 1
fix ui responsive #158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix ui responsive #158
Changes from all commits
0235ea7
c180549
4deb12d
18904a6
a83c7c2
048cfa4
70734a7
606c367
16a42da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -98,6 +98,7 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| const timerRef = useRef<NodeJS.Timeout | null>(null); | ||||||
| const [timerFrozen, setTimerFrozen] = useState(false); | ||||||
| const freezeTimeoutRef = useRef<NodeJS.Timeout | null>(null); | ||||||
| const isProcessingTimeout = useRef(false); | ||||||
|
|
||||||
| // Power-ups | ||||||
| const [powerUps, setPowerUps] = useState<PowerUp[]>([ | ||||||
|
|
@@ -193,10 +194,6 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| const responseData = userInfoResp?.data as { Info?: { current_exp?: number; subscription?: number }; info?: { current_exp?: number; subscription?: number } } | undefined; | ||||||
| // Try both Info (capital) and info (lowercase) for compatibility | ||||||
| const userInfo = responseData?.Info || responseData?.info; | ||||||
| console.log('User info response:', responseData); | ||||||
| console.log('Extracted user info:', userInfo); | ||||||
| console.log('Current EXP:', userInfo?.current_exp); | ||||||
| console.log('Subscription:', userInfo?.subscription); | ||||||
|
|
||||||
| const exp = userInfo?.current_exp || 0; | ||||||
| const subscription = userInfo?.subscription || 0; | ||||||
|
|
@@ -233,10 +230,22 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| }, [quizId]); | ||||||
|
|
||||||
| const handleTimeUp = useCallback(() => { | ||||||
| if (timerRef.current) clearInterval(timerRef.current); | ||||||
| // Prevent duplicate execution | ||||||
| if (isProcessingTimeout.current) { | ||||||
| return; | ||||||
| } | ||||||
| isProcessingTimeout.current = true; | ||||||
|
|
||||||
| if (timerRef.current) { | ||||||
| clearInterval(timerRef.current); | ||||||
| timerRef.current = null; | ||||||
| } | ||||||
|
|
||||||
| const currentCard = quiz?.cards[currentIndex]; | ||||||
| if (!currentCard) return; | ||||||
| if (!currentCard) { | ||||||
| isProcessingTimeout.current = false; | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| // Show toast after state updates to avoid setState in render | ||||||
| setTimeout(() => { | ||||||
|
|
@@ -257,6 +266,8 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| // Auto submit on last question | ||||||
| handleSubmit(); | ||||||
| } | ||||||
| // Reset flag after transition | ||||||
| isProcessingTimeout.current = false; | ||||||
| }, 1500); | ||||||
| }, [quiz, currentIndex, answers, timePerQuestion]); | ||||||
|
|
||||||
|
|
@@ -266,9 +277,9 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
|
|
||||||
| timerRef.current = setInterval(() => { | ||||||
| setTimeLeft((prev) => { | ||||||
| if (prev <= 0) { | ||||||
| // Time's up for this question | ||||||
| handleTimeUp(); | ||||||
| if (prev <= 1) { | ||||||
| // Time's up for this question - use ref to avoid dependency issues | ||||||
| handleTimeUpRef.current(); | ||||||
| return 0; | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -282,9 +293,12 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| }, 1000); | ||||||
|
|
||||||
| return () => { | ||||||
| if (timerRef.current) clearInterval(timerRef.current); | ||||||
| if (timerRef.current) { | ||||||
| clearInterval(timerRef.current); | ||||||
| timerRef.current = null; | ||||||
| } | ||||||
| }; | ||||||
| }, [quiz, submitted, loading, currentIndex, timePerQuestion, handleTimeUp, timerFrozen]); | ||||||
| }, [quiz, submitted, loading, currentIndex, timePerQuestion, timerFrozen]); | ||||||
|
|
||||||
| const handleTimeUpRef = useRef(handleTimeUp); | ||||||
| useEffect(() => { | ||||||
|
|
@@ -576,13 +590,11 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
|
|
||||||
| // Calculate average score for saving as previous_score | ||||||
| const avgScore = quiz ? Math.round(actualTotalScore / quiz.cards.length) : 0; | ||||||
| console.log('Average score for quiz:', avgScore); | ||||||
|
|
||||||
| // Update previous_score if this score is higher | ||||||
| if (avgScore > (quiz.previous_score || 0)) { | ||||||
| try { | ||||||
| await quizApi.updatePreviousScore(quizId, avgScore); | ||||||
| console.log('Updated previous_score to:', avgScore); | ||||||
| } catch (updateError) { | ||||||
| console.error('Failed to update previous_score:', updateError); | ||||||
| // Don't show error to user, just log it | ||||||
|
|
@@ -618,10 +630,15 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| setEliminatedOptions({}); | ||||||
| setShowHint({}); | ||||||
| setPowerUps(prev => prev.map(p => ({ ...p, usesLeft: p.maxUses, active: false }))); | ||||||
| isProcessingTimeout.current = false; | ||||||
|
|
||||||
| if (freezeTimeoutRef.current) { | ||||||
| clearTimeout(freezeTimeoutRef.current); | ||||||
| } | ||||||
| if (timerRef.current) { | ||||||
| clearInterval(timerRef.current); | ||||||
| timerRef.current = null; | ||||||
| } | ||||||
|
|
||||||
| // Reload to fetch fresh user EXP | ||||||
| window.location.reload(); | ||||||
|
|
@@ -860,12 +877,12 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| </div> | ||||||
|
|
||||||
| {/* Power-ups */} | ||||||
| <div className="bg-white/70 backdrop-blur-sm rounded-xl p-4 shadow-sm border border-gray-100"> | ||||||
| <div className="flex items-center gap-2 mb-3"> | ||||||
| <Zap className="w-4 h-4 text-purple-600" /> | ||||||
| <h3 className="font-bold text-gray-900 text-sm">Items (EXP: {userExp})</h3> | ||||||
| <div className="bg-white/70 backdrop-blur-sm rounded-xl p-3 sm:p-4 shadow-sm border border-gray-100"> | ||||||
| <div className="flex items-center gap-1.5 sm:gap-2 mb-2 sm:mb-3"> | ||||||
| <Zap className="w-3.5 h-3.5 sm:w-4 sm:h-4 text-purple-600" /> | ||||||
| <h3 className="font-bold text-gray-900 text-xs sm:text-sm">Items (EXP: {userExp})</h3> | ||||||
| </div> | ||||||
| <div className="flex gap-2 flex-wrap"> | ||||||
| <div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-1.5 sm:gap-2"> | ||||||
| {powerUps.map((powerUp) => { | ||||||
| const isActive = powerUp.active; | ||||||
| const canUse = powerUp.usesLeft > 0 && userExp >= powerUp.cost; | ||||||
|
|
@@ -883,7 +900,7 @@ export default function QuizPlayPage({ params }: PageProps) { | |||||
| key={powerUp.id} | ||||||
| onClick={() => activatePowerUp(powerUp.id)} | ||||||
| disabled={!canUse || isActive} | ||||||
| className={`group relative flex items-center gap-2 px-4 py-2.5 rounded-lg border-2 font-semibold text-sm transition-all ${ | ||||||
| className={`group relative flex flex-col lg:flex-row items-center justify-center lg:justify-start gap-1 sm:gap-1.5 lg:gap-2 px-2 sm:px-3 lg:px-4 py-2 sm:py-2.5 rounded-lg border-2 font-semibold text-[10px] sm:text-xs lg:text-sm transition-all ${ | ||||||
|
||||||
| className={`group relative flex flex-col lg:flex-row items-center justify-center lg:justify-start gap-1 sm:gap-1.5 lg:gap-2 px-2 sm:px-3 lg:px-4 py-2 sm:py-2.5 rounded-lg border-2 font-semibold text-[10px] sm:text-xs lg:text-sm transition-all ${ | |
| className={`group relative flex flex-col lg:flex-row items-center justify-center lg:justify-start gap-1 sm:gap-1.5 lg:gap-2 px-2 sm:px-3 lg:px-4 py-2 sm:py-2.5 rounded-lg border-2 font-semibold text-xs sm:text-xs lg:text-sm transition-all ${ |
Copilot
AI
Jan 8, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The text size text-[9px] is extremely small (9px) and will be very difficult to read on mobile devices. This is below accessibility standards. Consider using at least text-xs (12px).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition changed from
prev <= 0toprev <= 1, which means the timeout will trigger 1 second earlier than before. This changes the business logic and may not align with user expectations. If a quiz question has 10 seconds, users would expect to see "0" before the timeout, not have it trigger when there's still 1 second remaining. Consider reverting toprev <= 0or explaining why this change is necessary.