From 43268d8d8626de543c99a4a52164a9db89f1b636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20F=C3=B6rtsch?= Date: Fri, 13 Mar 2026 07:18:18 +0100 Subject: [PATCH] add QuizBuzzer, QuizHost, QuizDisplay components Co-Authored-By: Claude Sonnet 4.6 --- .../client/src/components/quiz-buzzer.tsx | 73 +++++++++++++ .../client/src/components/quiz-display.tsx | 50 +++++++++ packages/client/src/components/quiz-host.tsx | 100 ++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 packages/client/src/components/quiz-buzzer.tsx create mode 100644 packages/client/src/components/quiz-display.tsx create mode 100644 packages/client/src/components/quiz-host.tsx diff --git a/packages/client/src/components/quiz-buzzer.tsx b/packages/client/src/components/quiz-buzzer.tsx new file mode 100644 index 0000000..b6b7a40 --- /dev/null +++ b/packages/client/src/components/quiz-buzzer.tsx @@ -0,0 +1,73 @@ +import type { QuizQuestion } from "@celebrate-esc/shared" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" + +interface QuizBuzzerProps { + question: QuizQuestion + buzzStatus: "can_buzz" | "already_buzzed" | "excluded" | "waiting" | null + onBuzz: () => void +} + +const difficultyColors: Record = { + easy: "text-green-600", + medium: "text-yellow-600", + hard: "text-red-600", +} + +export function QuizBuzzer({ question, buzzStatus, onBuzz }: QuizBuzzerProps) { + return ( + + + + Quiz — Question {question.index + 1}/{question.total} + + {question.difficulty} + + + + + {question.status === "buzzing" && buzzStatus === "can_buzz" && ( + + )} + + {question.status === "buzzing" && buzzStatus === "excluded" && ( +

You are excluded from this question.

+ )} + + {question.status === "judging" && buzzStatus === "already_buzzed" && ( +

You buzzed! Waiting for the host to judge...

+ )} + + {buzzStatus === "waiting" && ( +

+ {question.buzzerName} buzzed in! Waiting for judgment... +

+ )} + + {question.status === "resolved" && question.wasCorrect && ( +

+ {question.buzzerName} answered correctly! +

+ )} + + {question.status === "resolved" && question.wasCorrect === null && ( +

+ Question skipped. +

+ )} + + {question.status === "resolved" && question.wasCorrect === false && ( +

+ Question resolved — no one answered correctly. +

+ )} +
+
+ ) +} diff --git a/packages/client/src/components/quiz-display.tsx b/packages/client/src/components/quiz-display.tsx new file mode 100644 index 0000000..76163db --- /dev/null +++ b/packages/client/src/components/quiz-display.tsx @@ -0,0 +1,50 @@ +import type { QuizQuestion } from "@celebrate-esc/shared" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" + +interface QuizDisplayProps { + question: QuizQuestion +} + +const difficultyColors: Record = { + easy: "text-green-600", + medium: "text-yellow-600", + hard: "text-red-600", +} + +export function QuizDisplay({ question }: QuizDisplayProps) { + return ( + + + + Quiz — Question {question.index + 1}/{question.total} + + {question.difficulty} + + + + +

{question.text}

+ + {question.status === "buzzing" && ( +

+ Buzz in to answer! +

+ )} + + {question.status === "judging" && question.buzzerName && ( +

+ {question.buzzerName} buzzed in! +

+ )} + + {question.status === "resolved" && ( +

+ {question.wasCorrect + ? `✓ ${question.buzzerName} got it right!` + : "✗ No one got it right."} +

+ )} +
+
+ ) +} diff --git a/packages/client/src/components/quiz-host.tsx b/packages/client/src/components/quiz-host.tsx new file mode 100644 index 0000000..e46985f --- /dev/null +++ b/packages/client/src/components/quiz-host.tsx @@ -0,0 +1,100 @@ +import type { QuizQuestion } from "@celebrate-esc/shared" +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" + +interface QuizHostProps { + question: QuizQuestion | null + onStartQuestion: () => void + onJudge: (correct: boolean) => void + onSkip: () => void +} + +const difficultyColors: Record = { + easy: "text-green-600", + medium: "text-yellow-600", + hard: "text-red-600", +} + +export function QuizHost({ question, onStartQuestion, onJudge, onSkip }: QuizHostProps) { + if (!question) { + return ( + + + Quiz + + + + + + ) + } + + return ( + + + + Question {question.index + 1}/{question.total} + + {question.difficulty} + + + + +
+

{question.text}

+
+
+

Answer:

+

{question.answer}

+
+ + {question.status === "buzzing" && ( +
+

Waiting for someone to buzz...

+ +
+ )} + + {question.status === "judging" && question.buzzerName && ( +
+

+ {question.buzzerName} buzzed in! +

+
+ + +
+
+ )} + + {question.status === "resolved" && ( +
+

+ {question.wasCorrect + ? `${question.buzzerName} answered correctly!` + : "No one answered correctly."} +

+ +
+ )} +
+
+ ) +}