# 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