feat(19-03): create QuestionForm component

- Renders mixed question types from questions array
- Submit disabled until all questions answered
- onSubmit called with Record<string, string> mapping questionId to answer
This commit is contained in:
Lukas May
2026-02-04 21:52:08 +01:00
parent bf3521e3dd
commit 648f9db230

View File

@@ -0,0 +1,91 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { OptionGroup } from "@/components/OptionGroup";
import { FreeTextInput } from "@/components/FreeTextInput";
interface QuestionFormQuestion {
id: string;
question: string;
options?: Array<{ label: string; description?: string }>;
multiSelect?: boolean;
}
interface QuestionFormProps {
questions: QuestionFormQuestion[];
onSubmit: (answers: Record<string, string>) => void;
onCancel: () => void;
isSubmitting?: boolean;
}
export function QuestionForm({
questions,
onSubmit,
onCancel,
isSubmitting = false,
}: QuestionFormProps) {
const [answers, setAnswers] = useState<Record<string, string>>(() => {
const initial: Record<string, string> = {};
for (const q of questions) {
initial[q.id] = "";
}
return initial;
});
function handleAnswerChange(questionId: string, value: string) {
setAnswers((prev) => ({ ...prev, [questionId]: value }));
}
const allAnswered = questions.every(
(q) => answers[q.id] !== undefined && answers[q.id].trim() !== ""
);
function handleSubmit() {
if (allAnswered) {
onSubmit(answers);
}
}
return (
<div className="space-y-6">
{questions.map((q, index) => (
<div key={q.id} className="space-y-2">
<p className="text-sm font-medium">
Q{index + 1}: {q.question}
</p>
{q.options && q.options.length > 0 ? (
<OptionGroup
questionId={q.id}
options={q.options}
multiSelect={q.multiSelect ?? false}
value={answers[q.id] ?? ""}
onChange={(value) => handleAnswerChange(q.id, value)}
/>
) : (
<FreeTextInput
questionId={q.id}
value={answers[q.id] ?? ""}
onChange={(value) => handleAnswerChange(q.id, value)}
/>
)}
</div>
))}
<div className="flex justify-end gap-2 pt-2">
<Button
variant="outline"
onClick={onCancel}
disabled={isSubmitting}
>
Cancel
</Button>
<Button
onClick={handleSubmit}
disabled={!allAnswered || isSubmitting}
>
{isSubmitting ? "Sending..." : "Send Answers"}
</Button>
</div>
</div>
);
}