From f2666c7d3cfa10e63c13b13abc726036e5f72c77 Mon Sep 17 00:00:00 2001 From: markosbenitez Date: Tue, 23 Jun 2026 21:43:52 -0300 Subject: [PATCH] Con las mejoras visuales --- components/survey-form.tsx | 274 ------------------------------------- 1 file changed, 274 deletions(-) delete mode 100644 components/survey-form.tsx diff --git a/components/survey-form.tsx b/components/survey-form.tsx deleted file mode 100644 index d670522..0000000 --- a/components/survey-form.tsx +++ /dev/null @@ -1,274 +0,0 @@ -'use client' -import { useCallback, useEffect, useRef, useState, useTransition } from 'react' -import type { FormAnswers, Question, Survey } from '@/lib/types' -import { clearDraft, loadDraft, saveDraft } from '@/lib/storage' -import { getHiddenCodes, isQuestionVisible, ruleQuestionCodes } from '@/lib/conditional' -import { submitSurvey } from '@/app/actions/submit-survey' -import { ConsentScreen } from './consent-screen' -import { ProgressBar } from './progress-bar' -import { QuestionRenderer } from './question-renderer' - -// Section metadata (code prefix → display title) -const SECTIONS: { prefix: string; title: string }[] = [ - { prefix: 'A', title: 'Datos Generales' }, - { prefix: '1', title: 'Prevalencia: cuidado y discapacidad' }, - { 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): string { - const m = code.match(/^([A-Za-z]+|\d+)/) - return m ? m[1] : code -} - -type FormStage = 'consent' | 'form' | 'success' | 'error' - -interface SurveyFormProps { - survey: Survey - questions: Question[] -} - -export function SurveyForm({ survey, questions }: SurveyFormProps) { - const [stage, setStage] = useState('consent') - const [consentOperativo, setConsentOperativo] = useState(false) - const [consentMacroN1, setConsentMacroN1] = useState(false) - const [answers, setAnswers] = useState({}) - const [errors, setErrors] = useState>({}) - const [submitError, setSubmitError] = useState(null) - const [isPending, startTransition] = useTransition() - const [a11yAnnounce, setA11yAnnounce] = useState('') - const [hydrated, setHydrated] = useState(false) - const prevAnswers = useRef({}) - - // Hydrate from localStorage on mount - useEffect(() => { - const draft = loadDraft(survey.id) - if (Object.keys(draft).length > 0) setAnswers(draft) - setHydrated(true) - }, [survey.id]) - - // Persist to localStorage after hydration - useEffect(() => { - if (!hydrated) return - saveDraft(survey.id, answers) - prevAnswers.current = answers - }, [answers, hydrated, survey.id]) - - const handleChange = useCallback( - (code: string, value: FormAnswers[string]) => { - setAnswers((prev) => { - const updated = { ...prev, [code]: value } - const toHide = getHiddenCodes(code, value, questions, prev) - for (const hiddenCode of toHide) { - updated[hiddenCode] = undefined as unknown as FormAnswers[string] - } - if (toHide.length > 0) { - setA11yAnnounce('Se ocultaron preguntas relacionadas y se limpiaron sus respuestas.') - } else { - const appeared = questions.some( - (q) => - q.conditional_rules?.some((r) => ruleQuestionCodes(r).includes(code)) && - isQuestionVisible(q, updated) && - !isQuestionVisible(q, prev) - ) - if (appeared) setA11yAnnounce('Aparecieron nuevas preguntas según tu respuesta.') - } - return updated - }) - setErrors((prev) => { - if (!prev[code]) return prev - const { [code]: _, ...rest } = prev - return rest - }) - }, - [questions] - ) - - function validate(): boolean { - const newErrors: Record = {} - for (const q of questions) { - if (!q.required) continue - if (!isQuestionVisible(q, answers)) continue - const val = answers[q.code] - if (val === null || val === undefined || val === '' || (Array.isArray(val) && val.length === 0)) { - newErrors[q.code] = 'Este campo es obligatorio.' - } - } - setErrors(newErrors) - return Object.keys(newErrors).length === 0 - } - - function handleSubmit(e: React.FormEvent) { - e.preventDefault() - if (isPending) return - if (!validate()) { - const firstErrorCode = Object.keys(errors)[0] - if (firstErrorCode) document.getElementById(firstErrorCode)?.focus() - return - } - - const questionMap = Object.fromEntries(questions.map((q) => [q.code, q.id])) - - startTransition(async () => { - const result = await submitSurvey({ - surveyId: survey.id, - answers: answers as Record, - questionMap, - consentOperativo, - consentMacroN1, - }) - if (result.success) { - clearDraft(survey.id) - setStage('success') - } else { - setSubmitError(result.error) - setStage('error') - } - }) - } - - // ── Stage: consent ────────────────────────────────────────── - if (stage === 'consent') { - return ( - { - setConsentOperativo(op) - setConsentMacroN1(macro) - setStage('form') - }} - /> - ) - } - - // ── Stage: success ────────────────────────────────────────── - if (stage === 'success') { - return ( -
-
-

¡Gracias por participar!

-

- Tu respuesta fue registrada correctamente. Recordá que la encuesta es anónima: no hay - forma de vincular tus respuestas con tu identidad. -

-

- Los resultados agregados ayudarán a {survey.brand_config?.org_name ?? 'tu empresa'} a - diseñar mejores apoyos para las personas cuidadoras. -

-
-
- ) - } - - // ── Stage: error ──────────────────────────────────────────── - if (stage === 'error') { - return ( -
-
-

No se pudo enviar la encuesta

-

Hubo un error al guardar tus respuestas ({submitError}). Podés intentarlo de nuevo.

- -
-
- ) - } - - // ── Stage: form ───────────────────────────────────────────── - const visibleQuestions = questions.filter((q) => isQuestionVisible(q, answers)) - const answeredCount = visibleQuestions.filter((q) => { - const v = answers[q.code] - return v !== null && v !== undefined && v !== '' && !(Array.isArray(v) && v.length === 0) - }).length - - type Section = { prefix: string; title: string; questions: Question[] } - const sectionMap = new Map() - for (const q of visibleQuestions) { - const prefix = getSectionPrefix(q.code) - if (!sectionMap.has(prefix)) { - const meta = SECTIONS.find((s) => s.prefix === prefix) - sectionMap.set(prefix, { prefix, title: meta?.title ?? prefix, questions: [] }) - } - sectionMap.get(prefix)!.questions.push(q) - } - - const bc = survey.brand_config - - return ( -
- Ir al formulario - -
- {a11yAnnounce} -
- - {/* Header contextual con org/branch si está configurado */} - {bc?.org_name && ( -
-

- Estás respondiendo esto porque pertenecés a {bc.org_name} - {bc.branch_name && ( - <> y participás en las oficinas de {bc.branch_name} - {bc.branch_city && <> en {bc.branch_city}}. - )} -

-
- )} - -
-

{survey.title}

-

Esta encuesta es anónima. Tus respuestas no te identifican.

-
- -
- -
- -
-
- {Array.from(sectionMap.values()).map((section) => ( -
-
-

Sección {section.prefix} · {section.title}

-
- {section.questions.map((q) => ( -
- -
- ))} -
- ))} - -
- -
-
-
-
- ) -}