All files / web/src/hooks useSessionHistory.ts

100% Statements 100/100
100% Branches 14/14
100% Functions 4/4
100% Lines 100/100

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 92 93 94 95 96 97 98 99 100 1011x 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 1x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 6x 7x 1x 1x 1x 5x 5x 5x 7x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x 13x  
'use client'
 
/**
 * Hook for infinite-scroll session history
 *
 * Uses React Query's useInfiniteQuery for cursor-based pagination.
 */
 
import { useInfiniteQuery } from '@tanstack/react-query'
import type { PracticeSession } from '@/db/schema/practice-sessions'
import { api } from '@/lib/queryClient'
import { sessionHistoryKeys } from '@/lib/queryKeys'
 
// ============================================================================
// Types
// ============================================================================
 
interface SessionHistoryPage {
  sessions: PracticeSession[]
  nextCursor: string | null
  hasMore: boolean
}
 
// ============================================================================
// API Functions
// ============================================================================
 
async function fetchSessionHistory(
  playerId: string,
  cursor?: string,
  limit: number = 20
): Promise<SessionHistoryPage> {
  const params = new URLSearchParams()
  if (cursor) params.set('cursor', cursor)
  params.set('limit', limit.toString())
 
  console.log(
    `[useSessionHistory] Fetching: playerId=${playerId}, cursor=${cursor}, limit=${limit}`
  )
 
  const response = await api(`curriculum/${playerId}/sessions?${params.toString()}`)
 
  if (!response.ok) {
    console.error(`[useSessionHistory] Fetch failed: ${response.status} ${response.statusText}`)
    throw new Error(`Failed to fetch session history: ${response.statusText}`)
  }
 
  const data = await response.json()
  console.log(
    `[useSessionHistory] Received: ${data.sessions?.length} sessions, hasMore=${data.hasMore}, nextCursor=${data.nextCursor}`
  )
  return data
}
 
// ============================================================================
// Hook
// ============================================================================
 
interface UseSessionHistoryOptions {
  /** Number of sessions per page (default: 20) */
  pageSize?: number
  /** Whether to enable the query (default: true) */
  enabled?: boolean
}
 
export function useSessionHistory(playerId: string, options: UseSessionHistoryOptions = {}) {
  const { pageSize = 20, enabled = true } = options
 
  const query = useInfiniteQuery({
    queryKey: sessionHistoryKeys.list(playerId),
    queryFn: ({ pageParam }) => fetchSessionHistory(playerId, pageParam, pageSize),
    initialPageParam: undefined as string | undefined,
    getNextPageParam: (lastPage) => (lastPage.hasMore ? lastPage.nextCursor : undefined),
    enabled: !!playerId && enabled,
  })
 
  // Flatten all pages into a single array of sessions
  const allSessions = query.data?.pages.flatMap((page) => page.sessions) ?? []
 
  return {
    /** All loaded sessions (flattened from all pages) */
    sessions: allSessions,
    /** Total number of sessions loaded so far */
    totalLoaded: allSessions.length,
    /** Whether more sessions are available to load */
    hasNextPage: query.hasNextPage,
    /** Whether we're currently fetching the next page */
    isFetchingNextPage: query.isFetchingNextPage,
    /** Function to load the next page */
    fetchNextPage: query.fetchNextPage,
    /** Whether the initial load is in progress */
    isLoading: query.isLoading,
    /** Whether there was an error */
    isError: query.isError,
    /** The error if any */
    error: query.error,
    /** Refetch all pages */
    refetch: query.refetch,
  }
}