diff --git a/components/devices/DevicesTable.tsx b/components/devices/DevicesTable.tsx index a55112e..93caeaf 100644 --- a/components/devices/DevicesTable.tsx +++ b/components/devices/DevicesTable.tsx @@ -1,11 +1,12 @@ "use client"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/navigation"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Input } from "@/components/ui/input"; -import { Button } from "@/components/ui/button"; +import { Check, Loader2 } from "lucide-react"; import { toast } from "sonner"; +import { cn } from "@/lib/utils"; export interface DeviceRow { id: number; @@ -14,34 +15,67 @@ export interface DeviceRow { lastConnectedAt: number | null; } +const AUTOSAVE_DELAY_MS = 600; + function DeviceNameCell({ device }: { device: DeviceRow }) { const router = useRouter(); - const [value, setValue] = useState(device.displayName ?? device.bleName); - const [saving, setSaving] = useState(false); + const initial = device.displayName ?? device.bleName; + const [value, setValue] = useState(initial); + const [status, setStatus] = useState<"idle" | "saving" | "saved">("idle"); + const lastSaved = useRef(initial); - async function handleSave() { - if (value.trim().length === 0) return; - setSaving(true); - const res = await fetch(`/api/devices/${device.id}`, { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ displayName: value.trim() }), - }); - setSaving(false); - if (res.ok) { - toast.success("Renamed"); - router.refresh(); - } else { - toast.error("Could not rename device"); - } - } + useEffect(() => { + const trimmed = value.trim(); + if (trimmed.length === 0 || trimmed === lastSaved.current) return; + + setStatus("saving"); + const timer = setTimeout(async () => { + const res = await fetch(`/api/devices/${device.id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ displayName: trimmed }), + }); + if (res.ok) { + lastSaved.current = trimmed; + setStatus("saved"); + router.refresh(); + } else { + setStatus("idle"); + toast.error("Could not rename device"); + } + }, AUTOSAVE_DELAY_MS); + + return () => clearTimeout(timer); + }, [value, device.id, router]); + + useEffect(() => { + if (status !== "saved") return; + const timer = setTimeout(() => setStatus("idle"), 1500); + return () => clearTimeout(timer); + }, [status]); return ( -