All files / src/hooks useTimers.ts

98.03% Statements 50/51
76.92% Branches 10/13
100% Functions 21/21
100% Lines 45/45

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                                            38x 38x 38x   38x 11x     38x 11x 11x 11x       38x 13x   13x         13x 9x 9x 9x     13x     38x 8x   8x 8x 8x   8x 8x 10x         38x 2x 2x 2x 2x         38x 1x 1x 1x 1x             38x 1x 2x     38x   2x 2x 2x 1x   1x           38x          
import { useState, useEffect, useRef, useCallback } from 'react'
import { createTimerTick, clearTimerInterval } from './timerUtils'
 
export interface Timer {
  id: string
  label: string
  duration: number // seconds
  remaining: number // seconds
  isRunning: boolean
}
 
export interface UseTimersReturn {
  timers: Timer[]
  addTimer: (label: string, duration: number, autoStart?: boolean) => string
  startTimer: (id: string) => void
  pauseTimer: (id: string) => void
  resetTimer: (id: string) => void
  deleteTimer: (id: string) => void
  toggleTimer: (id: string) => void
}
 
export function useTimers(onTimerComplete?: (timer: Timer) => void): UseTimersReturn {
  const [timers, setTimers] = useState<Timer[]>([])
  const intervalsRef = useRef<Map<string, number>>(new Map())
  const onCompleteRef = useRef(onTimerComplete)
 
  useEffect(() => {
    onCompleteRef.current = onTimerComplete
  }, [onTimerComplete])
 
  useEffect(() => {
    const intervals = intervalsRef.current
    return () => {
      intervals.forEach((intervalId) => clearInterval(intervalId))
    }
  }, [])
 
  const addTimer = useCallback((label: string, duration: number, autoStart: boolean = true): string => {
    const id = crypto.randomUUID()
 
    setTimers((prev) => [
      ...prev,
      { id, label, duration, remaining: duration, isRunning: autoStart },
    ])
 
    if (autoStart) {
      const tick = createTimerTick(id, intervalsRef, onCompleteRef, setTimers)
      const intervalId = window.setInterval(tick, 1000)
      intervalsRef.current.set(id, intervalId)
    }
 
    return id
  }, [])
 
  const startTimer = useCallback((id: string) => {
    clearTimerInterval(id, intervalsRef)
 
    const tick = createTimerTick(id, intervalsRef, onCompleteRef, setTimers)
    const intervalId = window.setInterval(tick, 1000)
    intervalsRef.current.set(id, intervalId)
 
    setTimers((prev) =>
      prev.map((timer) =>
        timer.id === id ? { ...timer, isRunning: true } : timer
      )
    )
  }, [])
 
  const pauseTimer = useCallback((id: string) => {
    clearTimerInterval(id, intervalsRef)
    setTimers((prev) =>
      prev.map((timer) =>
        timer.id === id ? { ...timer, isRunning: false } : timer
      )
    )
  }, [])
 
  const resetTimer = useCallback((id: string) => {
    clearTimerInterval(id, intervalsRef)
    setTimers((prev) =>
      prev.map((timer) =>
        timer.id === id
          ? { ...timer, remaining: timer.duration, isRunning: false }
          : timer
      )
    )
  }, [])
 
  const deleteTimer = useCallback((id: string) => {
    clearTimerInterval(id, intervalsRef)
    setTimers((prev) => prev.filter((timer) => timer.id !== id))
  }, [])
 
  const toggleTimer = useCallback(
    (id: string) => {
      const timer = timers.find((t) => t.id === id)
      Iif (!timer) return
      if (timer.isRunning) {
        pauseTimer(id)
      } else {
        startTimer(id)
      }
    },
    [timers, pauseTimer, startTimer]
  )
 
  return { timers, addTimer, startTimer, pauseTimer, resetTimer, deleteTimer, toggleTimer }
}
 
// Re-export utilities for consumers
export { detectTimes, formatTimerDisplay } from './timerUtils'
 
← Back to Dashboard