FactuGES_ERP/docs/suppliers/frontend-suppliers-ui-ux-design.md

175 lines
7.7 KiB
Markdown
Raw Normal View History

2026-08-24 14:24:58 +00:00
# Frontend de suppliers: diseño e implementación UI/UX
## 1. Objetivo
El frontend de `suppliers` debe ofrecer listado, detalle, creación y edición con el mismo lenguaje visual y los mismos patrones de navegación que `customers`, respetando el contrato funcional más pequeño de Supplier.
Este documento es la fuente normativa para la implementación. La paridad buscada es de arquitectura y experiencia, no de campos ni capacidades de negocio.
## 2. Estado actual
Antes de esta implementación, Supplier solo disponía de entidades frontend, adapters, APIs y hooks de TanStack Query. La sidebar enlazaba a `/suppliers`, pero no existían manifest, rutas, páginas, formularios ni traducciones del módulo.
El API client tenía una incompatibilidad activa: la actualización delegaba en `IDataSource.updateOne()`, que usa PUT, aunque Supplier solo expone PATCH.
## 3. Customer como referencia
Se adoptan de Customer:
- manifest y rutas lazy por módulo;
- páginas de listado con `RdxPageContainer`, `RdxPageHeader`, búsqueda con debounce y `DataTable`;
- editores fullscreen con `RdxEditorPageLayout`, header persistente, protección de cambios sin guardar y secciones Rdx;
- `PageErrorState`, skeletons, alertas y toasts del sistema;
- React Hook Form con validación Zod;
- queries y mutations encapsuladas en hooks y adapters de transporte.
No se copia la fiscalidad, la eliminación, el panel lateral ni las acciones exclusivas de Customer.
## 4. Diferencias funcionales Customer/Supplier
| Área | Customer | Supplier |
| --- | --- | --- |
| Lifecycle | Puede tener capacidades propias | Status solo informativo |
| Eliminación | Existe contrato Customer | No existe DELETE Supplier |
| Fiscalidad | Incluye configuración fiscal | Fuera de alcance |
| Pagos | Puede incluir términos y métodos | Fuera de alcance |
| Dirección | Contrato agrupado en áreas modernas | DTO Supplier plano |
| Actualización | Contrato propio | PATCH parcial, sin `null` para borrar |
## 5. Arquitectura frontend Supplier
```txt
Page
-> controller hook
-> query/mutation hook
-> API function
-> DTO adapter
-> frontend entity
```
Los DTO snake_case quedan limitados a `common`, API y adapters. Páginas, formularios y entidades usan camelCase.
## 6. Rutas
| Ruta | Pantalla | Layout |
| --- | --- | --- |
| `/suppliers` | Listado | `app-sidebar` |
| `/suppliers/create` | Creación | `app-fullscreen` |
| `/suppliers/:id` | Detalle | `app-fullscreen` |
| `/suppliers/:id/edit` | Edición | `app-fullscreen` |
Se adopta `edit`, que es la convención vigente de Customer. No se crean rutas DELETE, activate o deactivate.
## 7. Listado
El listado usa header, descripción, acción principal, `SimpleSearchInput`, tabla server-side y paginación. Las columnas son:
- identidad: nombre, nombre comercial, TIN y tipo empresa/persona;
- referencia;
- contacto principal;
- status no interactivo;
- acciones Ver y Editar.
Solo `name`, `reference` y `email_primary` ofrecen sorting, porque pertenecen a la whitelist real. La búsqueda usa el query param `q`, debounce de 300 ms y reinicia la página.
## 8. Detail
El detalle presenta un header con nombre, contexto secundario y badge de status. Se agrupa en Identificación, Contacto, Dirección y Preferencias. Los valores ausentes muestran `-` para mantener una cuadrícula estable. Las únicas acciones son Volver y Editar.
## 9. Create
Create reutiliza el editor común Supplier y genera el UUID en el cliente. El payload conserva el DTO plano del backend y omite campos opcionales vacíos. Tras éxito actualiza caché, muestra feedback y navega al detalle.
## 10. Update
Update carga el detalle, adapta la entidad al formulario y construye el PATCH desde `dirtyFields`. Solo se envían campos modificados con valor utilizable. Un campo vacío se omite porque el contrato vigente no admite `null => borrar`; la UI no inventa esa semántica.
La petición se realiza explícitamente con método PATCH, nunca con `IDataSource.updateOne()`.
## 11. Formularios y validación
Un único `SupplierFormSchema` en camelCase valida create y update. Se reutilizan schemas semánticos de Core para TIN, país, código postal, idioma, moneda, teléfono y web. Las secciones son Identificación, Dirección, Contacto y Preferencias.
`isCompany` es boolean y usa el selector visual empresa/persona. `status` no forma parte del formulario.
## 12. API / React Query
Las keys separan listado y detalle. Create establece el detalle e invalida listados. Update establece el detalle, parchea filas presentes e invalida listados. El cambio de empresa reutiliza el reset global de queries y el interceptor común que añade `X-Company-Id`.
## 13. Estados loading/error/empty
- List usa `SkeletonDataTable` en carga inicial.
- Detail y Update usan skeleton de editor.
- Errores bloqueantes usan `PageErrorState` con reintento y regreso.
- Errores de mutación usan `ErrorAlert` y toast.
- La tabla conserva el empty state común; una búsqueda sin resultados mantiene visible el buscador.
## 14. Responsive
Header y acciones apilan en móvil. Formularios pasan de dos columnas a una. Las tarjetas de detalle usan una columna en móvil y dos en escritorio. La tabla conserva scroll horizontal y paginación del componente compartido.
## 15. Accesibilidad
Todos los inputs tienen labels asociados mediante los componentes Rdx. Los botones incluyen nombre accesible, los iconos decorativos usan `aria-hidden`, las filas de acciones son navegables y los errores se asocian mediante React Hook Form. El foco se mueve al primer campo inválido.
## 16. i18n
Todos los textos visibles pertenecen al namespace `Suppliers`. Se mantienen recursos completos en `es` y `en`; no se insertan textos de interfaz específicos en componentes.
## 17. Componentes reutilizados
- `RdxPageContainer`, `RdxPageStack`, `RdxPageHeader`, `RdxPageActions`;
- `RdxEditorPageLayout`, `RdxPanel`, `RdxFormGrid`;
2026-08-24 14:24:58 +00:00
- `DataTable`, `SkeletonDataTable`, `DataTableColumnHeader`, `RdxRowActions`;
- `TextField`, `SelectField`, `PageFormHeader`, `FormActionsBar`;
- `SimpleSearchInput`, `PageErrorState`, `ErrorAlert`;
- `UnsavedChangesProvider` y `useReturnToNavigation`.
## 18. Componentes Supplier específicos
- `SuppliersGrid` y sus columnas, porque expresan identidad y acciones Supplier;
- `SupplierStatusBadge`, limitado al status del dominio;
- `SupplierEditorForm` y sus secciones, porque el DTO plano y la ausencia de fiscalidad son específicos;
- páginas y controllers de List, Detail, Create y Update.
No se extraen componentes desde Customer: la similitud visual no justifica acoplar ambos dominios.
## 19. Decisiones descartadas
Quedan expresamente fuera:
- DELETE;
- activate/deactivate y cualquier lifecycle HTTP;
- `paymentTermId`;
- `paymentMethodId`;
- fiscalidad y defaults fiscales;
- integración con `supplier-invoices`;
- edición de status;
- refactor del DTO plano de dirección;
- semántica `null => borrar` no soportada.
## 20. Plan de implementación
1. Corregir API PATCH, keys, adapters y estrategia de caché.
2. Registrar manifest y rutas Supplier.
3. Implementar listado y navegación.
4. Implementar detalle.
5. Implementar formulario compartido y Create.
6. Implementar Update con `dirtyFields`.
7. Añadir recursos `es` y `en`.
8. Revisar responsive y accesibilidad.
9. Añadir tests de mappers, PATCH parcial y rutas.
10. Ejecutar tests, typecheck, lint, build dirigido y checklist manual.
### Checklist manual
- Abrir listado, buscar por nombre, TIN y referencia.
- Ordenar nombre, referencia y email.
- Abrir detalle y navegar a editar.
- Guardar un único campo y confirmar que el PATCH es parcial.
- Guardar `isCompany = false`.
- Crear Supplier y validar errores de formulario/API.
- Confirmar actualización de detail y list.
- Cambiar de empresa y comprobar aislamiento.
- Revisar listado, detalle y formularios en desktop, tablet y móvil.