All files / web/src/constants helpTiming.ts

86.4% Statements 108/125
100% Branches 0/0
0% Functions 0/3
86.4% Lines 108/125

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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 1261x 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 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 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 1x     1x 1x 1x 1x 1x 1x 1x                            
/**
 * Timing configuration for progressive help system
 *
 * Production values give the kid time to try on their own before hints appear.
 * Debug values allow fast iteration during development.
 */
export const HELP_TIMING = {
  production: {
    /** Delay before showing coach hint */
    coachHintDelayMs: 5000,
    /** Delay before showing bead tooltip */
    beadTooltipDelayMs: 10000,
    /** Duration of celebration animation */
    celebrationDurationMs: 800,
    /** Duration of fade-out transition */
    transitionDurationMs: 300,
  },
  debug: {
    /** Delay before showing coach hint */
    coachHintDelayMs: 1000,
    /** Delay before showing bead tooltip */
    beadTooltipDelayMs: 3000,
    /** Duration of celebration animation */
    celebrationDurationMs: 500,
    /** Duration of fade-out transition */
    transitionDurationMs: 200,
  },
} as const
 
export type HelpTimingConfig = {
  readonly coachHintDelayMs: number
  readonly beadTooltipDelayMs: number
  readonly celebrationDurationMs: number
  readonly transitionDurationMs: number
}
 
/**
 * Get timing configuration based on debug mode
 */
export function getHelpTiming(debug: boolean): HelpTimingConfig {
  return debug ? HELP_TIMING.debug : HELP_TIMING.production
}
 
/**
 * Progressive assistance timing configuration
 *
 * Controls the escalation from idle → encouragement → help offer → auto-pause.
 * Production values give kids time; debug values allow fast iteration.
 */
export const PROGRESSIVE_ASSISTANCE_TIMING = {
  production: {
    /** Default encouragement delay when not enough data for stats (ms) */
    defaultEncouragementMs: 15_000,
    /** Default help offer delay when not enough data for stats (ms) */
    defaultHelpOfferMs: 30_000,
    /** Min clamp for encouragement threshold (ms) */
    minEncouragementMs: 8_000,
    /** Max clamp for encouragement threshold (ms) */
    maxEncouragementMs: 45_000,
    /** Min clamp for help offer threshold (ms) */
    minHelpOfferMs: 15_000,
    /** Max clamp for help offer threshold (ms) */
    maxHelpOfferMs: 90_000,
    /** Min clamp for auto-pause threshold (ms) */
    minAutoPauseMs: 15_000,
    /** Max clamp for auto-pause threshold (ms) */
    maxAutoPauseMs: 300_000,
    /** Number of wrong answers before suggesting help */
    wrongAnswerThreshold: 3,
    /** Grace period after all terms helped before moveOn becomes available (ms) */
    moveOnGraceMs: 12_000,
  },
  debug: {
    defaultEncouragementMs: 3_000,
    defaultHelpOfferMs: 6_000,
    minEncouragementMs: 2_000,
    maxEncouragementMs: 10_000,
    minHelpOfferMs: 4_000,
    maxHelpOfferMs: 15_000,
    minAutoPauseMs: 8_000,
    maxAutoPauseMs: 30_000,
    wrongAnswerThreshold: 2,
    moveOnGraceMs: 3_000,
  },
} as const
 
export interface ProgressiveAssistanceTimingConfig {
  readonly defaultEncouragementMs: number
  readonly defaultHelpOfferMs: number
  readonly minEncouragementMs: number
  readonly maxEncouragementMs: number
  readonly minHelpOfferMs: number
  readonly maxHelpOfferMs: number
  readonly minAutoPauseMs: number
  readonly maxAutoPauseMs: number
  readonly wrongAnswerThreshold: number
  readonly moveOnGraceMs: number
}
 
/**
 * Get progressive assistance timing based on debug mode
 */
export function getProgressiveAssistanceTiming(debug: boolean): ProgressiveAssistanceTimingConfig {
  return debug ? PROGRESSIVE_ASSISTANCE_TIMING.debug : PROGRESSIVE_ASSISTANCE_TIMING.production
}
 
/**
 * Check if we should use debug timing
 * - Always false in production builds
 * - True in development if localStorage flag is set or storybook
 */
export function shouldUseDebugTiming(): boolean {
  if (typeof window === 'undefined') return false
  if (process.env.NODE_ENV === 'production') return false

  // Check for storybook
  if (window.location?.href?.includes('storybook')) return true

  // Check for localStorage flag
  try {
    return localStorage.getItem('helpDebugTiming') === 'true'
  } catch {
    return false
  }
}