import { useCallback, useEffect, useRef, useState, type FormEvent, type KeyboardEvent, } from "react"; import { ArrowPathIcon, ArrowRightIcon, ArrowUturnLeftIcon, CheckIcon, } from "@heroicons/react/20/solid"; import { QuestionType } from "@qltysh/fabro-api-client"; import type { ApiQuestion, ApiQuestionOption, } from "@qltysh/fabro-api-client"; import { useSubmitInterviewAnswer, type SubmitInterviewAnswerArg, } from "../lib/mutations"; import { ApiError } from "../lib/api-client"; import { ErrorMessage } from "./ui"; const PRIMARY_BUTTON = "inline-flex items-center justify-center gap-1.5 rounded-lg bg-teal-500 px-3.5 py-2 text-sm font-medium text-on-primary transition-colors hover:bg-teal-300 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-500 disabled:cursor-not-allowed disabled:opacity-60 disabled:hover:bg-teal-500"; const CHOICE_BUTTON = "inline-flex items-center justify-center gap-1.5 rounded-lg bg-overlay px-3.5 py-2 text-sm font-medium text-fg-2 outline-1 -outline-offset-1 outline-line-strong transition-colors hover:bg-overlay-strong hover:text-fg focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-teal-500 disabled:cursor-not-allowed disabled:opacity-60"; const CHOICE_BUTTON_SELECTED = "inline-flex items-center justify-center gap-1.5 rounded-lg bg-teal-500/15 px-3.5 py-2 text-sm font-medium text-fg outline-1 -outline-offset-1 outline-teal-500/60 transition-colors hover:bg-teal-500/20 focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-teal-500"; type SubmitInterviewAnswer = SubmitInterviewAnswerArg["answer"]; export interface InterviewDockProps { runId: string; questions: ApiQuestion[]; } export function InterviewDock({ runId, questions }: InterviewDockProps) { const [activeIndex, setActiveIndex] = useState(0); const submitMutation = useSubmitInterviewAnswer(runId); const [error, setError] = useState(null); const safeIndex = activeIndex < questions.length ? activeIndex : 0; const question = questions[safeIndex]; useEffect(() => { setError(null); submitMutation.reset(); }, [question?.id, submitMutation.reset]); const submit = useCallback( async (answer: SubmitInterviewAnswer) => { if (!question) return; setError(null); try { await submitMutation.trigger({ questionId: question.id, answer }); } catch (caught) { setError(interviewSubmitErrorMessage(caught)); } }, [question, submitMutation], ); if (!question) return null; const moreCount = questions.length - 1; const submitting = submitMutation.isMutating; return (
setActiveIndex((index) => (index + 1) % questions.length) } />

{question.text}

{questionTypeLabel(question.question_type)}

{question.context_display && ( )} {error && }
); } function DockHeader({ stage, moreCount, onCycle, }: { stage: string; moreCount: number; onCycle: () => void; }) { return (
Awaiting input {stage && ( <> {stage} )}
{moreCount > 0 && ( )}
); } function PulseDot() { return (