Files
qwen3-6-lora/data/raw/sanitized/plans/gfiber-pilot-extension-lively-sloth.md

11 KiB
Raw Permalink Blame History

GFIBER-673 — Propuesta de tutorial in-app con reactour

Contexto

GFIBER-673 es un spike: "¿cómo se vería un tutorial paso a paso al primer login o tras un release mayor, para Admins y para Users?" No existe hoy ningún componente de tour/onboarding en el repo (confirmado por grep exhaustivo). El usuario propuso evaluar reactour como librería base. Esta propuesta cubre: (1) el veredicto de viabilidad técnica, (2) el contenido concreto del tour para cada rol, anclado en pantallas reales del repo, y (3) el enfoque de implementación e integración con las convenciones ya establecidas del proyecto.

Veredicto de viabilidad: apto, sin bloqueantes

Chequeo Requisito de reactour Este repo Resultado
React 16.x | 17.x | 18.x | 19.x (peer dep) React 19.2.4 (pinneado) Compatible
Next.js / router Necesita boundary 'use client' (hooks + DOM) Next.js 16.2.7, App Router, 57 archivos ya usan 'use client' Patrón ya establecido
TypeScript Reescrito en TS nativo TS 5 strict Compatible
Estilos Popover/mask vía portal, estilable por props inline Tailwind v4 (app/) + SCSS Modules (packages/design-system), sin Radix/MUI/Headless UI Sin conflicto de dependencias
Persistencia "ya lo vio" Fuera del alcance de la librería Convención ya usada: columna boolean en profiles vía migración (is_enabled, notify_pending_attendance) Patrón reusable directo
Paquete @reactour/tour v3.8.0, MIT, activo (4.1k★) Apto

Dos matices para la implementación (no bloquean el spike, pero condicionan el enfoque):

  1. reactour apunta pasos por selector CSS — usar atributos dedicados data-tour="..." en los elementos objetivo, nunca clases de Tailwind (frágil ante cambios de diseño).
  2. El theming de reactour es vía objetos de estilo inline, no clases Tailwind — se puede lograr consistencia visual referenciando directamente las custom properties --fiber-* ya definidas en app/globals.css (ej. backgroundColor: 'var(--fiber-primary)'), sin depender de Tailwind dentro del portal de reactour.

Fuera de alcance de este spike: Triple T no existe en este repositorio (confirmado — solo aparece mencionado como "fuera de alcance" en docs/plans/*). El AC del ticket pide tours por rol (Admin / User), no por producto, así que esto no bloquea la propuesta — se deja anotado como gap a resolver el día que Triple T viva en este monorepo o se integre.

Hallazgo clave que moldea el diseño

Todos los roles — Admin, Owner y User — aterrizan en la misma página tras login: /upsell-evaluator (confirmado: app/page.tsx redirige a /login, y el wordmark del NavBar en components/NavBar.tsx:38 linkea /upsell-evaluator como "GFiber Pilot home" para todos). No existe un "home de admin" separado. Esto significa que un tour "por rol" en el sentido de páginas de entrada distintas no aplica — en cambio, el diseño correcto es:

  • Un tour base común (Upsell Evaluator) que ven Admin y User por igual, la primera vez que llegan a /upsell-evaluator.
  • Un tour adicional, solo-Admin/Owner, que se dispara la primera vez que visitan /admin o /dashboard — páginas que ni siquiera son visibles en el NavBar para un User raso (canAccessAdmin en components/NavBar.tsx).

Esto respeta el AC del ticket ("proponer tutorial para Admins" + "proponer tutorial para Users") sin inventar una página de entrada que no existe.

Propuesta — Tour de Users (y base para Admins)

Disparado la primera vez que cualquier usuario autenticado visita /upsell-evaluator (app/(protected)/upsell-evaluator/page.tsx).

# Elemento objetivo (data-tour) Componente real Contenido del paso
1 nav-wordmark components/NavBar.tsx "Este es tu punto de partida — GFiber Pilot home."
2 stage-transition-gaid _flow/StageTransition.tsx "Ingresa el GAID y Case ID del cliente, luego presiona Check para validar elegibilidad."
3 stage-transition-hardstops Chips de riesgo (Financial Sensitivity, Technical Instability, Negative Sentiment) "Marca estos chips si detectas alguna señal de riesgo antes de continuar."
4 objection-drawer-trigger ObjectionDrawer.tsx "En cualquier momento de la llamada, abre este panel para scripts de manejo de objeciones."
5 copilot-widget-launcher components/upsell/CopilotWidget.tsx "¿Duda sobre qué responder? Pega el chat del cliente aquí y el asistente sugiere una respuesta."
6 stage-discovery-quickcapture _flow/StageDiscovery.tsx "Usa estos chips rápidos (Gaming, WFH, Cámaras...) o profundiza en el acordeón de abajo."
7 stage-value-comparison _flow/StageValue.tsx "Aquí comparas el plan actual del cliente contra el upgrade recomendado, con costo diario."
8 stage-close-outcome _flow/StageClose.tsx "Registra el resultado (Aceptado/Declinado); si aceptó, la nota para Salesforce se genera sola."
9 navbar-my-metrics Link "My Metrics" en components/NavBar.tsx "Aquí revisas tu historial de sesiones y métricas personales."

Persistencia: nueva columna has_seen_upsell_tour boolean not null default false en profiles, siguiendo el patrón exacto de supabase/migrations/20260625000000_add_notify_pending_attendance_to_profiles.sql. Se marca true vía Server Action al completar o saltar el tour.

Propuesta — Tour adicional de Admins/Owners

Disparado la primera vez que un usuario con role IN ('admin', 'owner') visita /admin (y, por separado, la primera vez que visita /dashboard) — ambos gateados hoy por app/(protected)/admin/layout.tsx y app/(protected)/dashboard/layout.tsx.

Parte A — /admin (User Management)

# Elemento objetivo Componente real Contenido del paso
1 admin-invite-form components/admin/InviteUserForm.tsx "Invita usuarios nuevos por email, asignando su rol desde aquí."
2 admin-user-table components/admin/UserTable.tsx "Esta tabla lista a todos los usuarios; usa '⋯ More' para gestionar cada uno."
3 admin-manage-drawer components/admin/UserManageDrawer.tsx "Desde aquí cambias rol, equipo, activas/desactivas o reenvías la invitación."

Parte B — /dashboard (Sales Dashboard)

# Elemento objetivo Componente real Contenido del paso
1 dashboard-date-range DateRangeControl "Filtra todas las métricas por rango de fechas."
2 dashboard-team-toggle TeamToggle "Alterna entre ver solo tu equipo o todos los equipos."
3 dashboard-leaderboard Leaderboard / AllTeamsCard "Aquí comparas el desempeño de agentes y equipos."
4 dashboard-export Botón "Export report" (app/(protected)/dashboard/api/export/route.ts) "Descarga el reporte completo en un clic."

Persistencia: columna has_seen_admin_tour boolean not null default false en profiles — mismo patrón de migración, solo relevante/seteable para admin/owner.

Controles de usuario: Skip y reinicio manual

Ambos tours (Users y Admin/Owner) deben poder saltarse y reiniciarse a demanda — no solo dispararse una vez de forma automática:

  • Skip: cada paso del popover incluye un botón "Saltar tutorial" (override del componente Close/footer de reactour, vía la prop components de TourProvider), visible desde el primer paso — no solo al final. Al presionarlo, setIsOpen(false) cierra el tour y dispara la misma Server Action que marca has_seen_upsell_tour / has_seen_admin_tour en true, para que no se vuelva a mostrar automáticamente en el siguiente login.
  • Reinicio manual: un botón persistente para volver a lanzar el tour cuando el usuario quiera, sin depender del flag de "ya lo vio":
    • Tour de Users → ícono " Ver tutorial" junto al wordmark en components/NavBar.tsx, visible para todos los roles. Llama setIsOpen(true) reseteando currentStep a 0, sin tocar el flag en profiles (reiniciar no debe tener efectos secundarios de persistencia).
    • Tour de Admin → mismo patrón de botón " Ver tutorial", ubicado en el header de app/(protected)/admin/page.tsx y de app/(protected)/dashboard/page.tsx respectivamente (cada página relanza solo su propia mitad del tour — Parte A o Parte B).

Esto significa que el TourProvider necesita exponer el hook useTour no solo para auto-arranque en el layout, sino también consumible desde estos botones — encaja de forma natural con la API de reactour (useTour() es válido en cualquier client component descendiente del TourProvider).

Enfoque técnico de implementación (para cuando se apruebe pasar de spike a build)

  1. Instalar @reactour/tour.
  2. Nuevo client component components/ProductTour.tsx ('use client'), envolviendo el contenido de app/(protected)/layout.tsx con <TourProvider>. Recibe profile.role, profile.has_seen_upsell_tour, profile.has_seen_admin_tour como props desde el server component padre (ya se resuelve ahí vía getCurrentUserWithProfile()).
  3. Dos arrays de steps (upsellTourSteps, adminTourSteps) definidos por selector data-tour, no por clase Tailwind.
  4. Botón " Ver tutorial" reutilizable (components/TourRestartButton.tsx) que consume useTour() — instanciado en NavBar.tsx (tour de Users) y en los headers de /admin y /dashboard (tour de Admin).
  5. Override del footer/Close de reactour vía la prop components de TourProvider, agregando la acción "Saltar tutorial" en todos los pasos.
  6. Dos migraciones nuevas en supabase/migrations/, siguiendo el formato YYYYMMDDHHMMSS_add_<column>_to_profiles.sql.
  7. Server Action para marcar cada flag true al completar o saltar el tour respectivo (patrón ya usado para notify_pending_attendance); el botón de reinicio manual NO llama a esta acción.
  8. Theming del popover/mask vía las custom properties --fiber-* existentes en app/globals.css, para que visualmente no desentone con el resto de la UI.
  9. Spike técnico corto (≈30 min) antes de comprometerse: confirmar si los componentes internos de reactour (Wrapper, Badge, Close) aceptan override completo o solo estilos inline — determina cuánto se puede "tailwindizar" el look del tour, incluyendo el botón de Skip.

Verificación

  • Levantar el repo local, loguear como user → confirmar que el tour de Upsell Evaluator se dispara una sola vez (flag persiste tras reload).
  • Loguear como admin/owner → confirmar que ven el tour base de Upsell Evaluator y, al visitar /admin y /dashboard por primera vez, el tour adicional.
  • Confirmar que un user sin acceso a /admin nunca ve ese tour (ni el flag se crea/lee para él de forma que rompa nada).
  • Revisar visualmente que el popover de reactour respeta paleta y modo oscuro (--fiber-*, variante .dark).
  • Presionar "Saltar tutorial" en el paso 1 → confirmar que el tour se cierra y el flag correspondiente queda en true (no vuelve a auto-abrirse en el siguiente login).
  • Con el flag ya en true, presionar el botón " Ver tutorial" en NavBar//admin//dashboard → confirmar que el tour se relanza desde el paso 1 sin alterar el flag.

Entrega

Publicar esta propuesta como página en el space de Docmost del proyecto (gfiber-pilot-extension), como respuesta al spike GFIBER-673. Se enlaza el ticket de Jira en la página.