quiz-renderer.tsx 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. 'use client';
  2. import { useState } from 'react';
  3. import type { QuizContent } from '@/lib/types/stage';
  4. import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
  5. import { Button } from '@/components/ui/button';
  6. import { cn } from '@/lib/utils';
  7. interface QuizRendererProps {
  8. readonly content: QuizContent;
  9. readonly mode: 'autonomous' | 'playback';
  10. readonly sceneId: string;
  11. }
  12. export function QuizRenderer({ content, mode, sceneId: _sceneId }: QuizRendererProps) {
  13. const [answers, setAnswers] = useState<Record<string, string>>({});
  14. const handleAnswerChange = (questionId: string, answer: string) => {
  15. setAnswers((prev) => ({ ...prev, [questionId]: answer }));
  16. };
  17. return (
  18. <div className="w-full h-full overflow-y-auto p-8">
  19. <div className="max-w-3xl mx-auto space-y-6">
  20. <h1 className="text-3xl font-bold">Quiz</h1>
  21. {content.questions.map((question) => (
  22. <Card key={question.id}>
  23. <CardHeader>
  24. <CardTitle>{question.question}</CardTitle>
  25. </CardHeader>
  26. <CardContent>
  27. {question.type === 'single' && question.options && (
  28. <div className="space-y-2">
  29. {question.options.map((option, optIndex) => {
  30. // Normalize: options may be QuizOption objects or plain strings from AI
  31. const optionValue = typeof option === 'string' ? option : option.value;
  32. const optionLabel = typeof option === 'string' ? option : option.label;
  33. const letterPrefix = String.fromCharCode(65 + optIndex); // A, B, C, D...
  34. return (
  35. <label
  36. key={`${question.id}-opt-${optIndex}`}
  37. className={cn(
  38. 'flex items-center space-x-2 p-2 rounded cursor-pointer hover:bg-muted',
  39. answers[question.id] === (optionValue || letterPrefix) && 'bg-muted',
  40. )}
  41. >
  42. <input
  43. type="radio"
  44. name={question.id}
  45. value={optionValue || letterPrefix}
  46. checked={answers[question.id] === (optionValue || letterPrefix)}
  47. onChange={(e) => handleAnswerChange(question.id, e.target.value)}
  48. className="size-4"
  49. />
  50. <span>
  51. {letterPrefix}. {optionLabel}
  52. </span>
  53. </label>
  54. );
  55. })}
  56. </div>
  57. )}
  58. {question.type === 'short_answer' && (
  59. <textarea
  60. className="w-full min-h-24 p-2 border rounded"
  61. placeholder="Enter your answer..."
  62. value={answers[question.id] || ''}
  63. onChange={(e) => handleAnswerChange(question.id, e.target.value)}
  64. />
  65. )}
  66. </CardContent>
  67. </Card>
  68. ))}
  69. {mode === 'autonomous' && (
  70. <div className="flex justify-end">
  71. <Button>Submit Answers</Button>
  72. </div>
  73. )}
  74. </div>
  75. </div>
  76. );
  77. }