42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
import { useState, useEffect, useRef } from 'react'
|
|
|
|
export function useSessionTimer(startedAt: string | undefined | null): string | null {
|
|
const [elapsed, setElapsed] = useState<string | null>(null)
|
|
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
|
|
|
useEffect(() => {
|
|
// Always clear any previous interval before (re)initializing.
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current)
|
|
intervalRef.current = null
|
|
}
|
|
|
|
if (!startedAt) return
|
|
|
|
const parsedStartTime = new Date(startedAt).getTime()
|
|
// If the server timestamp is invalid or ahead of the local clock, fall back to "now"
|
|
// so the timer still starts ticking immediately for the user.
|
|
const startTime = Number.isNaN(parsedStartTime) || parsedStartTime > Date.now()
|
|
? Date.now()
|
|
: parsedStartTime
|
|
|
|
const tick = () => {
|
|
const diff = Math.max(0, Math.floor((Date.now() - startTime) / 1000))
|
|
const hours = Math.floor(diff / 3600)
|
|
const minutes = Math.floor((diff % 3600) / 60)
|
|
const seconds = diff % 60
|
|
const pad = (n: number) => String(n).padStart(2, '0')
|
|
setElapsed(hours > 0 ? `${pad(hours)}:${pad(minutes)}:${pad(seconds)}` : `${pad(minutes)}:${pad(seconds)}`)
|
|
}
|
|
|
|
tick()
|
|
intervalRef.current = setInterval(tick, 1000)
|
|
|
|
return () => {
|
|
if (intervalRef.current) clearInterval(intervalRef.current)
|
|
}
|
|
}, [startedAt])
|
|
|
|
return startedAt ? elapsed : null
|
|
}
|