added edit tasks
Deploy / deploy (push) Successful in 4m5s

This commit is contained in:
twotalesanimation
2026-05-29 09:35:35 +02:00
parent 0723bea4ee
commit 521eb38dcd
3 changed files with 281 additions and 10 deletions
@@ -123,6 +123,12 @@ export function TaskDetailClient({
const { toast } = useToast();
const [showUpload, setShowUpload] = useState(false);
const [updatingStatus, setUpdatingStatus] = useState(false);
const [dueDateValue, setDueDateValue] = useState(
task.dueDate ? format(new Date(task.dueDate), "yyyy-MM-dd") : ""
);
const [estimatedHoursValue, setEstimatedHoursValue] = useState(
task.estimatedHours != null ? String(task.estimatedHours) : ""
);
const statusCfg = TASK_STATUS_CONFIG[task.status];
const StatusIcon = statusCfg.icon;
@@ -147,6 +153,27 @@ export function TaskDetailClient({
}
};
const handleDueDateChange = async (value: string) => {
setDueDateValue(value);
try {
await updateTask(task.id, { dueDate: value || null });
router.refresh();
} catch {
toast({ title: "Failed to update due date", variant: "destructive" });
}
};
const handleEstimatedHoursBlur = async () => {
const parsed = estimatedHoursValue === "" ? null : parseFloat(estimatedHoursValue);
if (parsed !== null && (isNaN(parsed) || parsed <= 0)) return;
try {
await updateTask(task.id, { estimatedHours: parsed });
router.refresh();
} catch {
toast({ title: "Failed to update estimated hours", variant: "destructive" });
}
};
const handleAssigneeChange = async (artistId: string) => {
try {
await updateTask(task.id, { assignedArtistId: artistId === "__none__" ? null : artistId });
@@ -410,26 +437,51 @@ export function TaskDetailClient({
</p>
</div>
{task.dueDate && (
<div>
<p className="text-xs text-zinc-500 mb-1">Due Date</p>
<div>
<p className="text-xs text-zinc-500 mb-1">Due Date</p>
{canManage ? (
<input
type="date"
value={dueDateValue}
onChange={(e) => handleDueDateChange(e.target.value)}
className="w-full text-sm bg-transparent border border-border rounded-md px-2 py-1 text-zinc-300 focus:outline-none focus:ring-1 focus:ring-amber-500/50 [color-scheme:dark]"
/>
) : task.dueDate ? (
<p className={cn("text-sm flex items-center gap-1.5", isOverdue ? "text-red-400" : "text-zinc-300")}>
<CalendarDays className="h-3.5 w-3.5" />
{format(new Date(task.dueDate), "MMM d, yyyy")}
{isOverdue && <span className="text-xs">(Overdue)</span>}
</p>
</div>
)}
) : (
<p className="text-sm text-zinc-600"></p>
)}
</div>
{task.estimatedHours && (
<div>
<p className="text-xs text-zinc-500 mb-1">Estimated</p>
<div>
<p className="text-xs text-zinc-500 mb-1">Estimated Hours</p>
{canManage ? (
<div className="flex items-center gap-1.5">
<input
type="number"
min="0"
step="0.5"
value={estimatedHoursValue}
onChange={(e) => setEstimatedHoursValue(e.target.value)}
onBlur={handleEstimatedHoursBlur}
placeholder="—"
className="w-full text-sm bg-transparent border border-border rounded-md px-2 py-1 text-zinc-300 focus:outline-none focus:ring-1 focus:ring-amber-500/50 [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none"
/>
<span className="text-sm text-zinc-500 shrink-0">h</span>
</div>
) : task.estimatedHours ? (
<p className="text-sm flex items-center gap-1.5">
<Clock className="h-3.5 w-3.5 text-zinc-400" />
{task.estimatedHours}h
</p>
</div>
)}
) : (
<p className="text-sm text-zinc-600"></p>
)}
</div>
</div>
</div>