mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
feat: made use-stopwatch hook
This commit is contained in:
parent
a2825208b8
commit
72ab77fa6f
154
apps/app/hooks/use-stopwatch.tsx
Normal file
154
apps/app/hooks/use-stopwatch.tsx
Normal file
@ -0,0 +1,154 @@
|
||||
import { useState, useEffect, useCallback, useMemo } from "react";
|
||||
|
||||
// hooks
|
||||
import useLocalStorage from "hooks/use-local-storage";
|
||||
|
||||
type TimeSlot = {
|
||||
start_time: Date | string;
|
||||
end_time: Date | null | string;
|
||||
type: "START" | "PAUSE" | "RESUME" | "STOP";
|
||||
actual_time: number;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
key: string | null;
|
||||
};
|
||||
|
||||
const defaultValue: {
|
||||
actual_time_spent: number;
|
||||
time_slots: TimeSlot[];
|
||||
} = {
|
||||
actual_time_spent: 0,
|
||||
time_slots: [],
|
||||
};
|
||||
|
||||
const useStopwatch = (props: Props) => {
|
||||
const { key } = props;
|
||||
|
||||
const { storedValue, setValue } = useLocalStorage(key ?? "", defaultValue);
|
||||
|
||||
const [elapsed, setElapsed] = useState(0);
|
||||
|
||||
const start = useCallback(() => {
|
||||
setValue({
|
||||
actual_time_spent: 0,
|
||||
time_slots: [
|
||||
{
|
||||
start_time: new Date(),
|
||||
end_time: null,
|
||||
type: "START",
|
||||
actual_time: 0,
|
||||
},
|
||||
],
|
||||
});
|
||||
}, [setValue]);
|
||||
|
||||
const stop = useCallback(() => {
|
||||
if (!storedValue || storedValue.time_slots.length <= 0) return;
|
||||
|
||||
const lastTimeSlot = storedValue.time_slots[storedValue.time_slots.length - 1];
|
||||
|
||||
if (lastTimeSlot.type === "STOP") return;
|
||||
|
||||
const newTimeSlot = {
|
||||
start_time: lastTimeSlot.start_time,
|
||||
end_time: new Date(),
|
||||
type: "STOP" as const,
|
||||
actual_time:
|
||||
lastTimeSlot.type === "PAUSE"
|
||||
? lastTimeSlot.actual_time
|
||||
: lastTimeSlot.actual_time +
|
||||
(new Date().getTime() - new Date(lastTimeSlot.start_time).getTime()),
|
||||
};
|
||||
|
||||
setValue({
|
||||
actual_time_spent: storedValue.actual_time_spent + newTimeSlot.actual_time,
|
||||
time_slots: [...storedValue.time_slots, newTimeSlot],
|
||||
});
|
||||
}, [setValue, storedValue]);
|
||||
|
||||
const pause = useCallback(() => {
|
||||
if (!storedValue || storedValue.time_slots.length <= 0) return;
|
||||
|
||||
const lastTimeSlot = storedValue.time_slots[storedValue.time_slots.length - 1];
|
||||
|
||||
if (lastTimeSlot.type === "PAUSE") return;
|
||||
|
||||
const newTimeSlot = {
|
||||
start_time: lastTimeSlot.start_time,
|
||||
end_time: new Date(),
|
||||
type: "PAUSE" as const,
|
||||
actual_time:
|
||||
lastTimeSlot.actual_time +
|
||||
(new Date().getTime() - new Date(lastTimeSlot.start_time).getTime()),
|
||||
};
|
||||
|
||||
setValue({
|
||||
actual_time_spent: storedValue.actual_time_spent + newTimeSlot.actual_time,
|
||||
time_slots: [...storedValue.time_slots, newTimeSlot],
|
||||
});
|
||||
}, [setValue, storedValue]);
|
||||
|
||||
const resume = useCallback(() => {
|
||||
if (!storedValue || storedValue.time_slots.length <= 0) return;
|
||||
|
||||
const lastTimeSlot = storedValue.time_slots[storedValue.time_slots.length - 1];
|
||||
|
||||
if (lastTimeSlot.type === "RESUME") return;
|
||||
|
||||
const newTimeSlot = {
|
||||
start_time: new Date(),
|
||||
end_time: null,
|
||||
type: "RESUME" as const,
|
||||
actual_time: lastTimeSlot.actual_time,
|
||||
};
|
||||
|
||||
setValue({
|
||||
actual_time_spent: storedValue.actual_time_spent,
|
||||
time_slots: [...storedValue.time_slots, newTimeSlot],
|
||||
});
|
||||
}, [setValue, storedValue]);
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setElapsed(0);
|
||||
setValue(defaultValue);
|
||||
}, [setValue]);
|
||||
|
||||
const isRunning = useMemo(() => {
|
||||
if (!storedValue || storedValue.time_slots.length <= 0) return false;
|
||||
|
||||
const lastTimeSlot = storedValue.time_slots[storedValue.time_slots.length - 1];
|
||||
|
||||
return lastTimeSlot.type === "START" || lastTimeSlot.type === "RESUME";
|
||||
}, [storedValue]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!storedValue || storedValue.time_slots.length <= 0) return;
|
||||
|
||||
const lastTimeSlot = storedValue.time_slots[storedValue.time_slots.length - 1];
|
||||
|
||||
if (lastTimeSlot.type === "START" || lastTimeSlot.type === "RESUME") {
|
||||
const interval = setInterval(() => {
|
||||
setElapsed(
|
||||
lastTimeSlot.actual_time +
|
||||
(new Date().getTime() - new Date(lastTimeSlot.start_time).getTime())
|
||||
);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
} else setElapsed(lastTimeSlot.actual_time);
|
||||
}, [storedValue, setElapsed]);
|
||||
|
||||
return {
|
||||
elapsed,
|
||||
isRunning,
|
||||
start,
|
||||
stop,
|
||||
isStopped: storedValue?.time_slots[storedValue?.time_slots.length - 1]?.type === "STOP",
|
||||
reset,
|
||||
pause,
|
||||
resume,
|
||||
} as const;
|
||||
};
|
||||
|
||||
export default useStopwatch;
|
Loading…
Reference in New Issue
Block a user