# F-123 — Editor de producto: quitar gate, reorder y selector de peso en gramos

## Diagnóstico

F-121 (`a40d78d`) y F-107 (reorder previo) fueron fixes parciales:

1. **Gate "Guarda primero" sigue activo**: `ProductEditor.tsx` líneas 286 y 374 mantienen los `div` con el warning. F-121 solo cambió el flujo post-save (`router.push → router.replace` + `setProductId`), no eliminó los textos. Bundle live `15z1dcv3uvf3z.js` aún contiene "Guarda primero" (1 ocurrencia).
2. **Reorder incompleto**: Marca / Canal / Caducidad están en `ProductEditor.tsx` **después** de Descripción. El operador quiere esos campos **antes** de Descripción, justo debajo de Peso unitario.
3. **Peso unitario en kg con input libre**: actualmente `<input type="text" value={unitWeightKg}>` con label "Peso unitario (kg)". El operador quiere:
   - Label "Peso unitario (Gr)"
   - Select dropdown con valores [100, 150, 200, 250, 300, 350, 500, 740, custom]
   - Al elegir "custom" mostrar input libre en gramos
   - Convertir a kg al guardar (dividir por 1000)

## Diseño

### Cambios

1. **`ProductEditor.tsx`** — Eliminar los dos bloques condicionales `{productId ? <Section/> : <Warning/>}`. Renderizar siempre:
   - `<PriceStockSection productId={productId} />` (productId puede ser undefined)
   - `<ImagesSection productId={productId} />` (idem)

2. **`PriceStockSection.tsx`** — Aceptar `productId?: string`:
   - Si `productId` es undefined → renderizar el formulario con inputs activos, **pero** desactivar los botones de guardado y mostrar caption "Se guardará al crear el producto".
   - Si `productId` definido y la variante aún no carga → mantener el warning actual de "no datos internos de venta".
   - Si `productId` definido y variante cargada → comportamiento normal.

3. **`ImagesSection.tsx`** — Aceptar `productId?: string`:
   - Si `productId` undefined → mostrar UI con inputs/área de drop deshabilitados y caption.
   - Si `productId` definido → comportamiento normal.

### Garantías

- Sin cambios en backend.
- Sin cambios en tipos del API client.
- Los productos ya creados siguen funcionando idéntico (productId siempre truthy → mismo path que antes).
- Para nuevos productos: el operador puede escribir precio, stock, EAN y planificar imágenes desde el inicio; al pulsar "Crear producto" el bundle se persiste (precio/stock/EAN se guardan con `setVariantPrice`/`setStock`/`updateVariant` tras crear el id; las imágenes vía upload + POST /products/:id/images). El caption avisa que los botones de guardado individual están inactivos hasta tener id.

### Riesgos

- Bajo. Cambios puramente UI. Sin migraciones, sin API, sin tipos.

## Plan de implementación

1. Editar `ProductEditor.tsx`:
   - Quitar los dos bloques de warning.
   - Renderizar siempre `<PriceStockSection>` y `<ImagesSection>`.
   - **Mover** el bloque Marca/Canal/Caducidad a estar **después** de `<PriceStockSection>` y **antes** de Descripción.
2. Editar `PriceStockSection.tsx`:
   - Prop opcional `productId?: string` + flag `pending`.
   - Early return si pending → renderizar UI deshabilitada.
   - Reemplazar input libre de peso por `<select>` con opciones [100,150,200,250,300,350,500,740,custom]. Custom muestra input auxiliar.
   - Convertir gramos → kg al llamar API.
3. Editar `ImagesSection.tsx`:
   - Prop opcional `productId?: string`.
   - Estado pending → renderizar UI deshabilitada con caption.
4. `npx tsc --noEmit` en `apps/admin`.
5. `npm run build` en `apps/admin`.
6. Reiniciar admin (`monolith.sh prod restart`).
7. Verificar bundle servido: `curl /products/new | grep "Guarda primero"` → 0 ocurrencias; HTML contiene el dropdown.
8. Cerrar gates.