/ hooks / useElapsedTime.ts
useElapsedTime.ts
 1  import { useCallback, useSyncExternalStore } from 'react'
 2  import { formatDuration } from '../utils/format.js'
 3  
 4  /**
 5   * Hook that returns formatted elapsed time since startTime.
 6   * Uses useSyncExternalStore with interval-based updates for efficiency.
 7   *
 8   * @param startTime - Unix timestamp in ms
 9   * @param isRunning - Whether to actively update the timer
10   * @param ms - How often should we trigger updates?
11   * @param pausedMs - Total paused duration to subtract
12   * @param endTime - If set, freezes the duration at this timestamp (for
13   *   terminal tasks). Without this, viewing a 2-min task 30 min after
14   *   completion would show "32m".
15   * @returns Formatted duration string (e.g., "1m 23s")
16   */
17  export function useElapsedTime(
18    startTime: number,
19    isRunning: boolean,
20    ms: number = 1000,
21    pausedMs: number = 0,
22    endTime?: number,
23  ): string {
24    const get = () =>
25      formatDuration(Math.max(0, (endTime ?? Date.now()) - startTime - pausedMs))
26  
27    const subscribe = useCallback(
28      (notify: () => void) => {
29        if (!isRunning) return () => {}
30        const interval = setInterval(notify, ms)
31        return () => clearInterval(interval)
32      },
33      [isRunning, ms],
34    )
35  
36    return useSyncExternalStore(subscribe, get, get)
37  }