# Estado de cambios y controles compactos del portal de prestadores

**Fecha:** 2026-08-24

**Proyecto:** `web_mycode`

**Alcance:** portal privado de prestadores

**API:** sin cambios

## Objetivo

Evitar acciones de guardado cuando un formulario no tiene cambios pendientes y corregir los controles visualmente desproporcionados de horarios y excepciones. La solución debe ser consistente en los formularios editables del portal, conservar la accesibilidad nativa y respetar el sistema visual bilingüe de MyCode.

## Problemas observados

1. Los botones de guardado permanecen habilitados aunque el formulario esté intacto.
2. Los botones `Quitar fila` ocupan demasiado espacio y compiten visualmente con la acción principal.
3. Los controles `Cerrado` y `Atención 24 horas` quedan sobre sus textos porque una regla general de etiquetas gana por especificidad.
4. Aplicar la corrección sólo a excepciones dejaría comportamientos contradictorios en otros formularios de edición del mismo portal.

## Alcance funcional

Se incorporará control de estado modificado en los formularios que persisten información ya cargada:

- identidad del prestador;
- categorías y categoría principal;
- sucursales;
- servicios de una sucursal;
- horario semanal;
- excepciones de horario;
- especialidades;
- atributos;
- contactos existentes.

Quedan fuera de este control las acciones que crean o ejecutan una operación nueva y no representan la edición de un estado precargado:

- login, registro, recuperación y segundo factor;
- formulario para agregar un contacto nuevo;
- carga de logo, portada e imágenes de sucursal;
- envío de verificaciones;
- envío del perfil a revisión.

Estas exclusiones conservan sus reglas actuales de validación y disponibilidad.

## Modelo de estado

Cada formulario editable tendrá una instantánea base canónica de sus controles persistibles. El estado se evaluará con cuatro condiciones independientes:

- **editable:** el usuario y el estado del recurso permiten modificarlo;
- **prístino:** los valores actuales coinciden con la instantánea base;
- **modificado:** al menos un valor, fila, selección o eliminación difiere de la base;
- **ocupado:** existe una solicitud de guardado en curso.

La acción de guardar estará habilitada únicamente cuando el formulario sea editable, esté modificado y no esté ocupado.

### Construcción de la instantánea

La instantánea incluirá, en orden de aparición, el nombre, tipo y valor persistible de cada `input`, `select` y `textarea`. Para `checkbox` y `radio` se utilizará el estado `checked`. Se excluirán botones, tokens, mensajes de error, indicadores de carga y cualquier dato que no forme parte del contrato enviado al servidor.

El orden de filas se conservará porque puede ser significativo en horarios, excepciones y elementos ordenables. Se usará una serialización determinista para que editar y luego devolver un campo a su valor original restaure el estado prístino.

### Transiciones

- Al renderizar o cargar datos, se captura la base y el botón queda deshabilitado.
- `input` y `change` recalculan el estado; agregar o quitar una fila también lo recalcula.
- Una respuesta exitosa reemplaza la base con el estado confirmado por el servidor y vuelve a deshabilitar el guardado.
- Una respuesta fallida conserva el formulario modificado y permite reintentar.
- Cambiar de prestador, sucursal o contexto descarta la base anterior y crea una nueva después de renderizar los datos correctos.
- El estado ocupado deshabilita temporalmente los controles según la política existente y usa cursor de espera.

La implementación se concentrará en una utilidad compartida y pequeña, integrada con la política existente de formularios y las funciones de renderizado/guardado. No se duplicará lógica de comparación en cada vista.

## Diseño visual y accesibilidad

### Botones de guardado

- Prístino: deshabilitado, apariencia atenuada y cursor `not-allowed`.
- Modificado: acción primaria azul existente.
- Ocupado: deshabilitado con cursor `wait` e indicador actual.
- No se agregará texto nuevo sólo para indicar “sin cambios”; el estado deshabilitado evita ruido visual y no requiere nuevas traducciones.

### Quitar fila

- Botón píldora coral de peligro, compacto y de ancho intrínseco.
- No se estirará para completar la columna ni siquiera en la grilla de horarios.
- En pantallas pequeñas podrá reubicarse, pero conservará tamaño compacto.
- Mantendrá texto y semántica de botón existentes en español e inglés.

### Checkbox y radio

- Tamaño uniforme de `20px × 20px`.
- Control y texto permanecerán en una fila, centrados verticalmente.
- Toda la etiqueta seguirá siendo clicable mediante asociación nativa.
- Una regla específica del bloque de operaciones evitará que el estilo general `display: grid` de las etiquetas desarme la alineación.
- El foco, el estado seleccionado y el contraste seguirán siendo perceptibles sin depender exclusivamente del color.

## Internacionalización

El comportamiento no depende del idioma. Se reutilizarán las etiquetas ES/EN existentes. Si durante la implementación aparece la necesidad real de un mensaje visible nuevo, deberá incorporarse simultáneamente en ambos catálogos antes de considerar terminado el cambio.

## Manejo de errores y seguridad

- No se almacenarán valores del formulario fuera del navegador ni se enviarán solicitudes adicionales para detectar cambios.
- Los errores del servidor conservarán el estado modificado y los mensajes seguros actuales.
- No se incluirán tokens, archivos ni datos auxiliares sensibles en la instantánea.
- El mecanismo no sustituye la validación de cliente ni de servidor; sólo controla la disponibilidad de la acción.

## Verificación

Se agregarán pruebas enfocadas en:

1. estado inicial prístino y guardado deshabilitado;
2. habilitación al editar, seleccionar, agregar o quitar;
3. retorno a prístino al deshacer manualmente un cambio;
4. retorno a prístino después de una respuesta exitosa;
5. permanencia modificada después de un error;
6. reinicio correcto al cambiar de prestador o sucursal;
7. exclusión de formularios de acción nueva;
8. tamaño, alineación y especificidad CSS de botones compactos y controles de selección;
9. conservación de las etiquetas en español e inglés;
10. compilación de assets, auditoría de arquitectura y suite completa de PHP/JavaScript.

## Criterios de aceptación

- Ningún formulario editable incluido permite guardar sin cambios pendientes.
- Cualquier modificación real habilita su acción y una reversión exacta vuelve a deshabilitarla.
- Un guardado exitoso establece una nueva base; un fallo permite reintentar.
- `Quitar fila` se ve como acción secundaria compacta y coral.
- `Cerrado` y `Atención 24 horas` muestran control y texto alineados horizontalmente con controles de al menos `20px`.
- Login, creación, cargas, verificaciones y envío a revisión mantienen su disponibilidad funcional actual.
- No se requieren cambios ni despliegue en `api_mycode`.
