158 lines
4.8 KiB
TypeScript
158 lines
4.8 KiB
TypeScript
"use client";
|
|
|
|
import { usePathname, useRouter } from "next/navigation";
|
|
import { toast } from "@/components/ui/use-toast";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
import { useUpdateHour } from "@lifetracker/shared-react/hooks/days";
|
|
import { EditableText } from "@/components/dashboard/EditableText";
|
|
import { format } from "date-fns";
|
|
import { TZDate } from "@date-fns/tz";
|
|
import { ZHour } from "@lifetracker/shared/types/days";
|
|
import { useEffect, useRef } from "react";
|
|
|
|
function selectNext(time: number) {
|
|
document.getElementById("hour-" + (time).toString())?.getElementsByClassName("edit-hour-code")[0].focus();
|
|
}
|
|
|
|
function EditCode({
|
|
originalText,
|
|
hour,
|
|
onSubmit
|
|
}) {
|
|
const ref = useRef<HTMLInputElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (ref.current) {
|
|
ref.current.value = originalText;
|
|
}
|
|
}, [ref]);
|
|
|
|
const submit = () => {
|
|
let newCode: string | null = ref.current?.value ?? null;
|
|
if (originalText == newCode) {
|
|
// Nothing to do here
|
|
return;
|
|
}
|
|
if (newCode == "") {
|
|
if (originalText == null) {
|
|
// Set value to previous hour's value
|
|
newCode = document.getElementById("hour-" + (hour.time - 1).toString())?.getElementsByClassName("edit-hour-code")[0].value;
|
|
console.log(newCode);
|
|
}
|
|
else {
|
|
newCode = null;
|
|
}
|
|
}
|
|
// console.log(hour);
|
|
onSubmit({
|
|
dateQuery: hour.date,
|
|
time: hour.time,
|
|
code: newCode,
|
|
})
|
|
selectNext(hour.time + 1);
|
|
};
|
|
|
|
return (
|
|
<input
|
|
className="w-8 border-b-2 text-center edit-hour-code"
|
|
style={{
|
|
background: hour.background, color: hour.foreground, fontFamily: "inherit",
|
|
}}
|
|
ref={ref}
|
|
defaultValue={originalText}
|
|
onKeyDown={(e) => {
|
|
if (e.key === "Enter") {
|
|
e.preventDefault();
|
|
submit();
|
|
}
|
|
if (e.key == "ArrowDown") {
|
|
e.preventDefault();
|
|
selectNext(hour.time + 1);
|
|
}
|
|
if (e.key == "ArrowUp") {
|
|
e.preventDefault();
|
|
selectNext(hour.time - 1);
|
|
}
|
|
}}
|
|
onClick={(e) => {
|
|
const range = document.createRange();
|
|
range.selectNodeContents(ref.current);
|
|
const selection = window.getSelection();
|
|
if (selection) {
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
}
|
|
}}
|
|
/>
|
|
// <input type="text"
|
|
// className="w-10 bg-inherit border-b-2 text-center"
|
|
// style={{ color: "inherit", borderColor: "inherit" }}
|
|
// onKeyDown={(e) => {
|
|
// if (e.key === "Enter") {
|
|
// e.preventDefault();
|
|
// onSave();
|
|
// }
|
|
// }}
|
|
// value={originalText.originalText ?? ""}
|
|
// />
|
|
);
|
|
}
|
|
|
|
|
|
export default function EditableHour({
|
|
hour,
|
|
className,
|
|
}: {
|
|
hour: ZHour,
|
|
className?: string;
|
|
}) {
|
|
const router = useRouter();
|
|
const currentPath = usePathname();
|
|
const { mutate: updateHour, isPending } = useUpdateHour({
|
|
onSuccess: () => {
|
|
toast({
|
|
description: "Hour updated!",
|
|
});
|
|
if (currentPath.includes("dashboard")) {
|
|
router.refresh();
|
|
}
|
|
},
|
|
});
|
|
|
|
function isActiveHour(hour: ZHour) {
|
|
const now = new TZDate();
|
|
return (hour.date == format(now, "yyyy-MM-dd")) && (((now.getHours()) + (now.getTimezoneOffset() / 60) - (parseInt(hour.time))) == 0)
|
|
}
|
|
return (
|
|
<div className={cn(
|
|
"p-4 grid justify-between",
|
|
)}
|
|
style={{
|
|
background: hour.background, color: hour.foreground, fontFamily: "inherit",
|
|
gridTemplateColumns: "100px 100px 1fr 200px"
|
|
}}
|
|
>
|
|
<span className="text-right">
|
|
{isActiveHour(hour) && "--> "}
|
|
{hour.datetime}
|
|
</span>
|
|
<div className="flex justify-center">
|
|
<EditCode
|
|
originalText={hour.categoryCode}
|
|
hour={hour}
|
|
onSubmit={updateHour}
|
|
/>
|
|
</div>
|
|
<span>
|
|
{hour.categoryDesc || " "}
|
|
</span>
|
|
<div className="text-right">
|
|
<EditableText
|
|
originalText={hour.comment || " "}
|
|
viewClassName="text-right"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |