Dashboard
Ruta: /teacher/dashboard · Atajo: g d · Sidebar: Inicio
El Dashboard es la primera pantalla que ve el profesor al iniciar sesion. Muestra un resumen rapido del negocio, la agenda completa del dia, solicitudes de prueba pendientes y acciones sugeridas.
Layout
Section titled “Layout”┌──────────────────────────────────────────────────────────┐│ Saludo + Streak badge [+ Clase rapida] │├──────────────────────────────────────────────────────────┤│ KPIs (2x2) │ Acciones sugeridas ││ Ingresos · Clases │ (smart actions) ││ Alumnos · Asistencia │ │├──────────────────────────────────┼────────────────────────┤│ Agenda de hoy (col-span-2) │ Solicitudes pendientes ││ Timeline compacto, scroll │ (trials sin confirmar) │├──────────────────────────────────┴────────────────────────┤│ Esta semana (full width, solo si hay eventos no-hoy) │└──────────────────────────────────────────────────────────┘Que hay
Section titled “Que hay”Saludo contextual
Section titled “Saludo contextual”Mensaje de bienvenida que cambia segun la hora del dia:
| Hora | Saludo |
|---|---|
| 6:00 – 11:59 | Buenos dias, NAME |
| 12:00 – 17:59 | Buenas tardes, NAME |
| 18:00 – 5:59 | Buenas noches, NAME |
Subtitulo fijo: “Tus alumnos tienen suerte de tenerte”
Incluye un boton ”+ Clase rapida” a la derecha del saludo para programar sesiones sin salir del dashboard.
Si el profesor tiene un streak activo (dias consecutivos con clases completadas), se muestra un badge con icono de llama: “Llevas X dias consecutivos”.
KPIs configurables (4 tarjetas)
Section titled “KPIs configurables (4 tarjetas)”Grid de 2x2 con metricas. El profesor elige 4 de un catalogo de 8 metricas disponibles desde Ajustes > General > KPIs del dashboard. Por defecto se muestran las 4 primeras.
| Metrica | Key | Color | Datos | Tendencia |
|---|---|---|---|---|
| Ingresos del mes | month_revenue | Verde | Total enrollments.pricePaid del mes en curso | % vs mes anterior |
| Clases este mes | month_lessons | Azul | Sesiones scheduled + completed + pending_review | % vs mes anterior |
| Alumnos activos | active_students | Morado | Count de students con status active | — |
| Asistencia | attendance_rate | Ambar | completed / (completed + no_shows) * 100 o ”—” si no hay datos | — |
| Ingresos pendientes | pending_revenue | Esmeralda | Suma de services.priceAmount para sesiones futuras scheduled | — |
| Racha de ensenanza | teaching_streak | Naranja | Dias consecutivos con clases completadas | — |
| Nuevos alumnos | new_students | Cielo | Students creados este mes | — |
| Sesiones completadas | completed_sessions | Esmeralda | Sesiones con status completed este mes | — |
La seleccion se guarda en teachers.dashboardConfig (JSONB) con la estructura { kpis: string[] }. NULL = defaults.
La tarjeta de Ingresos del mes muestra un subtitulo con los ingresos pendientes cuando hay sesiones programadas.
API: GET /teacher/dashboard/summary
Acciones sugeridas
Section titled “Acciones sugeridas”Panel lateral derecho con alertas priorizadas que enlazan a la pagina correspondiente:
| Accion | Prioridad | Cuando aparece | Enlaza a |
|---|---|---|---|
| Solicitudes de prueba pendientes | Alta | Hay trials con status pending_confirmation | /teacher/calendar |
| Alumnos sin clase programada | Media | Students activos sin sesion scheduled futura | /teacher/students |
| Creditos por expirar | Alta | Enrollments activos con validUntil < 7 dias | /teacher/students |
| Alumnos en riesgo de abandono | Alta | Lifecycle events gap_detected en los ultimos 90 dias | /teacher/students |
| Pruebas sin convertir | Media | Trials completados en ultimos 30 dias sin enrollment activo/completado | /teacher/insights |
| Alumnos inactivos | Baja | Students con status inactive | /teacher/students |
| Resenas sin responder | Media | Reviews con status approved y teacherResponse IS NULL | /teacher/reviews |
| Content insight | Variable | Insights del content-analytics-worker (cache < 24h) | /teacher/templates |
API: GET /teacher/dashboard/smart-actions
Agenda de hoy
Section titled “Agenda de hoy”Timeline compacto de todas las sesiones del dia actual. Ocupa 2 columnas en desktop, con scroll vertical cuando hay 8+ sesiones (max-h-[420px]). Auto-scroll al evento “next up”.
Cada fila tiene 3 estados visuales:
| Estado | Visual |
|---|---|
| Pasada/completada | Opacidad reducida (opacity-50), borde izquierdo muted |
| Siguiente/en curso | Borde izquierdo 4px color del evento, fondo con tint, badge “En curso” o countdown |
| Futura | Normal, borde izquierdo a opacidad reducida |
Contenido de cada fila:
- Hora de inicio (columna fija)
- Nombre del alumno + badge de servicio + badge de templates vinculadas
- Rango horario completo (inicio – fin)
- Badge “En curso” si la sesion esta en progreso, o countdown si es la siguiente
- Acciones al hover: ver notas, WhatsApp, marcar completada
Header con contador de clases del dia. Si hay completadas, muestra “X de Y completadas”.
Casos especiales:
| Escenario | Comportamiento |
|---|---|
| 0 eventos hoy | Estado vacio: icono calendario + “No hay clases hoy” + “Disfruta tu dia libre” |
| 8+ eventos | max-h-[420px] overflow-y-auto, auto-scroll al evento next-up |
| Todas completadas | Todas dimmed, resumen “8 de 8 completadas” |
| En curso | Badge “En curso” en vez de countdown |
| Cancelada/no-show | Dimmed con opacity-50, se mantiene en su posicion del timeline |
Esta semana
Section titled “Esta semana”Lista de las proximas 4 sesiones que NO son de hoy (grid de 2 columnas en desktop). Solo se renderiza si hay eventos futuros no-hoy.
Cada tarjeta muestra:
- Nombre del alumno + badge de servicio
- Dia relativo (Hoy/Manana/Lun 3 mar) + rango horario
- Acciones al hover (mismas que agenda de hoy)
Enlace “Ver todo” → navega a /teacher/calendar
API: GET /teacher/calendar?start={hoy}&end={+7dias}
Solicitudes pendientes
Section titled “Solicitudes pendientes”Tarjetas para cada sesion de prueba sin confirmar:
- Badge del servicio + duracion
- Nombre del alumno
- Fecha y hora solicitada
- Boton “Confirmar” → session status
scheduled, crea evento en Calendar, envia email - Boton “Rechazar” (X) → dialog con motivo opcional, envia email de rechazo
API: GET /teacher/sessions?status=pending_confirmation
Clase rapida (Quick add)
Section titled “Clase rapida (Quick add)”Boton ”+ Clase rapida” en la cabecera del dashboard que abre un Sheet lateral con un formulario minimo:
- Servicio: Selector con servicios activos del profesor (nombre + duracion)
- Alumno: Selector con todos los alumnos
- Fecha: Input date (default: hoy)
- Hora: Input time con step de 15 min (default: siguiente cuarto de hora)
- Boton “Programar” →
POST /teacher/sessionsconserviceId,studentId,startUtc,timezone
Al confirmar, invalida queries de calendario y dashboard.
Streak del profesor
Section titled “Streak del profesor”Badge motivacional junto al saludo que muestra dias consecutivos con al menos una clase completada. Calcula hacia atras desde hoy (o ayer si hoy aun no hay clase completada). Se oculta si el streak es 0.
Modo normal: Icono de llama naranja + texto: “Llevas X dias consecutivos”
Modo record: Cuando el streak actual supera el best_streak guardado, el badge cambia a icono de trofeo ambar con animacion animate-pulse y aparece un toast de celebracion (5 segundos, icono Trophy). El toast solo se dispara una vez por carga de datos gracias a streakToastShown ref.
Tarjeta KPI teaching_streak: Muestra el icono y etiqueta segun el estado:
- Normal: llama + label “Racha de ensenanza”, subtitulo con el mejor record historico
- Record: trofeo + label “Nuevo record”, subtitulo con el record anterior superado
Datos: Calculo en getSummary() — agrupa class_sessions completadas por fecha, ordena desc, cuenta dias consecutivos (maximo 365 dias atras). Lee teachers.best_streak al inicio para comparar. Si isNewRecord, actualiza best_streak en la DB (fire-and-forget) y crea una notificacion in-app via NotificationService con tipo streak_record.
API: Los campos bestStreak, isNewRecord se incluyen en la respuesta de GET /teacher/dashboard/summary.
Ingresos pendientes
Section titled “Ingresos pendientes”Subtitulo en la tarjeta de Ingresos del mes que muestra la suma de services.priceAmount para sesiones futuras con status scheduled.
Formato: “Ingresos pendientes: $X”. Solo se muestra si hay sesiones programadas (pendingRevenue > 0).
Cuando el profesor tiene pagos en multiples monedas, el dashboard agrupa los ingresos pendientes por moneda y muestra cada importe formateado de forma independiente. El campo pendingRevenueByCurrency es un array de objetos { currency: string, amount: number } ordenado por importe desc. La tarjeta KPI itera el array y muestra una linea por moneda.
Que falta
Section titled “Que falta”No hay items pendientes.
Que falla
Section titled “Que falla”| Bug | Descripcion | Estado | Corregido |
|---|---|---|---|
| Moneda hardcodeada a EUR | El dashboard ahora lee teachers.defaultCurrency (configurable en Ajustes > General) | ✅ | Batch 1 |
| Ingresos mezclan monedas | La moneda del profesor (defaultCurrency) se usa como referencia para el simbolo y el formato | ✅ | Batch 1 |
| Asistencia 100% con 0 sesiones | Devuelve null y muestra ”—” cuando no hay datos | ✅ | Batch 1 |
| Key i18n incorrecta para templates | Usa key dedicada dashboard.linkedTemplates | ✅ | Batch 1 |
| Content insights no renderizados | El tipo content_insight ahora se renderiza en SmartActionCard | ✅ | Batch 1 |
Que cambiaria
Section titled “Que cambiaria”| Mejora | Descripcion | Dificultad | Estado | Implementado |
|---|---|---|---|---|
| KPIs con drag-and-drop para reordenar | Actualmente el orden de los 4 KPIs seleccionados sigue el orden de seleccion. Podria anadirse drag-and-drop para reordenar las tarjetas. | Medio | ✅ | Batch 5 |
Referencia tecnica
Section titled “Referencia tecnica”Archivos clave
Section titled “Archivos clave”| Archivo | Proposito |
|---|---|
apps/web/src/routes/teacher/dashboard.lazy.tsx | Pagina completa (componente React) |
apps/api/src/services/teacher/dashboard-service.ts | Calculo de KPIs y smart actions |
apps/api/src/routes/teacher/dashboard.ts | Rutas thin (GET summary, GET smart-actions) |
apps/web/src/components/ui/kpi-card.tsx | Componente reutilizable de tarjeta KPI |
| Endpoint | Metodo | Respuesta |
|---|---|---|
/teacher/dashboard/summary | GET | { monthRevenue, monthRevenueChange, monthLessons, monthLessonsChange, activeStudents, attendanceRate: number | null, currency, pendingRevenue, pendingRevenueByCurrency: { currency: string, amount: number }[], teachingStreak, bestStreak, isNewRecord, newStudents, completedSessions } |
/teacher/dashboard/smart-actions | GET | [{ type, count, priority, insight? }] — tipos: pending_trials, expiring_credits, no_upcoming, inactive_students, at_risk, unconverted_trials, unanswered_reviews, content_insight |
/teacher/sessions?status=pending_confirmation | GET | [{ id, startsAt, student, service, ... }] |
/teacher/calendar?start=X&end=Y | GET | [{ id, type, title, startsAt, endsAt, status, ... }] |
/teacher/sessions | POST | Crea sesion manual. Body: { serviceId, studentId, startUtc, timezone? } |
/teacher/services | GET | Lista de servicios (usada por Quick add) |
/teacher/students | GET | Lista de alumnos (usada por Quick add) |
Queries (TanStack Query)
Section titled “Queries (TanStack Query)”// KPIsuseQuery({ queryKey: ['teacher-dashboard-summary'], queryFn: ... })
// Smart actionsuseQuery({ queryKey: ['teacher-dashboard-smart-actions'], queryFn: ... })
// Teacher settings (for dashboardConfig.kpis)useQuery({ queryKey: ['teacher', 'settings'], queryFn: ... })
// Trials pendientesuseQuery({ queryKey: ['teacher-sessions-pending'], queryFn: ... })
// Proximas 7 diasuseQuery({ queryKey: ['teacher-calendar', start, end], queryFn: ... })
// Servicios (lazy, solo cuando se abre Quick add)useQuery({ queryKey: ['teacher-services'], enabled: open, queryFn: ... })
// Alumnos (lazy, solo cuando se abre Quick add)useQuery({ queryKey: ['teacher-students-for-scheduling'], enabled: open, queryFn: ... })Mutations
Section titled “Mutations”| Accion | Hook | Optimista |
|---|---|---|
| Confirmar trial | useMutation | No (server-side, espera confirmacion) |
| Rechazar trial | useMutation | No |
| Completar sesion | useCompleteSession | Si (actualiza cache calendario) |
| Clase rapida | useMutation | No (server-side, espera confirmacion) |