Skip to content

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.

Widgets page

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:

Fila de botones pill para cada configuracion guardada. Estrella en la variante por defecto. Boton “Nueva variante” para crear configs adicionales.

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

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)
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

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"
data-prefill-email="juan@ejemplo.com"
></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.

Todos los tipos de widget soportan CSS personalizado via textarea en el editor de configuracion:

  • Campo customCss en los schemas de configuracion de los 3 tipos de widget
  • Sanitizacion XSS: Zod .refine() bloquea @import, url(), expression(), javascript:
  • Endpoint dedicado: GET /:slug/widget-css?configId=xxx retorna CSS como text/css
  • Los iframes inyectan el CSS via <style> tag en mount
  • Deteccion de cambios via serializacion JSON (nombre + config)
  • Evento beforeunload para navegacion accidental
  • ConfirmDialog al colapsar fila o cambiar variante con cambios sin guardar

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

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

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 ✅

Archivo Proposito
apps/app/src/routes/teacher/widgets.lazy.tsx Pagina principal
apps/app/src/components/widgets/widget-editor.tsx Editor de variante
apps/app/src/components/widgets/widget-preview-panel.tsx Preview en vivo
apps/app/src/components/widgets/widget-embed-section.tsx Codigo embed
apps/app/src/components/widgets/widget-embed-utils.ts Generacion de embed code
apps/app/src/components/widgets/booking-config-form.tsx Config booking
apps/app/src/components/widgets/storefront-config-form.tsx Config storefront
apps/app/src/components/widgets/reviews-config-form.tsx Config reviews
apps/app/src/components/widgets/widget-analytics-badge.tsx Badge compacto de analytics
apps/app/src/components/widgets/widget-types.ts Tipos TypeScript y configuraciones por defecto
apps/app/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