All files / web/src/hooks useSkillMetrics.ts

100% Statements 90/90
100% Branches 12/12
100% Functions 6/6
100% Lines 90/90

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 911x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 1x 1x 2x 2x 2x 2x 1x 3x 3x 3x 3x 3x 3x 1x 1x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x  
/**
 * Hooks for managing skill metrics for the scoreboard
 *
 * Provides access to:
 * - Player's skill metrics (overall mastery, category breakdown, trends)
 * - Classroom skills leaderboard (effort-based, improvement-based, speed champions)
 */
 
'use client'
 
import { useQuery } from '@tanstack/react-query'
import { api } from '@/lib/queryClient'
import { skillMetricsKeys } from '@/lib/queryKeys'
import type {
  StudentSkillMetrics,
  ClassroomSkillsLeaderboard,
} from '@/lib/curriculum/skill-metrics'
 
// Re-export query keys for consumers
export { skillMetricsKeys } from '@/lib/queryKeys'
 
// ============================================================================
// API Functions
// ============================================================================
 
async function fetchPlayerSkillMetrics(playerId: string): Promise<StudentSkillMetrics> {
  const response = await api(`curriculum/${playerId}/skills/metrics`)
 
  if (!response.ok) {
    throw new Error(`Failed to fetch skill metrics: ${response.statusText}`)
  }
 
  const data = await response.json()
  return data.metrics
}
 
async function fetchClassroomSkillsLeaderboard(
  classroomId: string
): Promise<ClassroomSkillsLeaderboard> {
  const response = await api(`classroom/${classroomId}/skills/leaderboard`)
 
  if (!response.ok) {
    throw new Error(`Failed to fetch skills leaderboard: ${response.statusText}`)
  }
 
  const data = await response.json()
  return data.leaderboard
}
 
// ============================================================================
// Hooks
// ============================================================================
 
/**
 * Hook to fetch a player's skill metrics for display on the scoreboard.
 *
 * Returns:
 * - Overall mastery percentage (weighted by confidence)
 * - Category breakdown (basic, fiveComplements, etc.)
 * - Normalized response time (seconds per term) with trend
 * - Accuracy metrics with trend
 * - Progress metrics (improvement rate, streak, problem counts)
 */
export function usePlayerSkillMetrics(playerId: string | null) {
  return useQuery({
    queryKey: skillMetricsKeys.player(playerId ?? ''),
    queryFn: () => fetchPlayerSkillMetrics(playerId!),
    enabled: !!playerId,
    // Skill metrics don't change frequently, cache for 1 minute
    staleTime: 60 * 1000,
  })
}
 
/**
 * Hook to fetch the classroom skills leaderboard.
 *
 * Provides "fun ways to compare students across different ability levels":
 * - Effort-based: byWeeklyProblems, byTotalProblems, byPracticeStreak
 * - Improvement-based: byImprovementRate
 * - Speed champions: fastest in each category (only mastered students compete)
 */
export function useClassroomSkillsLeaderboard(classroomId: string | null) {
  return useQuery({
    queryKey: skillMetricsKeys.classroomLeaderboard(classroomId ?? ''),
    queryFn: () => fetchClassroomSkillsLeaderboard(classroomId!),
    enabled: !!classroomId,
    // Leaderboard is computed on demand, cache for 2 minutes
    staleTime: 2 * 60 * 1000,
  })
}