- CiudadSelectField: autocomplete sobre Object.keys(geoData[depto]), mismo patrón que BarrioAutocompleteField (position:fixed, getBoundingClientRect, scroll listener, teclado ARIA). Reutiliza clases CSS .barrio-autocomplete-*. - Limpia el valor de 2.2 via useEffect cuando cambia departamento (2.1), usando un ref estable para onChange para evitar dep cíclica. - QuestionRenderer: branch code==='2.2' dentro del bloque single_choice; pasa answers['2.1:default'] como prop departamento. - Sin cambios al seed, form-engine ni RPCs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
130 lines
3.2 KiB
TypeScript
130 lines
3.2 KiB
TypeScript
'use client'
|
|
import type { AnswerValue, FormAnswers, Question, QuestionOption } from '@/lib/form-engine.types'
|
|
import { RadioGroup } from './widgets/radio-group'
|
|
import { CheckboxGroup } from './widgets/checkbox-group'
|
|
import { TextAreaField } from './widgets/text-area-field'
|
|
import { TextShortField } from './widgets/text-short-field'
|
|
import { BarrioAutocompleteField } from './widgets/barrio-autocomplete-field'
|
|
import { CiudadSelectField } from './widgets/ciudad-select-field'
|
|
|
|
interface QuestionRendererProps {
|
|
question: Question
|
|
value: AnswerValue
|
|
onChange: (value: AnswerValue) => void
|
|
error?: string
|
|
answers?: FormAnswers
|
|
}
|
|
|
|
const YES_NO_OPTIONS: QuestionOption[] = [
|
|
{ value: 'true', label: 'Sí' },
|
|
{ value: 'false', label: 'No' },
|
|
]
|
|
|
|
export function QuestionRenderer({ question, value, onChange, error, answers }: QuestionRendererProps) {
|
|
const { code, type, prompt, required, max_select, options } = question
|
|
const legend = (
|
|
<>
|
|
<span className="q-code">{code} ·</span> {prompt}
|
|
</>
|
|
)
|
|
|
|
if (type === 'single_choice' && options) {
|
|
if (code === '2.2') {
|
|
return (
|
|
<CiudadSelectField
|
|
name={code}
|
|
label={legend}
|
|
value={(value as string) ?? ''}
|
|
required={required}
|
|
departamento={(answers?.['2.1:default'] as string) ?? null}
|
|
onChange={onChange}
|
|
error={error}
|
|
/>
|
|
)
|
|
}
|
|
return (
|
|
<RadioGroup
|
|
name={code}
|
|
legend={legend}
|
|
options={options}
|
|
value={(value as string) ?? undefined}
|
|
required={required}
|
|
onChange={onChange}
|
|
error={error}
|
|
/>
|
|
)
|
|
}
|
|
|
|
if (type === 'multiple_choice' && options) {
|
|
return (
|
|
<CheckboxGroup
|
|
name={code}
|
|
legend={legend}
|
|
options={options}
|
|
value={(value as string[]) ?? []}
|
|
maxSelect={max_select}
|
|
required={required}
|
|
onChange={onChange}
|
|
error={error}
|
|
/>
|
|
)
|
|
}
|
|
|
|
// yes_no resuelto con el RadioGroup existente — dos opciones fijas, sin widget nuevo.
|
|
if (type === 'yes_no') {
|
|
return (
|
|
<RadioGroup
|
|
name={code}
|
|
legend={legend}
|
|
options={YES_NO_OPTIONS}
|
|
value={(value as string) ?? undefined}
|
|
required={required}
|
|
onChange={onChange}
|
|
error={error}
|
|
/>
|
|
)
|
|
}
|
|
|
|
if (type === 'text_short') {
|
|
if (code === '2.3') {
|
|
return (
|
|
<BarrioAutocompleteField
|
|
name={code}
|
|
label={legend}
|
|
value={(value as string) ?? ''}
|
|
required={required}
|
|
departamento={(answers?.['2.1:default'] as string) ?? null}
|
|
ciudad={(answers?.['2.2:default'] as string) ?? null}
|
|
onChange={onChange}
|
|
error={error}
|
|
/>
|
|
)
|
|
}
|
|
return (
|
|
<TextShortField
|
|
name={code}
|
|
label={legend}
|
|
value={(value as string) ?? ''}
|
|
required={required}
|
|
onChange={onChange}
|
|
error={error}
|
|
/>
|
|
)
|
|
}
|
|
|
|
if (type === 'text_long') {
|
|
return (
|
|
<TextAreaField
|
|
name={code}
|
|
label={legend}
|
|
value={(value as string) ?? ''}
|
|
required={required}
|
|
onChange={onChange}
|
|
error={error}
|
|
/>
|
|
)
|
|
}
|
|
|
|
return null
|
|
}
|