Instrumento v2: 44 preguntas + widget text_short

This commit is contained in:
markosbenitez
2026-06-04 14:30:28 -03:00
parent 10c665d25c
commit d91ea6b2ff
11 changed files with 765 additions and 751 deletions

View File

@@ -4,6 +4,7 @@ import { RadioGroup } from './widgets/radio-group'
import { CheckboxGroup } from './widgets/checkbox-group'
import { RatingScale } from './widgets/rating-scale'
import { TextAreaField } from './widgets/text-area-field'
import { TextShortField } from './widgets/text-short-field'
interface QuestionRendererProps {
question: Question
@@ -72,7 +73,20 @@ export function QuestionRenderer({
)
}
if (type === 'text_long' || type === 'text_short') {
if (type === 'text_short') {
return (
<TextShortField
name={code}
label={prompt}
value={(answers[code] as string) ?? ''}
required={required}
onChange={(v) => onChange(code, v)}
error={error}
/>
)
}
if (type === 'text_long') {
return (
<TextAreaField
name={code}

View File

@@ -35,16 +35,22 @@ function formatAnswer(question: Question, raw: FormAnswers[string]): string {
return String(raw)
}
// Section titles by first question code prefix
// Section titles by code prefix ('A', '1', '2', …)
const SECTION_TITLES: Record<string, string> = {
A: 'Datos Generales',
B: '¿Vivís con discapacidad?',
C: 'Familiares con Discapacidad',
D: 'Adultos Mayores a Cargo',
E: 'Tu Rol como Cuidador/a',
F: 'Impacto Económico',
G: 'Bienestar y Descanso',
H: 'Necesidades',
'1': 'Prevalencia: cuidado y discapacidad',
'2': 'Intensidad y rol del cuidado',
'3': 'Impacto económico del cuidado',
'4': 'Tiempo y descanso',
'5': 'Impacto en el trabajo',
'6': 'Conciencia organizacional',
'7': 'Para cerrar',
}
// 'A1' → 'A', '1.1' → '1', '6.4' → '6', '7.1' → '7'
function getSectionPrefix(code: string): string {
const m = code.match(/^([A-Za-z]+|\d+)/)
return m ? m[1] : code
}
export function SummaryScreen({
@@ -72,7 +78,7 @@ export function SummaryScreen({
<dl className="summary-list">
{visibleQuestions.map((q) => {
const section = q.code.replace(/\d+$/, '')
const section = getSectionPrefix(q.code)
const showHeader = section !== lastSection
lastSection = section

View File

@@ -8,19 +8,23 @@ import { QuestionRenderer } from './question-renderer'
import { SummaryScreen } from './summary-screen'
// Section metadata (code prefix → display title)
// Prefixes: 'A' for A1-A7, '1' for 1.1-1.16, '2' for 2.1-2.5, etc.
const SECTIONS: { prefix: string; title: string; sensitive?: boolean }[] = [
{ prefix: 'A', title: 'Datos Generales' },
{ prefix: 'B', title: '¿Vivís con discapacidad?', sensitive: true },
{ prefix: 'C', title: 'Familiares con Discapacidad', sensitive: true },
{ prefix: 'D', title: 'Adultos Mayores a Cargo', sensitive: true },
{ prefix: 'E', title: 'Tu Rol como Cuidador/a' },
{ prefix: 'F', title: 'Impacto Económico' },
{ prefix: 'G', title: 'Bienestar y Descanso' },
{ prefix: 'H', title: 'Necesidades' },
{ prefix: '1', title: 'Prevalencia: cuidado y discapacidad', sensitive: true },
{ prefix: '2', title: 'Intensidad y rol del cuidado' },
{ prefix: '3', title: 'Impacto económico del cuidado' },
{ prefix: '4', title: 'Tiempo y descanso' },
{ prefix: '5', title: 'Impacto en el trabajo' },
{ prefix: '6', title: 'Conciencia organizacional' },
{ prefix: '7', title: 'Para cerrar' },
]
function getSectionPrefix(code: string) {
return code.replace(/\d+$/, '')
// Extracts the leading alpha or numeric segment from a question code.
// 'A1' → 'A', '1.1' → '1', '1.16' → '1', '6.4' → '6', '7.1' → '7'
function getSectionPrefix(code: string): string {
const m = code.match(/^([A-Za-z]+|\d+)/)
return m ? m[1] : code
}
interface SurveyFormProps {

View File

@@ -0,0 +1,50 @@
'use client'
interface TextShortFieldProps {
name: string
label: string
value: string
required: boolean
placeholder?: string
onChange: (value: string) => void
error?: string
}
export function TextShortField({
name,
label,
value,
required,
placeholder = '',
onChange,
error,
}: TextShortFieldProps) {
return (
<div className="question-fieldset">
<label className="question-legend" htmlFor={name}>
{label}
{required && <span className="required-mark" aria-hidden="true"> *</span>}
{required && <span className="sr-only"> (obligatorio)</span>}
</label>
<input
type="text"
id={name}
name={name}
value={value}
required={required}
aria-required={required}
aria-describedby={error ? `${name}-error` : undefined}
aria-invalid={!!error}
placeholder={placeholder}
onChange={(e) => onChange(e.target.value)}
className="text-short-input"
autoComplete="off"
/>
{error && (
<p role="alert" className="field-error" id={`${name}-error`}>
{error}
</p>
)}
</div>
)
}