import * as api from "@client/api"; import type { Job } from "@shared/types.js"; import { StickyNote } from "lucide-react"; import type React from "react"; import { useCallback, useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { Textarea } from "@/components/ui/textarea"; import { cn } from "@/lib/utils"; interface JobNotesProps { job: Job; onJobUpdated: () => void | Promise; className?: string; } const DEBOUNCE_MS = 800; export const JobNotes: React.FC = ({ job, onJobUpdated, className, }) => { const [value, setValue] = useState(job.notes ?? ""); const [isSaving, setIsSaving] = useState(false); const pendingRef = useRef(null); const timerRef = useRef | null>(null); const jobIdRef = useRef(job.id); useEffect(() => { if (jobIdRef.current !== job.id) { jobIdRef.current = job.id; if (timerRef.current) clearTimeout(timerRef.current); pendingRef.current = null; } setValue(job.notes ?? ""); }, [job.id, job.notes]); const persist = useCallback( async (text: string) => { try { setIsSaving(true); await api.updateJob(job.id, { notes: text || null }); await onJobUpdated(); } catch (error) { const msg = error instanceof Error ? error.message : "Failed to save notes"; toast.error(msg); } finally { setIsSaving(false); if (pendingRef.current !== null) { const next = pendingRef.current; pendingRef.current = null; void persist(next); } } }, [job.id, onJobUpdated], ); const scheduleFlush = useCallback( (text: string) => { if (timerRef.current) clearTimeout(timerRef.current); timerRef.current = setTimeout(() => { if (isSaving) { pendingRef.current = text; } else { void persist(text); } }, DEBOUNCE_MS); }, [isSaving, persist], ); const handleChange = (e: React.ChangeEvent) => { const next = e.target.value; setValue(next); scheduleFlush(next); }; const handleBlur = () => { if (timerRef.current) clearTimeout(timerRef.current); const trimmed = value; if (trimmed !== (job.notes ?? "")) { if (isSaving) { pendingRef.current = trimmed; } else { void persist(trimmed); } } }; return (
Notes {isSaving && ( Saving… )}