Widgets
Ruta: /teacher/widgets · Atajo: g w · Sidebar: Widgets
Configuracion de widgets embebibles para insertar en webs externas. Tres tipos de widget con multiples variantes, preview en vivo y codigo de embed copiable.
Que hay
Section titled “Que hay”Layout de filas expandibles
Section titled “Layout de filas expandibles”Tres filas de tipo de widget, cada una muestra:
- Icono + nombre + conteo de variantes
- Descripcion breve
- Analytics resumidas (30 dias): impresiones, CTR, clicks
- Chevron de expansion
Al expandir, se muestra:
Pills de variantes
Section titled “Pills de variantes”Fila de botones pill para cada configuracion guardada. Estrella en la variante por defecto. Boton “Nueva variante” para crear configs adicionales.
Editor + Preview (2 columnas)
Section titled “Editor + Preview (2 columnas)”Columna izquierda — Editor:
- Input de nombre
- Boton “Set Default” (si no es la variante por defecto)
- Formulario de configuracion (segun tipo)
- Boton “Guardar” (deshabilitado si no hay cambios)
- Badge de analytics
- Seccion de codigo embed (copiable)
- Boton “Eliminar” (rojo, con confirmacion)
Columna derecha — Preview (sticky):
- Marco de navegador simulado (puntos rojo/amarillo/verde)
- Iframe en tiempo real con la configuracion actual
- Auto-resize via postMessage
Tipos de widget
Section titled “Tipos de widget”Modos: inline (pagina completa), popup (modal flotante), button (link)
Configuracion:
- Modo de display
- Tema: light / dark / auto
- Idioma: auto / es / en
- Label del boton (popup/button)
- Color del boton (hex picker)
- Posicion (popup): top-left / top-right / bottom-left / bottom-right
- Pre-fill nombre del alumno (opcional)
- Pre-fill email del alumno (opcional)
Configuracion:
- Modo: grid / list
- Columnas: 1, 2, 3
- Mostrar precios: toggle
- Mostrar descripciones: toggle
- Max servicios: numero (0 = sin limite)
- Mostrar tabs: toggle
- Modo tabs: auto (agrupa por estructura) / custom (tabs manuales)
- Seleccion de servicios: checkboxes
- Filtro por estructura (modo auto)
- Tabs custom: label + picker de servicios por tab
Layouts: carousel / grid / list / wall
Configuracion:
- Layout
- Tema: light / dark / auto
- Idioma
- Color de acento (hex)
- Max reviews: 1-50 (default 6)
- Rating minimo: 1-5 estrellas
- Toggles: rating, body, avatar, fecha, quick tags
- Orden: featured / recent / highest-rated
dateFrom(string, opcional): Fecha inicio para filtrar reviews por fecha de creaciondateTo(string, opcional): Fecha fin para filtrar reviews por fecha de creacion
Codigo embed generado
Section titled “Codigo embed generado”| Widget | Formato |
|---|---|
| Booking inline | <iframe> con handler de resize |
| Booking popup | <script> con boton flotante |
| Booking button | <a> con estilos inline |
| Storefront | <iframe> con handler de resize |
| Reviews | <iframe> con altura responsiva |
Pre-fill de campos en booking
Section titled “Pre-fill de campos en booking”El embed de booking soporta pre-rellenar campos del formulario via URL params. Los params se agregan automaticamente al generar el embed code segun lo que el profesor configure en el formulario de configuracion.
| Param URL | Campo |
|---|---|
prefill_name | Nombre del alumno |
prefill_email | Email del alumno |
prefill_service | ID del servicio pre-seleccionado |
Los modos inline y button incluyen los params directamente en la URL del iframe/enlace.
El modo popup soporta pre-fill via atributos data-* en el tag <script>:
<script src="https://pinteach.com/widget.js" data-teacher="maria-garcia" data-prefill-name="Juan Lopez"></script>El script de popup lee los atributos data-prefill-name y data-prefill-email al inicializarse
y los pasa como prefill_name / prefill_email en la URL del iframe interno cuando el popup se abre.
Dirty state protection
Section titled “Dirty state protection”- Deteccion de cambios via serializacion JSON (nombre + config)
- Evento
beforeunloadpara navegacion accidental ConfirmDialogal colapsar fila o cambiar variante con cambios sin guardar
Que falta
Section titled “Que falta”| Feature | Descripcion | Estado | Implementado |
|---|---|---|---|
| Pre-fill en modo popup | El script de popup acepta atributos data-prefill-name y data-prefill-email y los pasa al iframe interno. El embed code los incluye automaticamente | ✅ | Batch 3 |
| A/B testing de variantes | Se pueden crear multiples variantes pero no hay forma de comparar rendimiento entre ellas. Deberia haber dashboard de comparacion con metricas por variante | Implementado ✅ | |
| Custom CSS injection | Textarea en config del widget para CSS personalizado. Sanitizacion XSS (bloquea @import, url(), expression(), javascript:). Endpoint GET /:slug/widget-css?configId=xxx retorna CSS como text/css. Iframes lo inyectan via <style> en mount | ✅ | Batch 4 |
Que falla
Section titled “Que falla”| Bug | Descripcion | Estado | Corregido |
|---|---|---|---|
| Reviews carousel altura inicial de 300px | El embed de reviews carousel usa 300px como altura inicial del iframe (otros layouts 500px). El auto-resize via postMessage funciona correctamente — el salto visual es breve y solo ocurre en la carga inicial. No requiere fix |
Que cambiaria
Section titled “Que cambiaria”| Mejora | Descripcion | Dificultad | Estado | Implementado |
|---|---|---|---|---|
| Dashboard de comparacion de variantes | Tabla comparativa de metricas (impresiones, CTR, conversiones) entre variantes del mismo tipo | Medio | Implementado ✅ | |
| Pre-fill en modo popup | El script de popup acepta atributos data-prefill-* | Facil | ✅ | Batch 3 |
| Reviews carousel altura inicial mas precisa | Ajustar la altura inicial del iframe de reviews carousel (actualmente 300px) para reducir el salto visual antes del auto-resize | Facil | Implementado ✅ |
Referencia tecnica
Section titled “Referencia tecnica”Archivos clave
Section titled “Archivos clave”| Archivo | Proposito |
|---|---|
apps/web/src/routes/teacher/widgets.lazy.tsx | Pagina principal |
apps/web/src/components/widgets/widget-editor.tsx | Editor de variante |
apps/web/src/components/widgets/widget-preview-panel.tsx | Preview en vivo |
apps/web/src/components/widgets/widget-embed-section.tsx | Codigo embed |
apps/web/src/components/widgets/widget-embed-utils.ts | Generacion de embed code |
apps/web/src/components/widgets/booking-config-form.tsx | Config booking |
apps/web/src/components/widgets/storefront-config-form.tsx | Config storefront |
apps/web/src/components/widgets/reviews-config-form.tsx | Config reviews |
apps/web/src/components/widgets/widget-analytics-badge.tsx | Badge compacto de analytics |
apps/web/src/components/widgets/widget-types.ts | Tipos TypeScript y configuraciones por defecto |
apps/web/src/components/widgets/use-widget-dirty-state.ts | Deteccion de cambios |
apps/api/src/services/teacher/widget-config-service.ts | Servicio backend |
| Endpoint | Metodo | Proposito |
|---|---|---|
/teacher/widget-configs | GET | Lista por tipo |
/teacher/widget-configs/:id | GET/PATCH/DELETE | CRUD individual |
/teacher/widget-configs | POST | Crear variante |
/teacher/widget-configs/:id/analytics | GET | Metricas 30 dias |