175 lines
7.7 KiB
Markdown
175 lines
7.7 KiB
Markdown
# 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 `RdxPageFrame`, 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`, `RdxPageContent`, `RdxPageHeader`, `RdxPageActions`;
|
|
- `RdxPageFrame`, `RdxPanel`, `RdxFormGrid`;
|
|
- `DataTable`, `SkeletonDataTable`, `DataTableColumnHeader`, `RdxRowActions`;
|
|
- `TextField`, `SelectField`, `RdxEditorHeader`, `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.
|