# Drill-down genérica — sort por nombre emisor/receptor
## Contexto
La tabla de la página `/drill-down` (apps/web/app/(dashboard)/drill-down/page.tsx)
actualmente permite ordenar por `Fecha`, `Total MXN`, `Monto Pago` e `IVA Trasl.`
mediante el hook `useTableSort` y el componente `SortableHeader` de
`@horux/shared-ui`. Las columnas `Nombre Emisor` y `Nombre Receptor` se
renderizan como `
` planos no ordenables.
## Objetivo
Permitir ordenar también por nombre del emisor y por nombre del receptor,
sin remover ninguna de las columnas ordenables existentes.
Alcance limitado a la drill-down genérica. Las 9 páginas de `/alertas/*` quedan
fuera de este cambio (decisión del owner — se evaluarán después).
## Cambios
Archivo único: `apps/web/app/(dashboard)/drill-down/page.tsx`.
1. Extender el segundo parámetro de tipo de `useTableSort` para incluir las
nuevas keys:
```ts
useTableSort
```
2. Agregar dos accesores al objeto pasado al hook:
```ts
emisor: (c) => c.nombreEmisor || '',
receptor: (c) => c.nombreReceptor || '',
```
`useTableSort` ya soporta accesores de tipo `string` — usa
`String.prototype.localeCompare` cuando ambos valores son strings, lo cual
maneja la collation del español correctamente.
3. Reemplazar los dos `| ` planos por `SortableHeader`:
```tsx
// antes
| Nombre Emisor |
Nombre Receptor |
// después
toggleSort('emisor')} />
toggleSort('receptor')} />
```
4. Mantener el `initialKey = 'fecha'` y `initialDir = 'desc'` (default actual).
## No-cambios
- No se tocan: `useTableSort`, `SortableHeader`, ni cualquier otro archivo en
`@horux/shared-ui`.
- No se tocan controllers ni services del API. El sort es 100% client-side.
- No se tocan las columnas RFC Emisor, RFC Receptor, UUID, Comp., M. Pago,
Reg. E ni Reg. R — siguen siendo `` planos no ordenables.
- No se modifica el export a Excel: ya consume `sortedData`, así que el orden
vigente del usuario se respeta automáticamente.
## Comportamiento esperado
- Click sobre "Nombre Emisor": ordena ascendente por nombre. Re-click:
descendente. Cambia el sort activo (un solo sort a la vez, ya es el
contrato del hook).
- Click sobre "Nombre Receptor": idéntico, reemplaza al sort previo.
- Filas con `nombreEmisor` o `nombreReceptor` null/undefined: el accesor
retorna string vacío `''`, así que en `asc` aparecen primero. Es el
comportamiento estándar de `localeCompare` y se considera aceptable
(un CFDI sin nombre emisor/receptor es raro y debería ser visible al
ordenar por nombre).
## Riesgo
Mínimo:
- Cambio puramente client-side, una sola página, ~6 líneas netas.
- No introduce dependencias nuevas.
- `pnpm typecheck` debería seguir limpio (las nuevas keys están dentro del
union genérico, los accesores cumplen el contrato `(row: T) => number | string`).
## Plan de pruebas (smoke)
1. `pnpm typecheck` debe seguir en 0 errores.
2. Abrir `/drill-down` desde cualquier KPI del dashboard.
3. Click en "Nombre Emisor" → verificar orden alfabético ascendente y flecha
en el header. Re-click → descendente.
4. Click en "Nombre Receptor" → mismo comportamiento.
5. Click en "Fecha" / "Total MXN" → confirmar que los sorts pre-existentes
siguen funcionando.
6. Exportar a Excel después de ordenar por "Nombre Emisor" → confirmar que
el archivo descargado mantiene el mismo orden.
## Pendientes derivados
- Replicar el patrón en las 9 páginas de `/alertas/*` (cancelaciones,
cancelaciones-periodo-anterior, efectivo, tipo-relacion-sospechosa,
concentracion-clientes, concentracion-proveedores, discrepancia-regimen,
lista-negra-clientes, lista-negra-proveedores). Decisión del owner cuándo
abordarlas. Para `lista-negra-*` además habrá que introducir
`useTableSort` desde cero (hoy no lo usan).
| |