spec 02 aprobada
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
# SPEC 02 — Niños: listado y perfil (`/kids` y `/kids/[slug]`)
|
||||
|
||||
> **Estado:** Aprobado
|
||||
> **Depende de:** SPEC 01
|
||||
> **Fecha:** 2026-10-20
|
||||
> **Objetivo:** Implementar las plantillas `references/pantallas/ninos.dc.html` y `references/pantallas/perfil-nino.dc.html` como `/kids` y `/kids/[slug]`, visualmente idénticas, con mock de 8 niños con ficha completa y buscador funcional.
|
||||
|
||||
## Alcance
|
||||
|
||||
**In:**
|
||||
|
||||
- Página `/kids` (`app/kids/page.tsx`): sidebar con "Niños" activo, encabezado (eyebrow "GESTIÓN" + título "Niños"), botón "Agregar niño" (→ `/agregar-nino`), buscador y grilla de 2 columnas con las 8 tarjetas de la plantilla.
|
||||
- Buscador **funcional** (filtro client-side): filtra por nombre mientras se escribe, el contador "8 niños" se actualiza y muestra estado vacío si no hay coincidencias.
|
||||
- Página `/kids/[slug]` (`app/kids/[slug]/page.tsx`): breadcrumb "Volver a Niños" (→ `/kids`), avatar 84px + nombre + "3 años · Sala Soles", botón "Editar" (→ `/agregar-nino`), recuadro naranja "Alergias y notas" (solo si el niño tiene notas), tarjeta de datos (nacimiento / sala / ingreso), columna derecha con botón "Resumen del día" (→ `/resumen-dia`), tarjeta "PADRES VINCULADOS" (badges ACTIVA/PENDIENTE) y link "Vincular otro padre" (→ `/vincular-padre`).
|
||||
- Las 8 fichas de perfil existen: cada slug renderiza los datos propios del niño (nombre, avatar, alergias, fechas y padres), coherentes con la lista.
|
||||
- Mock tipado en `app/data/kids.ts` con los 8 niños de la plantilla (Mateo con los datos exactos del perfil; los otros 7 con datos inventados coherentes con su fila de la lista).
|
||||
- Componentes nuevos en `app/components/`: `KidCard.tsx` (tarjeta de la lista) y `KidsBrowser.tsx` (cliente: buscador + contador + grilla + estado vacío).
|
||||
- Update de `app/components/Sidebar.tsx`: el link "Niños" pasa de `/ninos` a `/kids` (única referencia existente; SPEC 01 la cableó así).
|
||||
- Hover de tarjeta según plantilla: borde `#F2A78E` + `translateY(-2px)` con transición de 150ms.
|
||||
|
||||
**Out of scope (para specs futuras):**
|
||||
|
||||
- Páginas `/agregar-nino`, `/vincular-padre` y `/resumen-dia` (hoy dan 404 y está bien).
|
||||
- Alta/edición real de niños y vinculación real de padres.
|
||||
- Autenticación, base de datos y persistencia.
|
||||
- Responsive móvil y dark mode.
|
||||
|
||||
## Modelo de datos
|
||||
|
||||
```ts
|
||||
// app/data/kids.ts
|
||||
export type ParentStatus = "activa" | "pendiente";
|
||||
|
||||
export interface Parent {
|
||||
name: string; // "Lucía Fernández"
|
||||
role: string; // "Mamá" | "Papá"
|
||||
initial: string; // "L"
|
||||
bg: string; // "#C9B6E8"
|
||||
status: ParentStatus; // badge ACTIVA (verde) | PENDIENTE (amarillo)
|
||||
}
|
||||
|
||||
export interface Kid {
|
||||
slug: string; // "mateo-fernandez"
|
||||
name: string; // "Mateo Fernández"
|
||||
initial: string; // "M"
|
||||
avatar: { bg: string; text: string }; // { bg: "#A9D9E8", text: "#1F7A93" }
|
||||
age: number; // 3 → se renderiza "3 años"
|
||||
allergies: string[]; // ["MANÍ"] — badges de la lista (vacos = sin badge)
|
||||
allergyNote?: string; // texto del recuadro del perfil (si existe → se muestra)
|
||||
birthDate: string; // "12 mar 2022"
|
||||
room: string; // "Soles"
|
||||
admission: string; // "feb 2025"
|
||||
parents: Parent[];
|
||||
}
|
||||
```
|
||||
|
||||
- Los 8 niños con sus colores exactos de la plantilla: Mateo `#A9D9E8/#1F7A93`, Sofía `#F4B8CC/#C44A7A`, Benjamín `#B9DEC4/#3E8B62`, Valentina `#F4DC8E/#9A7B1E`, Tomás `#C9B6E8/#7B5FC0`, Emma `#F4B8CC/#C44A7A`, Lucas `#A9D9E8/#1F7A93`, Olivia `#B9DEC4/#3E8B62`.
|
||||
- Regla del badge lateral en la lista (deducida de la plantilla): sin padres → badge "VINCULAR" (`#F9D2DE`/`#C56486`); con alergia → primera alergia (`#FBD8CC`/`#D9684A`); resto → chevron `#CBB89F`.
|
||||
- Padres de Mateo (exactos de la plantilla): Lucía Fernández (Mamá, `#C9B6E8`, activa) y Diego Fernández (Papá, `#A9C7E8`, pendiente "invitación enviada").
|
||||
|
||||
Convenciones heredadas de SPEC 01: colores como hex exactos en utilities Tailwind arbitrarias; cero atributos `style`; todo server components salvo `KidsBrowser`.
|
||||
|
||||
## Plan de implementación
|
||||
|
||||
1. **Mock** — crear `app/data/kids.ts` con los tipos y los 8 niños. Test manual: `npm run dev` compila.
|
||||
2. **KidCard** — crear `app/components/KidCard.tsx`: avatar circular, nombre, "X años · N padre(s) vinculado(s)", badge según la regla y link a `/kids/[slug]` con hover de plantilla. Test manual: se ve correcta suelta en cualquier página temporal.
|
||||
3. **KidsBrowser (cliente)** — crear `app/components/KidsBrowser.tsx`: input "Buscar niño…", fila "SALA SOLES + contador + línea divisoria", grilla `grid-cols-2` filtrada por nombre (comparación sin mayúsculas ni acentos vía `normalize("NFD")`) y mensaje de estado vacío.
|
||||
4. **Página /kids** — crear `app/kids/page.tsx`: Sidebar `activeHref="/kids"`, encabezado, botón "Agregar niño" y `<KidsBrowser kids={kids}>`. Test manual: `http://localhost:3000/kids` muestra las 8 tarjetas y el filtro funciona.
|
||||
5. **Sidebar** — en `app/components/Sidebar.tsx` cambiar el href de "Niños" de `/ninos` a `/kids`. Test manual: el link navega y ninguna página queda rota.
|
||||
6. **Página /kids/[slug]** — crear `app/kids/[slug]/page.tsx` con `generateStaticParams` y `notFound()`: en Next.js 16 `params` es una Promise (`const { slug } = await params`). Layout de dos columnas (columna izquierda flexible + derecha fija de 300px), ficha completa, recuadro de alergias condicionado y tarjeta de padres con badges ACTIVA/PENDIENTE. Test manual: `/kids/mateo-fernandez` replica la plantilla y `/kids/valentina-soto` muestra su ficha sin recuadro de alergias ni padres.
|
||||
7. **Fidelidad visual** — comparación lado a lado de ambas pantallas contra las plantillas a ancho ≥1280px; ajustar diferencias. Capturas de verificación en `.playwright-mcp/`.
|
||||
|
||||
## Criterios de aceptación
|
||||
|
||||
- [ ] `npm run dev` levanta sin errores y `/kids` muestra eyebrow "GESTIÓN", título "Niños", botón "Agregar niño", buscador y las 8 tarjetas en grilla de 2 columnas.
|
||||
- [ ] `npm run build` completa sin errores, incluyendo el prerender de `/kids` y de los 8 slugs.
|
||||
- [ ] Escribir "sof" en el buscador deja solo la tarjeta de Sofía Méndez, el contador se actualiza y escribir algo sin coincidencias muestra el estado vacío.
|
||||
- [ ] Escribir "sofia" (sin acento) también encuentra a Sofía Méndez.
|
||||
- [ ] Cada tarjeta enlaza con `<Link>` al slug de su niño (8 hrefs distintos) y el badge es correcto: Mateo "MANÍ", Tomás "LACTOSA", Valentina "VINCULAR", resto chevron.
|
||||
- [ ] `/kids/mateo-fernandez` replica la plantilla: breadcrumb, avatar 84px "M", nombre, "3 años · Sala Soles", botón "Editar", recuadro "Alergias y notas" con el texto exacto ("Alergia al maní. Evitar frutos secos. Lleva inhalador en la mochila."), filas nacimiento/sala/ingreso, botón "Resumen del día" y tarjeta "PADRES VINCULADOS" con Lucía (ACTIVA, verde) y Diego (PENDIENTE, amarillo) + "Vincular otro padre".
|
||||
- [ ] Los otros 7 slugs muestran la ficha propia de cada niño (nombre, avatar, edad, padres y alergias coherentes con la lista); Valentina no tiene recuadro de alergias ni padres listados.
|
||||
- [ ] `/kids/no-existe` responde 404.
|
||||
- [ ] En el sidebar, "Niños" apunta a `/kids` y aparece activo (fondo `#FBE3D8`, texto `#D9583C`) tanto en `/kids` como en `/kids/[slug]`; en `/` sigue activo "Feed".
|
||||
- [ ] Los links futuros del perfil navegan con `<Link>`: Editar → `/agregar-nino`, Resumen del día → `/resumen-dia`, Vincular otro padre → `/vincular-padre` (hoy 404, aceptado).
|
||||
- [ ] A ancho ≥1280px ambas pantallas coinciden con las plantillas: lista con contenido centrado de 880px y perfil de 820px con columna derecha de 300px.
|
||||
- [ ] Los archivos nuevos no usan atributos `style`; todo es Tailwind con valores arbitrarios exactos.
|
||||
|
||||
## Decisiones
|
||||
|
||||
- **Sí:** rutas `/kids` y `/kids/[slug]` — decisión explícita del usuario aunque el sidebar decía `/ninos`; se actualiza `Sidebar.tsx` (única referencia, así ningún criterio de SPEC 01 queda huérfano sin notarlo).
|
||||
- **Sí:** los 8 niños con ficha completa en `app/data/kids.ts` — el perfil es una página por slug real, no un placeholder clonado.
|
||||
- **Sí:** datos inventados para los otros 7 perfiles, pero coherentes con la lista (misma edad, misma cantidad de padres, mismas alergias); solo Mateo conserva los datos literales de la plantilla.
|
||||
- **Sí:** buscador funcional con un único componente cliente (`KidsBrowser`) — es la primera pieza interactiva del repo y queda aislada; el resto sigue siendo server components.
|
||||
- **Sí:** búsqueda solo por nombre, insensible a mayúsculas y acentos — la plantilla dice "Buscar niño…" y en español los acentos son el caso de uso obvio.
|
||||
- **Sí:** regla de badge deducida de la plantilla (sin padres → VINCULAR, con alergia → alergia, resto → chevron) — los 3 casos existen en el diseño original.
|
||||
- **Sí:** recuadro de alergias solo cuando `allergyNote` existe — la plantilla no define cómo se ve un perfil sin alergias y omitirlo es lo más fiel.
|
||||
- **Sí:** perfil compuesto directo en `page.tsx` sin componentes de un solo uso — solo se extraen `KidCard` y `KidsBrowser`, que se reutilizan o aíslan estado.
|
||||
- **Sí:** `generateStaticParams` + `notFound()` — mock estático: los 8 slugs se prerenderizan y cualquier otro slug da 404 real.
|
||||
- **No:** filtrar por sala, edad o alergia — no está en la plantilla.
|
||||
- **No:** páginas `/agregar-nino`, `/vincular-padre` ni `/resumen-dia` — specs futuras.
|
||||
|
||||
## Riesgos
|
||||
|
||||
| Riesgo | Mitigación |
|
||||
| --- | --- |
|
||||
| El buscador cliente rompe la convención server-only del repo | `KidsBrowser` aísla el estado; `KidCard` sigue siendo puro y reutilizable |
|
||||
| Búsqueda lenta o hidratación inconsistente al filtrar | Filtrado en memoria sobre 8 items; el grid se deriva del mismo array tipado |
|
||||
| Links a páginas inexistentes confunden en la verificación | Documentado en Out of scope y en criterios: 404 esperado, igual que SPEC 01 |
|
||||
|
||||
## Qué **no** está en esta spec
|
||||
|
||||
- Páginas agregar/editar niño, vincular padre y resumen del día — cada una en su propia spec.
|
||||
- Autenticación, base de datos y persistencia.
|
||||
- Responsive móvil y dark mode.
|
||||
Reference in New Issue
Block a user