All files / web/src/arcade-games/know-your-world/hooks useRegionHint.ts

30% Statements 33/110
100% Branches 0/0
0% Functions 0/3
30% Lines 33/110

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 101 102 103 104 105 106 107 108 109 110 1111x 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 1x       1x 1x 1x 1x 1x                  
import { useCallback, useMemo, useRef, useState } from 'react'
import { useLocale } from 'next-intl'
import { getHints, hasHints, type HintMap } from '../messages'
import type { Locale } from '@/i18n/messages'
 
/**
 * Hook to get hints for a region with cycling support.
 * Starts with a random hint, and can cycle to the next hint when user is struggling.
 *
 * Returns:
 * - currentHint: The current hint text (null if no hints)
 * - hintIndex: Current index (0-based)
 * - totalHints: Total number of hints available
 * - nextHint: Function to advance to the next hint (cycles)
 * - hasMoreHints: Whether there are hints the user hasn't seen yet
 */
export interface UseRegionHintResult {
  currentHint: string | null
  hintIndex: number
  totalHints: number
  nextHint: () => void
  hasMoreHints: boolean
}
 
export function useRegionHint(map: HintMap, regionId: string | null): UseRegionHintResult {
  const locale = useLocale() as Locale
  // Track which region we're showing hints for
  const lastRegionRef = useRef<string | null>(null)
  // Track the starting index (randomized on region change)
  const startIndexRef = useRef<number>(0)
  // Track how many hints we've cycled through for this region
  const [cycleOffset, setCycleOffset] = useState(0)

  // Get all hints for this region
  const allHints = useMemo(() => {
    if (!regionId) return []
    return getHints(locale, map, regionId) ?? []
  }, [locale, map, regionId])

  // Reset cycle offset when region changes
  if (regionId !== lastRegionRef.current) {
    lastRegionRef.current = regionId
    // Pick a random starting index for this region
    startIndexRef.current = allHints.length > 0 ? Math.floor(Math.random() * allHints.length) : 0
    // Reset cycle offset (can't call setState in render, so we check in useMemo below)
  }

  // Calculate current hint
  const result = useMemo(() => {
    // Reset cycle offset if region changed (detected by mismatch)
    const effectiveCycleOffset = regionId === lastRegionRef.current ? cycleOffset : 0

    if (allHints.length === 0) {
      return {
        currentHint: null,
        hintIndex: 0,
        totalHints: 0,
        hasMoreHints: false,
      }
    }

    const currentIndex = (startIndexRef.current + effectiveCycleOffset) % allHints.length
    return {
      currentHint: allHints[currentIndex],
      hintIndex: effectiveCycleOffset,
      totalHints: allHints.length,
      hasMoreHints: effectiveCycleOffset < allHints.length - 1,
    }
  }, [allHints, cycleOffset, regionId])

  // Reset cycle offset when region changes
  const prevRegionRef = useRef<string | null>(null)
  if (regionId !== prevRegionRef.current) {
    prevRegionRef.current = regionId
    if (cycleOffset !== 0) {
      setCycleOffset(0)
    }
  }

  // Function to advance to the next hint
  const nextHint = useCallback(() => {
    if (allHints.length > 1) {
      setCycleOffset((prev) => prev + 1)
    }
  }, [allHints.length])

  return {
    ...result,
    nextHint,
  }
}
 
// Legacy function signature for backwards compatibility
export function useRegionHintSimple(map: HintMap, regionId: string | null): string | null {
  const { currentHint } = useRegionHint(map, regionId)
  return currentHint
}
 
/**
 * Hook to check if hints exist for a region in the current locale
 */
export function useHasRegionHint(map: HintMap, regionId: string | null): boolean {
  const locale = useLocale() as Locale

  if (!regionId) {
    return false
  }

  return hasHints(locale, map, regionId)
}