diff --git a/src/components/ui/editable-cell.tsx b/src/components/ui/editable-cell.tsx new file mode 100644 index 0000000..230d5c5 --- /dev/null +++ b/src/components/ui/editable-cell.tsx @@ -0,0 +1,148 @@ +"use client"; + +import { useState, useRef, useEffect } from "react"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { cn } from "@/lib/utils"; + +export interface EditableCellProps { + value: string | number | boolean; + type?: "text" | "number" | "textarea" | "toggle"; + onSave: (value: string) => void; + required?: boolean; + placeholder?: string; + disabled?: boolean; + formatDisplay?: (value: string) => string; +} + +export function EditableCell({ + value, + type = "text", + onSave, + required, + placeholder, + disabled, + formatDisplay, +}: EditableCellProps) { + const [isEditing, setIsEditing] = useState(false); + const [tempValue, setTempValue] = useState(String(value)); + const [error, setError] = useState(null); + const inputRef = useRef(null); + + useEffect(() => { + setTempValue(String(value)); + }, [value]); + + useEffect(() => { + if (isEditing && inputRef.current) { + inputRef.current.focus(); + if ("select" in inputRef.current) { + inputRef.current.select(); + } + } + }, [isEditing]); + + function startEdit() { + if (disabled) return; + setError(null); + setTempValue(String(value)); + setIsEditing(true); + } + + function commit() { + if (required && tempValue.trim().length === 0) { + setError("Campo richiesto"); + return; + } + setError(null); + onSave(tempValue); + setIsEditing(false); + } + + function cancel() { + setTempValue(String(value)); + setError(null); + setIsEditing(false); + } + + function handleKeyDown(e: React.KeyboardEvent) { + if (e.key === "Enter" && type !== "textarea") { + e.preventDefault(); + commit(); + } else if (e.key === "Escape") { + e.preventDefault(); + cancel(); + } + } + + if (!isEditing) { + let display: string; + if (type === "toggle") { + display = tempValue === "true" ? "✓ Attivo" : "✗ Disattivato"; + } else { + const raw = String(value); + display = formatDisplay ? formatDisplay(raw) : raw || "—"; + } + + return ( +
+ {display} +
+ ); + } + + return ( +
+ {type === "textarea" ? ( +