Add disable timer setting and fix per-question time limits

Add a 'Question Timer' toggle to game settings that lets the host disable
the countdown timer. When disabled, questions show ∞ instead of a countdown,
the host gets an 'End Question' button to manually advance, and all correct
answers receive maximum points.

Also fix a bug where per-question time limits were ignored — the timer and
scoring always used the hardcoded 20-second default instead of each question's
individual timeLimit.
This commit is contained in:
Joey Yakimowich-Payne 2026-02-23 13:44:12 -07:00
commit d1f82440a1
No known key found for this signature in database
GPG key ID: DDF6AF5B21B407D4
9 changed files with 94 additions and 31 deletions

View file

@ -2,6 +2,7 @@ import React from 'react';
import { Question, AnswerOption, GameState, GameRole } from '../types';
import { COLORS, SHAPES } from '../constants';
import { motion, AnimatePresence } from 'framer-motion';
import { StopCircle } from 'lucide-react';
interface GameScreenProps {
question?: Question;
@ -14,6 +15,8 @@ interface GameScreenProps {
hasAnswered: boolean;
lastPointsEarned: number | null;
hostPlays?: boolean;
timerEnabled?: boolean;
onEndQuestion?: () => void;
}
export const GameScreen: React.FC<GameScreenProps> = ({
@ -26,13 +29,15 @@ export const GameScreen: React.FC<GameScreenProps> = ({
onAnswer,
hasAnswered,
hostPlays = true,
timerEnabled = true,
onEndQuestion,
}) => {
const isClient = role === 'CLIENT';
const isSpectator = role === 'HOST' && !hostPlays;
const displayOptions = question?.options || [];
const timeLeftSeconds = Math.ceil(timeLeft / 1000);
const isUrgent = timeLeftSeconds <= 5 && timeLeftSeconds > 0;
const isUrgent = timerEnabled && timeLeftSeconds <= 5 && timeLeftSeconds > 0;
const timerBorderColor = isUrgent ? 'border-red-500' : 'border-white';
const timerTextColor = isUrgent ? 'text-red-500' : 'text-theme-primary';
const timerAnimation = isUrgent ? 'animate-ping' : '';
@ -45,11 +50,26 @@ export const GameScreen: React.FC<GameScreenProps> = ({
{currentQuestionIndex + 1} / {totalQuestions}
</div>
<div className="relative">
<div className="relative flex flex-col items-center gap-2">
<div className="absolute inset-0 bg-white/20 rounded-full blur-xl animate-pulse"></div>
<div className={`bg-white ${timerTextColor} rounded-full w-14 h-14 md:w-20 md:h-20 flex items-center justify-center text-2xl md:text-4xl font-black shadow-[0_6px_0_rgba(0,0,0,0.2)] border-4 ${timerBorderColor} ${timerAnimation} relative z-10 transition-colors duration-300`}>
{timeLeftSeconds}
</div>
{timerEnabled ? (
<div className={`bg-white ${timerTextColor} rounded-full w-14 h-14 md:w-20 md:h-20 flex items-center justify-center text-2xl md:text-4xl font-black shadow-[0_6px_0_rgba(0,0,0,0.2)] border-4 ${timerBorderColor} ${timerAnimation} relative z-10 transition-colors duration-300`}>
{timeLeftSeconds}
</div>
) : (
<div className="bg-white text-theme-primary rounded-full w-14 h-14 md:w-20 md:h-20 flex items-center justify-center text-3xl md:text-5xl font-black shadow-[0_6px_0_rgba(0,0,0,0.2)] border-4 border-white relative z-10">
</div>
)}
{!timerEnabled && role === 'HOST' && onEndQuestion && (
<button
onClick={onEndQuestion}
className="relative z-10 flex items-center gap-1.5 bg-white/90 hover:bg-white text-red-600 px-3 py-1.5 rounded-full text-xs md:text-sm font-bold shadow-lg hover:shadow-xl transition-all active:scale-95"
>
<StopCircle size={16} />
End Question
</button>
)}
</div>
<div className="bg-white/20 backdrop-blur-md px-3 md:px-6 py-1 md:py-2 rounded-xl md:rounded-2xl font-black text-sm md:text-xl shadow-sm border-2 border-white/10">
@ -163,4 +183,4 @@ export const GameScreen: React.FC<GameScreenProps> = ({
</AnimatePresence>
</div>
);
};
};