All files / web/src/arcade-games/know-your-world/features/hint useStruggleDetection.ts

0% Statements 0/85
0% Branches 0/1
0% Functions 0/1
0% Lines 0/85

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                                                                                                                                                                           
/**
 * Struggle Detection Hook
 *
 * Monitors user search behavior and automatically advances to the next hint
 * when the user appears to be struggling (based on time spent searching).
 */

import { useEffect, useRef } from 'react'

// Thresholds for triggering next hint
const STRUGGLE_TIME_THRESHOLD = 30000 // 30 seconds per hint level
const STRUGGLE_CHECK_INTERVAL = 5000 // Check every 5 seconds

export interface UseStruggleDetectionOptions {
  /** Whether hot/cold feedback is enabled (implies we're tracking search metrics) */
  effectiveHotColdEnabled: boolean
  /** Whether there are more hints available to show */
  hasMoreHints: boolean
  /** Current region prompt ID */
  currentPrompt: string | null
  /** Function to get search metrics */
  getSearchMetrics: (startTime: number) => { timeToFind: number }
  /** Function to advance to next hint */
  nextHint: () => void
  /** Ref to prompt start time */
  promptStartTime: React.RefObject<number>
}

/**
 * Hook that detects when a user is struggling to find a region and
 * automatically advances to the next hint level.
 *
 * Hint levels are based on time:
 * - Level 0 = first 30 seconds
 * - Level 1 = 30-60 seconds
 * - Level 2 = 60-90 seconds
 * - etc.
 */
export function useStruggleDetection({
  effectiveHotColdEnabled,
  hasMoreHints,
  currentPrompt,
  getSearchMetrics,
  nextHint,
  promptStartTime,
}: UseStruggleDetectionOptions): void {
  // Track which hint level triggered last hint
  const lastHintLevelRef = useRef(0)

  // Check for struggle and advance hint
  useEffect(() => {
    // Only run if hot/cold is enabled (means we're tracking search metrics)
    if (!effectiveHotColdEnabled || !hasMoreHints || !currentPrompt) return

    const checkStruggle = () => {
      const metrics = getSearchMetrics(promptStartTime.current ?? Date.now())

      // Calculate which hint level we should be at based on time
      // Level 0 = first 30 seconds, Level 1 = 30-60 seconds, etc.
      const expectedHintLevel = Math.floor(metrics.timeToFind / STRUGGLE_TIME_THRESHOLD)

      // If we should be at a higher hint level than last triggered, give next hint
      if (expectedHintLevel > lastHintLevelRef.current && hasMoreHints) {
        lastHintLevelRef.current = expectedHintLevel
        nextHint()
      }
    }

    const intervalId = setInterval(checkStruggle, STRUGGLE_CHECK_INTERVAL)

    return () => clearInterval(intervalId)
  }, [
    effectiveHotColdEnabled,
    hasMoreHints,
    currentPrompt,
    getSearchMetrics,
    nextHint,
    promptStartTime,
  ])

  // Reset hint level tracking when prompt changes
  useEffect(() => {
    lastHintLevelRef.current = 0
  }, [currentPrompt])
}