track time
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { type FC, useEffect, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { toast } from "react-toastify";
|
||||
import { ErrorType } from "../../../../../helpers/types";
|
||||
import { useEndTimeTracking, useGetTaskTimes, useStartTimeTracking } from "../../../task/hooks/useTaskTimeData";
|
||||
import { formatElapsedTime, getActiveTimeEntry, getElapsedSeconds } from "./utils";
|
||||
|
||||
type Props = {
|
||||
taskId: string;
|
||||
};
|
||||
|
||||
const TaskDetailTimePopover: FC<Props> = ({ taskId }) => {
|
||||
const { t } = useTranslation("global");
|
||||
const getTaskTimes = useGetTaskTimes(taskId);
|
||||
const startTimeTracking = useStartTimeTracking();
|
||||
const endTimeTracking = useEndTimeTracking();
|
||||
|
||||
const times = useMemo(() => getTaskTimes.data?.data ?? [], [getTaskTimes.data]);
|
||||
const activeEntry = useMemo(() => getActiveTimeEntry(times), [times]);
|
||||
const isTracking = !!activeEntry;
|
||||
const isSubmitting = startTimeTracking.isPending || endTimeTracking.isPending;
|
||||
|
||||
const [elapsedSeconds, setElapsedSeconds] = useState(() =>
|
||||
activeEntry ? getElapsedSeconds(activeEntry.startedAt) : 0,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeEntry) {
|
||||
setElapsedSeconds(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const updateElapsed = () => {
|
||||
setElapsedSeconds(getElapsedSeconds(activeEntry.startedAt));
|
||||
};
|
||||
|
||||
updateElapsed();
|
||||
const intervalId = window.setInterval(updateElapsed, 1000);
|
||||
|
||||
return () => {
|
||||
window.clearInterval(intervalId);
|
||||
};
|
||||
}, [activeEntry?.id, activeEntry?.startedAt]);
|
||||
|
||||
const handleStart = () => {
|
||||
startTimeTracking.mutate(taskId, {
|
||||
onSuccess: () => {
|
||||
toast.success(t("success"));
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error.response?.data?.error.message[0]);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleStop = () => {
|
||||
endTimeTracking.mutate(taskId, {
|
||||
onSuccess: () => {
|
||||
toast.success(t("success"));
|
||||
},
|
||||
onError: (error: ErrorType) => {
|
||||
toast.error(error.response?.data?.error.message[0]);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex min-h-9 w-full items-center">
|
||||
{isTracking ? (
|
||||
<div className="flex w-full items-center justify-between gap-3">
|
||||
<span className="font-mono text-sm font-bold tracking-wider text-[#01347A]">
|
||||
{formatElapsedTime(elapsedSeconds)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleStop}
|
||||
disabled={isSubmitting}
|
||||
className="shrink-0 rounded-lg bg-[#FF4D4F] px-3 py-1.5 text-[11px] font-medium text-white disabled:opacity-60"
|
||||
>
|
||||
{t("taskmanager.task_detail.stop_tracking")}
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleStart}
|
||||
disabled={isSubmitting}
|
||||
className="w-full rounded-lg bg-primary px-3 py-2 text-[11px] font-medium text-white disabled:opacity-60"
|
||||
>
|
||||
{t("taskmanager.task_detail.start_tracking")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TaskDetailTimePopover;
|
||||
Reference in New Issue
Block a user