1
0
Fork 0
panel/components/cards/SafetyNotesCard.tsx

116 lines
3.6 KiB
TypeScript

"use client"
import { useEffect, useState } from "react";
import { Textarea } from "../ui/textarea";
import { toast } from "../ui/use-toast";
import { SafetyNotes, fetchSafetyNote, updateSafetyNote } from "@/lib/db";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../ui/card";
import { useSession } from "next-auth/react";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
dayjs.extend(relativeTime);
export default function SafetyNotesCard({ objectId, type, title }: {
objectId: string,
type: SafetyNotes["_id"]["type"],
title?: string
}) {
const session = useSession();
const [draft, setDraft] = useState("");
const [value, setValue] = useState<SafetyNotes | null>(null);
const [ready, setReady] = useState(false);
const [error, setError] = useState<string | null>(null);
const [editing, setEditing] = useState(false);
useEffect(() => {
fetchSafetyNote(objectId, type)
.then((note) => {
setDraft(note?.text || "");
setValue(note);
setReady(true);
})
.catch((e) => {
setError(String(e));
});
}, [objectId, type]);
return (
<Card>
<CardHeader>
<CardTitle>{title ?? type.charAt(0).toUpperCase() + type.slice(1) + " notes"}</CardTitle>
</CardHeader>
<CardContent>
{
editing
? <Textarea
placeholder={
error
? error
: ready
? "Enter notes here... (save on unfocus)"
: "Fetching notes..."
}
className="!min-h-[80px] max-h-[50vh]"
disabled={!ready || error != null}
value={ready ? draft : undefined} // not defaulting to undefined causes next to complain
autoFocus
onChange={(e) => setDraft(e.currentTarget.value)}
onBlur={async () => {
if (draft === value?.text ?? "") return setEditing(false);
try {
await updateSafetyNote(objectId, type, draft);
setValue({
_id: { id: objectId, type: type },
edited_at: new Date(Date.now()),
edited_by: session.data?.user?.email || "",
text: draft,
});
setEditing(false);
toast({
title: "Updated notes",
});
} catch (err) {
setEditing(false);
toast({
title: "Failed to update notes",
description: String(err),
variant: "destructive",
});
}
}}
/>
: <div onClick={() => setEditing(true)}>
{
error
? <>{error}</>
: value?.text
? <ReactMarkdown
className="prose prose-a:text-[#fd6671] prose-img:max-h-96"
remarkPlugins={[remarkGfm]}
>
{value.text}
</ReactMarkdown>
: ready
? <i>Click to add a note</i>
: <i>Fetching notes...</i>
}
</div>
}
</CardContent>
<CardFooter className="-my-2">
<CardDescription>
{
value
? <>Last edited {dayjs(value.edited_at).fromNow()} by {value.edited_by}</>
: <>No object note set</>
}
</CardDescription>
</CardFooter>
</Card>
)
}