/admin/responses: filtro survey dinámico (select, no hardcodeado), paginación 50/página, link a vista detallada, conteos consistentes con el filtro de preguntas permitidas (evita página fantasma al final). /admin/responses/[id]: respuestas agrupadas por sección (derivado de type='section', igual que el wizard — no existen section_number/ section_title, ver TECH-DEBT-011), instancias bajo "Familiar N". RLS y exclusión de sensibles intactos en ambas vistas. Fixes de revisión antes de cerrar: toggle expandir/colapsar movido a un <button> real (evita anidar el link "Ver" dentro de un role=button), formatDate/renderValue unificados en admin-format.ts, queries independientes en paralelo (Promise.all).
28 lines
1006 B
TypeScript
28 lines
1006 B
TypeScript
// Compartido entre la lista (page.tsx) y la vista detallada ([id]/page.tsx) —
|
|
// deben renderizar fecha y valor exactamente igual; antes vivían duplicados
|
|
// en los dos archivos y ya habían divergido.
|
|
|
|
export function formatDate(iso: string): string {
|
|
const d = new Date(iso)
|
|
const pad = (n: number) => String(n).padStart(2, '0')
|
|
return `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
|
}
|
|
|
|
// null/undefined → null (renderizado como badge "sin dato"/"sin respuesta" por el caller)
|
|
export function renderValue(value: unknown, type: string): string | null {
|
|
if (value === null || value === undefined) return null
|
|
|
|
switch (type) {
|
|
case 'single_choice':
|
|
case 'text_short':
|
|
return String(value).replace(/^"|"$/g, '')
|
|
case 'multiple_choice':
|
|
if (Array.isArray(value)) return value.join(', ')
|
|
return String(value)
|
|
case 'rating':
|
|
return String(value)
|
|
default:
|
|
return String(value)
|
|
}
|
|
}
|