> ## Documentation Index
> Fetch the complete documentation index at: https://omniloy.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Modal de vista previa de inserción

> Permite al médico revisar, curar y editar un informe generado dentro del SDK antes de que llegue a tu aplicación

La **vista previa de inserción** (insertion preview) es un modal interno del SDK que permite al médico revisar, curar y editar un informe generado **antes** de que se devuelva a tu aplicación. Cuando está activo, un informe entrante abre una vista previa donde cada campo puede seleccionarse, editarse o completarse; luego el médico hace clic en **Aplicar** y tu app recibe el payload curado a través del callback `onReportApply`.

Esta página explica cómo **activarlo**, **desactivarlo** y **usarlo**.

<Info>
  El mismo modal se reutiliza para curar **acciones clínicas (extras)** — peticiones, citas, pruebas, derivaciones — por un canal paralelo. Ahí el gate es `showInsertionPreview` **y** la presencia de `templateExtras` (en lugar de `template`), y al **Aplicar** los items van a `handleExtras`. Ver [Acciones clínicas (Extras)](/sofia/es/sdk/extras).
</Info>

## Cómo encaja en el flujo

<Steps>
  <Step title="Grabación → Detener">
    Cuando el médico detiene la grabación, un auto-review en segundo plano borronea un informe. El borrador **no se muestra todavía** — espera, igual que el botón **Generar**.
  </Step>

  <Step title="El usuario hace clic en Generar (o Regenerar)">
    El modal **nunca se abre solo** desde el auto-review en segundo plano. Espeja el botón Generar y espera un **clic del usuario**. Todo resultado iniciado por el usuario —incluso tras una generación automática fallida— abre el modal.
  </Step>

  <Step title="Curar en el modal">
    La vista previa se abre con los campos del informe. El médico puede seleccionar, editar o completar cada uno. Los campos **obligatorios** bloquean **Aplicar** hasta que se completen.
  </Step>

  <Step title="Aplicar → onReportApply(curado)">
    Al hacer clic en **Aplicar**, tu app recibe el payload curado —solo los campos que el médico dejó o editó— vía `onReportApply`. Tu app lo inserta en el EHR/HIS.
  </Step>
</Steps>

<Info>
  Si la función está **desactivada**, un informe entrante pasa directo a tu callback `handleReport` (comportamiento legacy) — el modal no se renderiza.
</Info>

## Activar el modal

El modal tiene **dos canales independientes**: uno para informes y otro para [acciones clínicas (extras)](/sofia/es/sdk/extras). Cada uno se activa solo cuando se cumplen **sus dos** condiciones. Ambos comparten el mismo flag de backend, pero cada uno tiene su propio esquema:

| Canal        | Flag de backend              | Esquema requerido                       | Se cura al **Aplicar** por |
| ------------ | ---------------------------- | --------------------------------------- | -------------------------- |
| **Informes** | `showInsertionPreview: true` | `template` (o la deprecada `toolsargs`) | `onReportApply`            |
| **Extras**   | `showInsertionPreview: true` | `templateExtras`                        | `handleExtras`             |

```
informes activos = showInsertionPreview (backend, por API key)  Y  template presente
extras activos   = showInsertionPreview (backend, por API key)  Y  templateExtras presente
```

El flag `showInsertionPreview` es **por API key** y común a ambos canales. Los esquemas son independientes: puedes activar el modal solo para informes (`template`), solo para extras (`templateExtras`), o para los dos.

### Activar el flag de backend

El flag es **por API key** y vive en tus ajustes de perfil de Omniloy (`showInsertionPreview`). **No** puedes activarlo desde el frontend — contacta a [support@omniloy.com](mailto:support@omniloy.com) para que lo activen para tu key. Hasta que sea `true`, el SDK ignora el modal por completo y cae en `handleReport`.

### Pasar un template

El `template` es el JSON Schema que describe la estructura del informe (el mismo esquema usado para generarlo). **Debe** estar presente para que el modal se abra. Consulta [Esquemas de datos clínicos](/sofia/es/sdk/templates).

## Desactivar el modal (opt-out)

El modal está **apagado por defecto** — solo aparece cuando se cumplen *ambas* condiciones de activación de arriba. No hay un interruptor "off" especial: hacer que **cualquiera** de las condiciones sea falsa lo desactiva. Tienes dos palancas independientes:

| Palanca             | Cómo                                                                                                           | Efecto                                                                                                                                                                                                                    |
| ------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Flag de backend** | Deja `showInsertionPreview` en `false` para tu API key (el default), o pide a Omniloy que lo ponga en `false`. | Interruptor autoritativo, por API key. La generación de informes sigue funcionando; los informes van directo a `handleReport`.                                                                                            |
| **Sin `template`**  | No pases la prop `template` (ni la deprecada `toolsargs`).                                                     | Opt-out del lado del cliente. **Ojo:** el template también habilita la generación de informes — sin él, los botones Generar/Regenerar también quedan ocultos. Usa esto solo si tampoco quieres la generación de informes. |

Cuando está desactivado, los informes generados se entregan a tu callback **`handleReport`** como antes — sin modal, sin paso de curación. Este es el comportamiento legacy.

<Warning>
  **Mantén `handleReport` cableado incluso cuando actives el modal.** Es el camino de fallback: si el flag de backend está apagado (o quitas el template), tu integración sigue recibiendo informes sin cambiar una línea de código.
</Warning>

### Errores comunes al activarlo/desactivarlo

<AccordionGroup>
  <Accordion title="No existe ninguna prop ni atributo HTML que active/desactive la función">
    En algún código de demo aparece un atributo `show-insertion-preview` — es un **no-op**: el SDK nunca lo lee. Las únicas palancas de activación/desactivación son el flag de backend `showInsertionPreview` y la presencia de `template`.
  </Accordion>

  <Accordion title="Omitir onReportApply no desactiva el modal">
    Si la función está activa, el modal igual se abre; al **Aplicar** simplemente cae en `handleReport` (y avisa por log si no hay ninguno cableado). Para no mostrar el modal, usa una de las dos palancas de arriba.
  </Accordion>

  <Accordion title="Un template vacío igual cuenta como presente">
    El gate solo verifica que `template` sea truthy, así que pasar `{}` (o un objeto sin `properties`) puede abrir un modal **sin campos**. Pasa un JSON Schema real, u omite `template` por completo.
  </Accordion>
</AccordionGroup>

## Usarlo

<CodeGroup>
  ```tsx React theme={null}
  import { Omniscribe } from '@omniloy/sofia-sdk/react';
  import '@omniloy/sofia-sdk/react/index.css';

  <Omniscribe
    apikey={API_KEY}
    userid={USER_ID}
    patientid={PATIENT_ID}
    // Requerido para que el modal se renderice (JSON Schema del informe):
    template={REPORT_TEMPLATE}

    // Se llama cuando el médico hace clic en Aplicar — recibe el payload curado:
    onReportApply={(curated) => {
      // curated: Record<string, unknown> — solo los campos que el médico dejó/editó
      myEhr.insertNote(curated);
    }}

    // Fallback: se usa cuando el modal está desactivado (flag off / sin template):
    handleReport={(report) => {
      myEhr.insertNote(report);
    }}

    // Opcional: acota tu CSS al modal (vive en el shadow DOM del SDK):
    insertionPreviewClassNames={{
      panel: 'my-preview-panel',
      applyButton: 'my-apply-btn',
    }}
  />
  ```

  ```html Web Component theme={null}
  <sofia-sdk id="sofia" apikey="your-api-key" userid="doctor-123" patientid="patient-456"></sofia-sdk>

  <script>
    const el = document.querySelector('#sofia');

    // Props JSON
    el.template = REPORT_TEMPLATE;
    el.insertionPreviewClassNames = { panel: 'my-preview-panel' };

    // Props de función (asigna como propiedades JS, nunca como atributos HTML)
    el.onReportApply = (curated) => myEhr.insertNote(curated);
    el.handleReport = (report) => myEhr.insertNote(report); // fallback
  </script>
  ```
</CodeGroup>

<Info>
  En el web component, `template` e `insertionPreviewClassNames` son **props JSON** y `onReportApply`/`handleReport` son **props de función** — asígnalas como **propiedades JS** del elemento, no como atributos HTML. Las funciones no pueden ir como atributos HTML, y el atributo `template` se elimina del DOM tras leerse (es un dato sensible).
</Info>

### Referencia de props

| Prop                         | Tipo                               | Propósito                                                                                                                         |
| ---------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `template`                   | JSON Schema (`object`)             | **Requerido para activar.** Describe la estructura del informe y las reglas por campo. También impulsa la generación de informes. |
| `onReportApply`              | `(curated: CuratedReport) => void` | Se dispara cuando el médico hace clic en **Aplicar**. Recibe solo los campos que el médico dejó/editó.                            |
| `handleReport`               | `(report: object) => void`         | Entrega de fallback cuando el modal está desactivado. Mantenlo cableado.                                                          |
| `insertionPreviewClassNames` | `InsertionPreviewClassNames`       | Overrides de class-name para las clases internas del modal.                                                                       |
| `toolsargs`                  | JSON Schema (`object`)             | Alias **deprecado** de `template`. Prefiere `template`.                                                                           |

Claves de `InsertionPreviewClassNames` (todas opcionales): `backdrop`, `panel`, `header`, `body`, `footer`, `group`, `row`, `gapRow`, `applyButton`, `cancelButton`.

<Tip>
  El modal se renderiza dentro del **shadow DOM** del SDK, así que el CSS global de la página no lo alcanza. Usa `insertionPreviewClassNames` para adjuntar tus propias clases y luego estilarlas.
</Tip>

Los tipos `CuratedReport` e `InsertionPreviewClassNames` son estructurales (`Record<string, unknown>` y un mapa plano de strings de class-name opcionales) — tipa tus handlers contra esas formas directamente.

### Qué puede hacer el médico en el modal

* **Seleccionar / deseleccionar** campos — solo los campos tildados terminan en el payload curado.
* **Editar** valores inline (texto, prosa, número, booleano, fecha, enum, multi-enum y arrays de objetos).
* **Completar huecos** — los campos vacíos que el template espera se muestran como gaps.
* **Editar con voz** — dictar para refinar campos mientras el modal permanece abierto.
* **Aplicar** — emite `onReportApply(curated)`. Deshabilitado mientras haya algún gap **obligatorio** sin completar.
* **Cancelar** — cierra sin emitir.

## Esquema del template

El `template` es un objeto **JSON Schema** estándar. Además de las palabras clave estándar, el modal entiende:

* **`required`** (estándar) — el agente debería producir el campo cuando pueda.
* **`mandatory`** (palabra clave personalizada) — más fuerte que `required`: el médico **debe** revisarlo/completarlo antes de permitir Aplicar. Los campos obligatorios vacíos se muestran como gaps **bloqueantes** y deshabilitan Aplicar.
* **Los tipos de campo** se infieren del esquema: `string`, `prose` (texto largo), `number`, `boolean`, `date` (vía `pattern`), `enum`, `multi-enum` (array de enums) y `array-of-objects` (con `oneOf` + `discriminator` opcional para variantes por fila).

```json theme={null}
{
  "type": "object",
  "required": ["chief_complaint"],
  "properties": {
    "chief_complaint": { "type": "string" },
    "diagnosis":       { "type": "string", "mandatory": true },
    "follow_up_date":  { "type": "string", "pattern": "^(\\d{4}-\\d{2}-\\d{2})?$" },
    "medications": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": { "type": "string" },
          "dose": { "type": "number" },
          "unit": { "type": "string", "enum": ["mg", "g", "mcg"] }
        }
      }
    }
  }
}
```

<Warning>
  `mandatory` es una pista no estándar que el SDK lee para condicionar Aplicar (`"diagnosis"` arriba bloquea Aplicar hasta completarse). Además, instruye a tu prompt de generación a **no inventar** valores obligatorios — se espera que el médico los confirme.
</Warning>

## Checklist rápido

* [ ] El flag de backend `showInsertionPreview` está en `true` para tu API key (contacta a soporte para activarlo). Es común a ambos canales.
* [ ] **Para informes:** pasas un `template` (JSON Schema), con `onReportApply` cableado para el payload curado y `handleReport` como fallback.
* [ ] **Para extras:** pasas un `templateExtras` (JSON Schema), con `handleExtras` cableado para recibir los items curados. Ver [Acciones clínicas (Extras)](/sofia/es/sdk/extras).
* [ ] (Opcional) `insertionPreviewClassNames` seteado para estilos del lado del host.

<Tip>
  Si el modal no aparece al hacer clic en Generar, verifica ambas condiciones de activación. Con `debug={true}` el SDK loguea el estado del gate: `[InsertionPreview] gate { backend, templatePresent, isEnabled }`.
</Tip>

## Próximos pasos

* **[Esquemas de datos clínicos](/sofia/es/sdk/templates)** — diseña el `template` y usa la palabra clave `mandatory`
* **[Pre-cargar desde tu EMR](/sofia/es/sdk/update-template)** — alimenta contenido ya escrito en la generación con `updateTemplate`
* **[Propiedades opcionales](/sofia/es/sdk/optional-properties)** — referencia completa de callbacks
