From 54306be1c21905a03b275b7eb239ac1474f437cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Ben=C3=ADtez?= Date: Tue, 7 Jul 2026 22:02:19 -0300 Subject: [PATCH] Etapa 4.5 entregada. --- sprints/sprint-8/ETAPA_4_5_PROMPT.md | 266 +++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 sprints/sprint-8/ETAPA_4_5_PROMPT.md diff --git a/sprints/sprint-8/ETAPA_4_5_PROMPT.md b/sprints/sprint-8/ETAPA_4_5_PROMPT.md new file mode 100644 index 0000000..fa609e3 --- /dev/null +++ b/sprints/sprint-8/ETAPA_4_5_PROMPT.md @@ -0,0 +1,266 @@ +# Sprint 8 — Etapa 4.5: Fixes de navegación e InQuality + +> **Tipo:** UI — fixes puntuales +> **Rama:** main +> **Estimación:** 1 hora +> **Dependencias:** Etapa 4 completada ✅ + +--- + +## Objetivo + +Dos fixes independientes detectados en validación de Etapa 4: + +1. **InQuality invisible en admin:** `OrganizationsPage` filtra con `.eq('is_provider', false)`, dejando fuera a InQuality. El equipo no puede gestionar sus propias áreas ni procesos desde el panel. Fix: mostrar todas las orgs, con un badge visual para InQuality. + +2. **Back button sin contexto de org:** En el workspace, el botón "← Solar Banco" (o cualquier org) navega a `/library` sin parámetros — el usuario llega al home genérico en lugar de la sección de esa org. Fix: pasar `?org=` al navegar y hacer scroll al bloque correcto en LibraryPage. + +--- + +## Fix 1: `OrganizationsPage.tsx` + +### Problema actual + +Línea en `fetchOrgs()`: +```typescript +.eq('is_provider', false) +``` + +Esta condición excluye a InQuality (que tiene `is_provider = true`) de la lista. El equipo de InQuality no puede entrar a `/admin/organizations/:id` de su propia org para gestionar áreas y procesos. + +### Cambios en `OrganizationsPage.tsx` + +**1A. Extender la interface `OrgRow`:** + +```typescript +interface OrgRow { + id: string + name: string + is_provider: boolean // 🆕 + created_at: string + processes: [{ count: number }] + users: [{ count: number }] +} +``` + +**1B. Actualizar `fetchOrgs()` — quitar el filtro y agregar `is_provider` al select:** + +```typescript +const fetchOrgs = async () => { + const { data } = await supabase + .from('organizations') + .select('id, name, is_provider, created_at, processes:processes(count), users:users(count)') + // ← eliminar el .eq('is_provider', false) + .order('name') + + // Ordenar: proveedor primero, luego clientes alfabético + const sorted = ((data as OrgRow[] | null) ?? []).sort((a, b) => { + if (a.is_provider && !b.is_provider) return -1 + if (!a.is_provider && b.is_provider) return 1 + return a.name.localeCompare(b.name) + }) + + setOrgs(sorted) + setLoading(false) +} +``` + +**1C. Actualizar el título:** + +```tsx +// Antes: +

Organizaciones clientes

+ +// Después: +

Organizaciones

+``` + +**1D. Agregar badge "Proveedor" en la columna de nombre:** + +En la fila de la tabla, en la celda de nombre: +```tsx + +
+ {org.name} + {org.is_provider && ( + + InQuality + + )} +
+ +``` + +No cambiar el botón "Ver detalle →" — funciona igual para InQuality que para cualquier otra org. + +--- + +## Fix 2: Back button con contexto de org + +Son tres cambios coordinados: `router.tsx`, `WorkspacePage.tsx`, y `LibraryPage.tsx`. + +### Fix 2A: `router.tsx` — declarar `org` como search param de `/library` + +TanStack Router requiere que los search params estén declarados en la ruta para que `navigate({ search: ... })` sea type-safe. + +```typescript +// Antes: +const libraryRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/library', + component: LibraryPage, +}) + +// Después: +const libraryRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/library', + component: LibraryPage, + validateSearch: (search: Record) => ({ + org: typeof search.org === 'string' ? search.org : undefined, + }), +}) +``` + +**NO tocar** `indexRoute` (`/`) — no necesita el param porque nunca se navega a `/` desde el workspace. + +### Fix 2B: `WorkspacePage.tsx` — pasar org en `handleBack` + +```typescript +// Antes (línea ~194-196): +function handleBack() { + void navigate({ to: '/library' }) +} + +// Después: +function handleBack() { + void navigate({ + to: '/library', + search: currentProcess.orgId ? { org: currentProcess.orgId } : {}, + }) +} +``` + +### Fix 2C: `LibraryPage.tsx` — leer param y hacer scroll + +**Imports:** agregar `useLocation` al import existente de `@tanstack/react-router`: + +```typescript +// Antes: +import { useNavigate } from '@tanstack/react-router' + +// Después: +import { useNavigate, useLocation } from '@tanstack/react-router' +``` + +**Leer el param** (agregar dentro del cuerpo de `LibraryPage`, junto a los otros hooks): + +```typescript +const location = useLocation() +const orgParam = useMemo( + () => new URLSearchParams(location.search).get('org') ?? undefined, + [location.search] +) +``` + +`useMemo` ya está importado en el archivo. + +**Efecto de scroll** (agregar después de los efectos existentes): + +```typescript +// Scroll a la sección del org si venimos del workspace +useEffect(() => { + if (!orgParam || isLoading || processes.length === 0) return + requestAnimationFrame(() => { + const el = document.getElementById(`org-section-${orgParam}`) + el?.scrollIntoView({ behavior: 'smooth', block: 'start' }) + }) +}, [orgParam, isLoading, processes.length]) +``` + +**Agregar `id` al div de cada org en el bloque admin** (en el `orgGroups.map(...)`): + +```tsx +// Antes: +
+ +// Después: +
+``` + +Solo en el div raíz de cada org (el que tiene el `key={orgId}`). No tocar divs internos. + +--- + +## Lo que NO cambia en esta etapa + +- **`src/features/admin/OrganizationDetailPage.tsx`** — sin cambios; el detalle de InQuality ya funciona una vez que aparece en la lista. +- **`src/store/library-store.ts`** — sin cambios. +- **Cualquier otro archivo** — sin cambios. + +--- + +## Criterios de validación + +### Fix 1 — InQuality visible +- [ ] La página `/admin/organizations` muestra a InQuality en la lista +- [ ] InQuality aparece primero (antes que las orgs clientes) +- [ ] InQuality tiene el badge naranja "InQuality" +- [ ] Al hacer click en "Ver detalle →" de InQuality, lleva a su detalle con procesos, usuarios y áreas +- [ ] Las otras orgs clientes siguen apareciendo igual que antes + +### Fix 2 — Back button con scroll +- [ ] Abrir un proceso de "Solar Banco" → workspace → botón "← Solar Banco" → navega a `/library?org=` +- [ ] Al llegar a `/library`, la página hace scroll automático al bloque de "Solar Banco" +- [ ] El bloque de "Solar Banco" está expandido (todas las orgs empiezan expandidas por default) +- [ ] Si el proceso no tiene org (edge case), el back button va a `/library` sin param y no hay scroll + +### Técnicos +- [ ] `npm run build` sin errores TypeScript +- [ ] `npm run test` sin regresiones (596 tests) + +--- + +## Restricciones explícitas + +- **NO agregar** `validateSearch` a `indexRoute` (`/`) — solo a `libraryRoute` +- **NO modificar** `OrganizationDetailPage.tsx` en esta etapa +- **NO cambiar** el comportamiento del botón "Nueva organización" — InQuality se crea con `is_provider: false`, InQuality nunca se crea desde la UI (es dato de seeding) +- **NO agregar** tests en esta etapa + +--- + +## Archivos autorizados a modificar + +``` +src/ +├── router.tsx ← validateSearch en libraryRoute +├── features/ +│ ├── workspace/ +│ │ └── WorkspacePage.tsx ← handleBack con search: { org } +│ ├── library/ +│ │ └── LibraryPage.tsx ← useLocation + scroll effect + id en org divs +│ └── admin/ +│ └── OrganizationsPage.tsx ← quitar filtro is_provider + badge + título +``` + +--- + +## Commits esperados + +``` +fix(admin): InQuality visible en OrganizationsPage con badge — quitar filtro is_provider +fix(workspace): handleBack pasa ?org=orgId para scroll contextual en biblioteca +fix(library): scroll a sección de org al volver del workspace con ?org param +``` + +--- + +## Reporte esperado + +1. Confirmar que InQuality aparece en la lista de organizaciones con el badge +2. Confirmar que el back button del workspace pasa `?org=` en la URL +3. Confirmar que la biblioteca hace scroll al bloque correcto al recibir el param +4. `npm run build` y `npm run test` (con conteo) +5. **Solicitar validación visual del director** en los dos fixes antes del OK formal