159 lines
5.3 KiB
TypeScript
159 lines
5.3 KiB
TypeScript
"use client";
|
|
|
|
import type { Ajuda, Anexo, Pergunta, Resposta } from "@prisma/client";
|
|
import { Controller, useFormContext } from "react-hook-form";
|
|
import { AjudaButton } from "@/components/ajuda/AjudaButton";
|
|
import { AnexoField } from "@/components/form/AnexoField";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
|
|
type PerguntaComAjuda = Pergunta & {
|
|
ajuda: Ajuda | null;
|
|
anexos?: Anexo[];
|
|
respostas?: Resposta[];
|
|
};
|
|
|
|
type Props = {
|
|
briefingId: string;
|
|
pergunta: PerguntaComAjuda;
|
|
index: number;
|
|
readOnly?: boolean;
|
|
};
|
|
|
|
type FormValues = {
|
|
perguntas: Record<
|
|
string,
|
|
{
|
|
texto?: string;
|
|
selecionadas?: string[];
|
|
complemento?: string;
|
|
}
|
|
>;
|
|
};
|
|
|
|
function getOpcoes(pergunta: PerguntaComAjuda) {
|
|
return Array.isArray(pergunta.opcoes)
|
|
? pergunta.opcoes.filter((opcao): opcao is string => typeof opcao === "string")
|
|
: [];
|
|
}
|
|
|
|
export function PerguntaField({ briefingId, pergunta, index, readOnly = false }: Props) {
|
|
const form = useFormContext<FormValues>();
|
|
const fieldName = `perguntas.${pergunta.id}`;
|
|
const opcoes = getOpcoes(pergunta);
|
|
const texto = form.watch(`${fieldName}.texto`) ?? "";
|
|
|
|
return (
|
|
<section className="rounded-lg border bg-card p-4 shadow-sm">
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="space-y-1">
|
|
<div className="flex items-center gap-2">
|
|
<Badge variant="muted">{index + 1}</Badge>
|
|
<Label className="text-base leading-6">{pergunta.rotulo}</Label>
|
|
</div>
|
|
{pergunta.dica ? <p className="text-sm leading-6 text-muted-foreground">{pergunta.dica}</p> : null}
|
|
</div>
|
|
<div className="shrink-0">
|
|
<AjudaButton
|
|
rotulo={pergunta.rotulo}
|
|
ajuda={pergunta.ajuda}
|
|
allowTextShortcuts={pergunta.tipo === "TEXTAREA"}
|
|
onUseShortcut={(value) =>
|
|
form.setValue(`${fieldName}.texto`, value, { shouldDirty: true })
|
|
}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-4 space-y-3">
|
|
{pergunta.tipo === "TEXTAREA" ? (
|
|
<>
|
|
<div className="flex flex-wrap gap-2">
|
|
{["Nao se aplica", "A definir"].map((atalho) => (
|
|
<button
|
|
key={atalho}
|
|
type="button"
|
|
className="rounded-md border px-2.5 py-1 text-xs font-medium text-muted-foreground transition hover:bg-muted"
|
|
onClick={() => form.setValue(`${fieldName}.texto`, atalho, { shouldDirty: true })}
|
|
>
|
|
{atalho}
|
|
</button>
|
|
))}
|
|
</div>
|
|
<Textarea {...form.register(`${fieldName}.texto`)} rows={5} />
|
|
<p className="text-right text-xs text-muted-foreground">{String(texto).length} caracteres</p>
|
|
</>
|
|
) : null}
|
|
|
|
{pergunta.tipo === "RADIO" ? (
|
|
<Controller
|
|
control={form.control}
|
|
name={`${fieldName}.selecionadas`}
|
|
render={({ field }) => (
|
|
<RadioGroup
|
|
value={field.value?.[0] ?? ""}
|
|
onValueChange={(value) => field.onChange(value ? [value] : [])}
|
|
>
|
|
{opcoes.map((opcao) => (
|
|
<label key={opcao} className="flex items-center gap-3 rounded-md border p-3 text-sm">
|
|
<RadioGroupItem value={opcao} />
|
|
{opcao}
|
|
</label>
|
|
))}
|
|
</RadioGroup>
|
|
)}
|
|
/>
|
|
) : null}
|
|
|
|
{pergunta.tipo === "CHECKBOX" ? (
|
|
<Controller
|
|
control={form.control}
|
|
name={`${fieldName}.selecionadas`}
|
|
render={({ field }) => {
|
|
const selected = field.value ?? [];
|
|
|
|
return (
|
|
<div className="grid gap-2">
|
|
{opcoes.map((opcao) => (
|
|
<label key={opcao} className="flex items-center gap-3 rounded-md border p-3 text-sm">
|
|
<Checkbox
|
|
checked={selected.includes(opcao)}
|
|
onCheckedChange={(checked) => {
|
|
field.onChange(
|
|
checked ? [...selected, opcao] : selected.filter((value) => value !== opcao)
|
|
);
|
|
}}
|
|
/>
|
|
{opcao}
|
|
</label>
|
|
))}
|
|
</div>
|
|
);
|
|
}}
|
|
/>
|
|
) : null}
|
|
|
|
{pergunta.tipo === "ANEXO" ? (
|
|
<AnexoField
|
|
briefingId={briefingId}
|
|
perguntaId={pergunta.id}
|
|
anexos={pergunta.anexos ?? []}
|
|
readOnly={readOnly}
|
|
/>
|
|
) : null}
|
|
|
|
{pergunta.permiteComplemento ? (
|
|
<div className="space-y-2">
|
|
<Label htmlFor={`complemento-${pergunta.id}`}>Complemento / outro</Label>
|
|
<Input id={`complemento-${pergunta.id}`} {...form.register(`${fieldName}.complemento`)} />
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|