diff --git a/app/(dashboard)/tasks/[taskId]/TaskDetailClient.tsx b/app/(dashboard)/tasks/[taskId]/TaskDetailClient.tsx index 0efa2a5..9021c30 100644 --- a/app/(dashboard)/tasks/[taskId]/TaskDetailClient.tsx +++ b/app/(dashboard)/tasks/[taskId]/TaskDetailClient.tsx @@ -27,6 +27,7 @@ import { submitApproval, unapproveVersion } from "@/actions/approvals"; import { useToast } from "@/components/ui/use-toast"; import { TaskStatus, TaskType } from "@prisma/client"; import { formatDistanceToNow, format } from "date-fns"; +import { Input } from "@/components/ui/input"; import { ArrowLeft, CalendarDays, @@ -46,6 +47,7 @@ import { Trash2, XCircle, MoreHorizontal, + Pencil, } from "lucide-react"; import { TASK_STATUS_CONFIG, TASK_TYPE_LABELS } from "@/components/tasks/TaskCard"; import { VersionUpload } from "@/components/versions/VersionUpload"; @@ -133,6 +135,9 @@ export function TaskDetailClient({ const [estimatedHoursValue, setEstimatedHoursValue] = useState( task.estimatedHours != null ? String(task.estimatedHours) : "" ); + const [editingTitle, setEditingTitle] = useState(false); + const [titleValue, setTitleValue] = useState(task.title); + const titleInputRef = useRef(null); const statusCfg = TASK_STATUS_CONFIG[task.status]; const StatusIcon = statusCfg.icon; @@ -178,6 +183,33 @@ export function TaskDetailClient({ } }; + const handleTitleSave = async () => { + const trimmed = titleValue.trim(); + if (!trimmed || trimmed === task.title) { + setTitleValue(task.title); + setEditingTitle(false); + return; + } + try { + await updateTask(task.id, { title: trimmed }); + router.refresh(); + } catch { + toast({ title: "Failed to update title", variant: "destructive" }); + setTitleValue(task.title); + } finally { + setEditingTitle(false); + } + }; + + const handleTitleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + e.currentTarget.blur(); + } else if (e.key === "Escape") { + setTitleValue(task.title); + setEditingTitle(false); + } + }; + const handleAssigneeChange = async (artistId: string) => { try { await updateTask(task.id, { assignedArtistId: artistId === "__none__" ? null : artistId }); @@ -241,7 +273,7 @@ export function TaskDetailClient({ )} / - {task.title} + {titleValue}
@@ -251,7 +283,33 @@ export function TaskDetailClient({
-

{task.title}

+ {editingTitle && canManage ? ( + setTitleValue(e.target.value)} + onBlur={handleTitleSave} + onKeyDown={handleTitleKeyDown} + className="text-2xl font-bold h-auto py-0.5 px-1 bg-transparent border-zinc-700 focus-visible:ring-amber-500/50" + autoFocus + /> + ) : ( +
+

{titleValue}

+ {canManage && ( + + )} +
+ )}
{TASK_TYPE_LABELS[task.type]} {parentLink && (