Skip to content

Directorio de profesores

Ruta: /t en pinteach.app (SPA; el Worker de pinteach-app inyecta el head) · Auth: Ninguna (publica)

Pagina publica que lista todos los profesores con servicios activos. Incluye un quiz de compatibilidad, filtros de busqueda y tarjetas con informacion resumida de cada profesor.


Formulario de 5 preguntas (componente React CompatibilityQuiz, envio GET) que vuelve a /t con query params:

  1. Objetivo (goal): conversation, business, exam, travel, general
  2. Nivel actual (level): beginner, intermediate, advanced
  3. Horario preferido (schedule): morning (6-12h), afternoon (12-18h), evening (18-24h), flexible
  4. Horas por semana (hours): 1-2, 3-4, 5+
  5. Estilo de aprendizaje (style): structured, balanced, conversational

El quiz se muestra solo cuando no hay filtros activos.

La funcion computeCompatibilityScore() calcula un score 0-100% usando 5 dimensiones ponderadas. Solo las dimensiones con respuesta contribuyen al total (normalizacion dinamica).

Dimension Peso Matching
Objetivo 30 pts Keyword matching en subjects del profesor (ej: “conversacion” → conversation, “dele” → exam)
Horario 25 pts Overlap de rango horario con availability_rules activas del profesor
Nivel 20 pts Keywords en subjects + nombres de servicios. Partial score (+10) si no hay match exacto
Estilo 15 pts Tipo de servicio: structured → course/package, conversational → single + keyword, balanced → +10 siempre
Horas 10 pts Tipo de servicio: 5+ → subscription/package, 3-4 → package/course, 1-2 → +8 siempre

Formula: score = Math.round((earnedPoints / totalPossiblePoints) * 100)

Cuando hay quiz params, cada tarjeta de profesor muestra un badge con el porcentaje:

Score Color CSS
70-100% Verde bg-green-50 text-green-700 border-green-200
40-69% Ambar bg-amber-50 text-amber-700 border-amber-200
0-39% Gris bg-gray-50 text-gray-600 border-gray-200

Los profesores se ordenan descendente por compatibilidad cuando hay quiz params.

Panel lateral con:

  • Busqueda por texto (nombre, headline)
  • Especialidad (select con opciones del API)
  • Idioma (select)
  • Rango de precio (minimo/maximo)

Todos los filtros se envian como query params (GET) a la misma ruta /t.

Los links del directorio a perfiles de profesores NO incluyen ?ref=direct. Esto significa que cualquier alumno que llegue desde el directorio se registra con referralSource: 'directory' (lead de PinTeach). Solo los enlaces directos compartidos por el profesor llevan ?ref=direct.

Grid responsive (1-3 columnas) con tarjetas que muestran:

  • Avatar + badge Super Tutor
  • Nombre y headline
  • Materias (tags)
  • Rating promedio + total de resenas
  • Precio desde (servicio mas barato)
  • Badge de disponibilidad proxima
  • Link al perfil completo

Archivo Proposito
apps/app/src/routes/public/directory.tsx · directory.lazy.tsx Ruta /t y pagina del directorio
apps/app/src/components/public-profile/directory.tsx TeacherCard, CompatibilityQuiz, FilterSidebar
apps/app/src/worker/index.ts Head SEO de /t (title, description, canonical, OG)
Endpoint Metodo Proposito
/public/teachers GET Listado de profesores con filtros + quiz params (q, specialty, language, minPrice, maxPrice, goal, level, schedule, hours, style, limit, offset)
/public/sitemap-slugs GET Slugs de profesores para sitemap
Param Tipo Descripcion
q string Busqueda por texto (nombre, headline)
specialty string Filtro por materia
language string Filtro por idioma
minPrice number Precio minimo (centavos)
maxPrice number Precio maximo (centavos)
goal string Objetivo del quiz (conversation, business, exam, travel, general)
level string Nivel actual (beginner, intermediate, advanced)
schedule string Horario preferido (morning, afternoon, evening, flexible)
hours string Horas por semana (1-2, 3-4, 5+)
style string Estilo de clase (structured, balanced, conversational)
limit number Paginacion (default 20, max 50)
offset number Offset de paginacion
interface DirectoryTeacher {
slug: string;
name: string;
headline: string | null;
avatarUrl: string | null;
timezone: string;
subjects: string[];
languages: { language: string; level: string }[];
priceFrom: number | null;
currency: string;
reviewStats: { averageRating: number | null; totalReviews: number };
nextAvailableDate: string | null;
servicesCount: number;
compatibilityScore?: number | null; // Solo con quiz params
}

Cache-Control: public, s-maxage=300, stale-while-revalidate=600 (5 min cache, 10 min stale).