72 lines
1.7 KiB
TypeScript
72 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
|
|
import { formatSecondsToHHMMSS } from "@/shared/utils/date";
|
|
|
|
export interface UseTimerOptions {
|
|
initialSeconds: number;
|
|
persist?: boolean;
|
|
storageKey?: string;
|
|
}
|
|
|
|
export function useTimer({
|
|
initialSeconds,
|
|
persist = false,
|
|
storageKey,
|
|
}: UseTimerOptions) {
|
|
const [seconds, setSeconds] = useState<number>(() => {
|
|
if (persist && storageKey) {
|
|
const saved = localStorage.getItem(storageKey);
|
|
if (saved !== null) {
|
|
const parsed = parseInt(saved, 10);
|
|
if (!isNaN(parsed)) return parsed;
|
|
}
|
|
}
|
|
return initialSeconds;
|
|
});
|
|
|
|
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (persist && storageKey) {
|
|
localStorage.setItem(storageKey, seconds.toString());
|
|
}
|
|
}, [seconds, persist, storageKey]);
|
|
|
|
useEffect(() => {
|
|
if (seconds <= 0) return;
|
|
intervalRef.current = setInterval(() => {
|
|
setSeconds((prev) => {
|
|
if (prev <= 1) {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
}
|
|
return 0;
|
|
}
|
|
return prev - 1;
|
|
});
|
|
}, 1000);
|
|
return () => {
|
|
if (intervalRef.current) clearInterval(intervalRef.current);
|
|
};
|
|
}, [seconds]);
|
|
|
|
const reset = useCallback(() => {
|
|
setSeconds(initialSeconds);
|
|
if (persist && storageKey) {
|
|
localStorage.setItem(storageKey, initialSeconds.toString());
|
|
}
|
|
}, [initialSeconds, persist, storageKey]);
|
|
|
|
return useMemo(
|
|
() => ({
|
|
time: formatSecondsToHHMMSS(seconds, { isHours: false }),
|
|
seconds,
|
|
reset,
|
|
isFinished: seconds === 0,
|
|
}),
|
|
[seconds, reset]
|
|
);
|
|
}
|