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 91 | 1x 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,
})
}
|