workspace/projects/gamilit/docs/01-fase-alcance-inicial/EAI-003-gamificacion/especificaciones/ET-GAM-005-hook-user-gamification.md
rckrdmrd ea1879f4ad feat: Initial workspace structure with multi-level Git configuration
- Configure workspace Git repository with comprehensive .gitignore
- Add Odoo as submodule for ERP reference code
- Include documentation: SETUP.md, GIT-STRUCTURE.md
- Add gitignore templates for projects (backend, frontend, database)
- Structure supports independent repos per project/subproject level

Workspace includes:
- core/ - Reusable patterns, modules, orchestration system
- projects/ - Active projects (erp-suite, gamilit, trading-platform, etc.)
- knowledge-base/ - Reference code and patterns (includes Odoo submodule)
- devtools/ - Development tools and templates
- customers/ - Client implementations template

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 10:44:23 -06:00

10 KiB

ET-GAM-005: Hook useUserGamification

Información General

Campo Valor
ID ET-GAM-005
Épica EAI-003 - Gamificación
Título Hook Centralizado de Datos de Gamificación
Prioridad Alta (P1)
Estado COMPLETADO
Fecha Implementación 2025-11-19
Ubicación apps/frontend/src/shared/hooks/useUserGamification.ts

🎯 Objetivo

Proporcionar un hook React centralizado que gestione la obtención y actualización de datos de gamificación del usuario, eliminando la duplicación de código y preparando el sistema para la integración con el endpoint backend.


📦 Descripción

El hook useUserGamification es un custom hook de React que encapsula toda la lógica relacionada con la obtención de datos de gamificación de un usuario específico. Actualmente utiliza datos mock para desarrollo, pero está diseñado para una transición rápida al endpoint backend real.

Características Principales

  • Centralización: Único punto de acceso a datos de gamificación
  • Type-Safe: Completamente tipado con TypeScript
  • Loading States: Manejo de estados de carga y error
  • Mock Data: Datos de desarrollo realistas con delay simulado
  • Backend Ready: Preparado para activación de API real en 2 líneas
  • Fallback Robusto: Manejo de errores con datos por defecto

🔧 Interfaz TypeScript

UserGamificationData

export interface UserGamificationData {
  userId: string;
  level: number;
  totalXP: number;
  mlCoins: number;
  rank: string;
  achievements: string[];
}

Hook Signature

export function useUserGamification(userId?: string): {
  gamificationData: UserGamificationData | null;
  loading: boolean;
  error: string | null;
}

💻 Implementación Actual

Ubicación del Archivo

apps/frontend/src/shared/hooks/useUserGamification.ts

Código del Hook

import { useState, useEffect } from 'react';
import apiClient from '@/services/api/apiClient';
import type { UserGamificationData } from '@shared/types/user.types';

export function useUserGamification(userId?: string) {
  const [gamificationData, setGamificationData] = useState<UserGamificationData | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (!userId) {
      setGamificationData(null);
      setLoading(false);
      return;
    }

    const fetchGamificationData = async () => {
      try {
        setLoading(true);
        setError(null);

        // TODO: Replace with real API call when backend endpoint is ready
        // const response = await apiClient.get(`/api/users/${userId}/gamification`);
        // setGamificationData(response.data.data);

        // TEMPORARY: Mock data for development
        await new Promise(resolve => setTimeout(resolve, 300));
        const mockData: UserGamificationData = {
          userId,
          level: 15,
          totalXP: 3250,
          mlCoins: 1875,
          rank: 'Investigador Experto',
          achievements: ['first_case', 'streak_7', 'helper', 'speed_demon'],
        };
        setGamificationData(mockData);
      } catch (err: any) {
        console.error('Failed to fetch gamification data:', err);
        setError(err?.message || 'Failed to load gamification data');
        setGamificationData({
          userId,
          level: 1,
          totalXP: 0,
          mlCoins: 0,
          rank: 'Novato',
          achievements: [],
        });
      } finally {
        setLoading(false);
      }
    };

    fetchGamificationData();
  }, [userId]);

  return { gamificationData, loading, error };
}

📊 Uso del Hook

Patrón de Implementación

El hook se utiliza en 29 páginas de los 3 portales principales:

Admin Portal (7 páginas)

import { useUserGamification } from '@shared/hooks/useUserGamification';

export default function AdminDashboardPage() {
  const { user, logout } = useAuth();
  const { gamificationData } = useUserGamification(user?.id);

  const displayGamificationData = gamificationData || {
    userId: user?.id || 'mock-admin-id',
    level: 1,
    totalXP: 0,
    mlCoins: 0,
    rank: 'Novato',
    achievements: [],
  };

  return (
    <AdminLayout
      user={user || undefined}
      gamificationData={displayGamificationData}
      organizationName="GAMILIT Platform Admin"
      onLogout={handleLogout}
    >
      {/* contenido */}
    </AdminLayout>
  );
}

Teacher Portal (11 páginas)

import { useUserGamification } from '@shared/hooks/useUserGamification';

export default function TeacherDashboardPage() {
  const { user, logout } = useAuth();
  const { gamificationData } = useUserGamification(user?.id);

  const displayGamificationData = gamificationData || {
    userId: user?.id || 'mock-teacher-id',
    level: 1,
    totalXP: 0,
    mlCoins: 0,
    rank: 'Novato',
    achievements: [],
  };

  return (
    <TeacherLayout
      user={user ?? undefined}
      gamificationData={displayGamificationData}
      organizationName="GLIT Platform"
      onLogout={handleLogout}
    >
      {/* contenido */}
    </TeacherLayout>
  );
}

Student Portal (11 páginas)

import { useUserGamification } from '@shared/hooks/useUserGamification';

export default function DashboardComplete() {
  const { user, logout } = useAuth();
  const { gamificationData } = useUserGamification(user?.id);

  return (
    <div className="min-h-screen bg-gradient-to-br from-orange-50 via-amber-50 to-orange-100">
      <GamifiedHeader
        user={user || undefined}
        gamificationData={gamificationData}
        onLogout={handleLogout}
      />
      {/* contenido */}
    </div>
  );
}

🔄 Migración a API Real

Activación del Endpoint Backend

Una vez que el backend implemente GET /api/users/:userId/gamification, la activación es inmediata:

Paso 1: Editar apps/frontend/src/shared/hooks/useUserGamification.ts

Paso 2: Reemplazar el bloque de mock data (líneas 52-69) con:

// ✅ ACTIVAR (API real)
const response = await apiClient.get(`/api/users/${userId}/gamification`);
setGamificationData(response.data.data);

Paso 3: ¡Listo! Las 29 páginas automáticamente consumirán datos reales.

Endpoint Backend Esperado

GET /api/users/:userId/gamification

Response:
{
  "success": true,
  "data": {
    "userId": "550e8400-e29b-41d4-a716-446655440000",
    "level": 15,
    "totalXP": 3250,
    "mlCoins": 1875,
    "rank": "Ah K'in - Sacerdote del Sol",
    "achievements": ["first_case_solved", "streak_7_days"]
  }
}

Ver handoff completo: orchestration/integracion/HANDOFF-GAMIFICATION-FE-TO-BE.md


📈 Métricas de Impacto

Antes de la Implementación

  • 29 archivos con gamificationData hardcodeado
  • ~377 líneas de código duplicado
  • 29 puntos de actualización para API real
  • ~2-3 horas para activar API en todos los portales
  • Consistencia baja entre portales

Después de la Implementación

  • 1 único hook centralizado
  • ~42 líneas de código total (hook)
  • 1 punto de actualización para API real
  • 2 minutos para activar API (descomentar 2 líneas)
  • Consistencia alta - mismo patrón en 29 páginas

Mejoras Medibles

Métrica Antes Después Mejora
Archivos con código duplicado 29 0 -100%
Líneas de código duplicado ~377 ~42 -89%
Puntos de actualización 29 1 -97%
Tiempo activación API 2-3h 2min -98%

📄 Páginas Migradas

Admin Portal (7/7)

  1. AdminDashboardPage
  2. AdminUsersPage
  3. AdminInstitutionsPage
  4. AdminContentPage
  5. AdminReportsPage
  6. AdminSettingsPage
  7. AdminMonitoringPage

Teacher Portal (11/11)

  1. TeacherDashboardPage
  2. TeacherAlertsPage
  3. TeacherAnalyticsPage
  4. TeacherAssignmentsPage
  5. TeacherCommunicationPage
  6. TeacherContentPage
  7. TeacherGamificationPage
  8. TeacherMonitoringPage
  9. TeacherProgressPage
  10. TeacherReportsPage
  11. TeacherResourcesPage

Student Portal (11/11)

  1. DashboardComplete
  2. ProfilePage
  3. MissionsPage
  4. ModuleDetailPage
  5. FriendsPage
  6. ShopPage
  7. GuildsPage
  8. InventoryPage
  9. SettingsPage
  10. EnhancedProfilePage
  11. ExercisePage

Total: 29 páginas migradas (100%)


🔗 Referencias

Documentación Relacionada

  1. Reporte de Migración: orchestration/frontend/REPORTE-MIGRACION-USERGAMIFICATION-2025-11-19.md

  2. Handoff Backend: orchestration/integracion/HANDOFF-GAMIFICATION-FE-TO-BE.md

  3. Tipos TypeScript: apps/frontend/src/shared/types/user.types.ts

  4. Especificación Rangos Maya: docs/01-fase-alcance-inicial/EAI-003-gamificacion/especificaciones/ET-GAM-003-rangos-maya.md

Interfaces Relacionadas

  • UserGamificationData - Interfaz principal del hook
  • User - Usuario autenticado
  • GamifiedHeaderProps - Props del header con gamificación

Validación

TypeScript Compilation

  • Sin errores nuevos introducidos
  • Todos los tipos correctamente inferidos
  • Imports correctos en las 29 páginas

Testing

  • Pendiente: Tests unitarios del hook
  • Pendiente: Tests de integración con backend
  • Pendiente: Tests E2E de los 3 portales

👥 Responsables

Frontend Implementation: Claude Code (Agente Frontend) Backend Integration: Pendiente (ver handoff) Review: Pendiente Testing: Pendiente (después de backend)


📅 Historial

Fecha Versión Cambios
2025-11-19 1.0 Implementación inicial del hook
2025-11-19 1.0 Migración completa de 29 páginas
2025-11-19 1.0 Documentación técnica creada

Última actualización: 2025-11-19 Estado: COMPLETADO - Hook implementado y desplegado en los 3 portales