# Implementation Plan: Mejoras de Rendimiento - Formularios de Contratos

**Feature Branch**: `009-mejoras-rendimiento-contratos`

**Created**: 2026-07-03

**Status**: Draft

**Input**: `spec.md`

> **Constitution (II. Skinny Controllers, IV. Inertia.js Frontera)**: Este plan define CÓMO se implementará la funcionalidad en Laravel + React.

## User Review Required

- **Inertia Lazy vs API Endpoint:** ¿Prefieres que los catálogos pesados (como la lista completa de clientes) se carguen mediante `Inertia::lazy()` bajo demanda tras pintar la vista inicial, o prefieres implementar un endpoint de búsqueda (Search API) que el frontend consulte asíncronamente con debounce? El endpoint es mucho más escalable si la lista de clientes es gigantesca (> 5000).

## Proposed Changes

### Backend Services & Controllers (Laravel)

#### [MODIFY] `app/Http/Controllers/ContratosController.php`
- **FCP Rápido (US 1)**: Modificar `createContrato()`, `createContratoMultiPunto()` y los métodos de edición. Reemplazar la asignación directa de catálogos inmensos (particularmente `clientes`) usando `Inertia::lazy(fn () => $this->catalogoCache->getClientes())` o eliminándolos de las props iniciales si se decide por un endpoint de búsqueda separado.
- Esto permite renderizar el esqueleto del formulario (Inertia view) sin bloquearse por peticiones pesadas a la base de datos o caché.

### Frontend Pages & Components (React + Inertia)

#### [MODIFY] `resources/js/Pages/Eneon/Contratos/UniClienteUniPunto/Contrato.tsx` (y variantes como MultiCliente)
- **Gestión de Lazy Props (US 1)**: Modificar el componente principal de la página para que llame a `router.reload({ only: ['clientes'] })` una vez montado el componente, si se usa carga lazy.
- **Feedback visual de envío (US 3)**: Asegurar que se utiliza `useForm()` y pasar el flag booleano `processing` a los componentes hijos que renderizan los botones (por ejemplo, `FormActions`).

#### [MODIFY] `resources/js/Pages/Eneon/Contratos/FormActions.tsx` (o donde vivan los botones de acción)
- **Submit Seguro (US 3)**: Bindear el botón de guardar/tramitar a la propiedad `processing`.
  ```tsx
  <PrimaryButton disabled={processing}>
    {processing ? <LoadingSpinner /> : 'Guardar Contrato'}
  </PrimaryButton>
  ```

#### [MODIFY] `resources/js/Components/Common/TypeaheadCliente.tsx` (o equivalente usado en el formulario)
- **Selectores fluidos (US 2)**: 
  - Si el componente usa `react-select`, configurarlo con `react-select-async-paginate` (si se usa API) o aplicar virtualización (ej. `react-window`) para renderizar únicamente los elementos visibles en el viewport y no saturar el DOM con miles de opciones.
  - Añadir debounce de al menos `300ms` a los eventos onSearch/onChange para evitar sobrecarga del hilo principal al teclear.

## Verification Plan

### Manual Verification
1. Abrir la consola de red (Network) y la pestaña de Performance en Chrome.
2. Navegar a crear un nuevo contrato y verificar que el HTML (document) llega antes de 500ms y los catálogos grandes se resuelven en un request secundario.
3. Teclear rápido en el campo de "Cliente" y validar que no hay "long tasks" (cuadros rojos en Chrome Profiler).
4. Dar clic en "Guardar" y verificar que el botón se deshabilita instantáneamente impidiendo un segundo clic.
