- Introduced `page-layouts.md` to outline approved page patterns for progressive adoption. - Created `visual-system-design.md` to consolidate visual, architectural, and adoption decisions for a uniform UI/UX system in the ERP frontend. - Added `RdxEditorActionBar` component for managing action bars in editor screens. - Implemented `RdxPanel` component for grouping related content with optional headers and actions.
7.7 KiB
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 yDataTable; - 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
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
SkeletonDataTableen carga inicial. - Detail y Update usan skeleton de editor.
- Errores bloqueantes usan
PageErrorStatecon reintento y regreso. - Errores de mutación usan
ErrorAlerty 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;DataTable,SkeletonDataTable,DataTableColumnHeader,RdxRowActions;TextField,SelectField,PageFormHeader,FormActionsBar;SimpleSearchInput,PageErrorState,ErrorAlert;UnsavedChangesProvideryuseReturnToNavigation.
18. Componentes Supplier específicos
SuppliersGridy sus columnas, porque expresan identidad y acciones Supplier;SupplierStatusBadge, limitado al status del dominio;SupplierEditorFormy 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 => borrarno soportada.
20. Plan de implementación
- Corregir API PATCH, keys, adapters y estrategia de caché.
- Registrar manifest y rutas Supplier.
- Implementar listado y navegación.
- Implementar detalle.
- Implementar formulario compartido y Create.
- Implementar Update con
dirtyFields. - Añadir recursos
esyen. - Revisar responsive y accesibilidad.
- Añadir tests de mappers, PATCH parcial y rutas.
- 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.