"use client"; import { useState, useCallback, useRef } from "react"; import { useMutation } from "convex/react"; import { ArrowUpRight, MoreHorizontal, Pencil } from "lucide-react"; import { toast } from "@/lib/toast"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Input } from "@/components/ui/input"; import { api } from "@/convex/_generated/api"; import type { Id } from "@/convex/_generated/dataModel"; import { cn } from "@/lib/utils"; interface CanvasCardProps { canvas: { _id: Id<"canvases">; name: string }; onNavigate: (id: Id<"canvases">) => void; } export default function CanvasCard({ canvas, onNavigate }: CanvasCardProps) { const [isEditing, setIsEditing] = useState(false); const [editName, setEditName] = useState(canvas.name); const [isSaving, setIsSaving] = useState(false); const inputRef = useRef(null); const suppressCardNavigationRef = useRef(false); const saveInFlightRef = useRef(false); const updateCanvas = useMutation(api.canvases.update); const handleStartEdit = useCallback(() => { suppressCardNavigationRef.current = true; setEditName(canvas.name); setIsEditing(true); setTimeout(() => { inputRef.current?.select(); setTimeout(() => { suppressCardNavigationRef.current = false; }, 0); }, 0); }, [canvas.name]); const handleSave = useCallback(async () => { const trimmedName = editName.trim(); if (!trimmedName) { toast.error("Name darf nicht leer sein"); return; } if (trimmedName === canvas.name) { setIsEditing(false); return; } if (saveInFlightRef.current) return; saveInFlightRef.current = true; setIsSaving(true); try { await updateCanvas({ canvasId: canvas._id, name: trimmedName }); toast.success("Arbeitsbereich umbenannt"); setIsEditing(false); } catch { toast.error("Fehler beim Umbenennen"); } finally { setIsSaving(false); saveInFlightRef.current = false; } }, [editName, canvas.name, canvas._id, updateCanvas]); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === "Enter") { e.preventDefault(); handleSave(); } else if (e.key === "Escape") { e.preventDefault(); setIsEditing(false); setEditName(canvas.name); } }, [handleSave, canvas.name] ); // Prevent duplicate toast: only save on blur if still in editing mode const handleBlur = useCallback(() => { if (!isEditing) return; handleSave(); }, [isEditing, handleSave]); const handleCardClick = useCallback(() => { if (suppressCardNavigationRef.current) return; if (!isEditing) { onNavigate(canvas._id); } }, [isEditing, onNavigate, canvas._id]); return (
{/* Avatar */}
{canvas.name.slice(0, 1).toUpperCase()}
{/* Content */}
{isEditing ? ( setEditName(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleBlur} disabled={isSaving} autoFocus onClick={(e) => e.stopPropagation()} className="h-auto py-0.5 text-sm font-medium bg-transparent border px-1.5 focus-visible:ring-1" /> ) : (

{canvas.name}

)}

Canvas

{/* Actions - positioned to not overlap with content */} {!isEditing && (
Umbenennen
)}
); }