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 111 | 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 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)
}
|