"use client"; import type React from "react"; import { useState, useEffect } from "react"; import { toast } from "sonner"; import { useAuth } from "@/hooks/use-auth"; import { uploadAttachment, deleteAttachment } from "@/services/api-attachments"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { MultiSelect } from "@/components/multi-select"; import type { Todo, Tag } from "@/services/api-types"; import { Progress } from "./ui/progress"; interface TodoFormProps { todo?: Todo; tags: Tag[]; onSubmit: (todo: Partial) => Promise; onAttachmentsChanged?: (attachments: string[]) => void; // Now just an array of one or zero } export function TodoForm({ todo, tags, onSubmit, onAttachmentsChanged, }: TodoFormProps) { const { token } = useAuth(); const [formData, setFormData] = useState>({ title: "", description: "", status: "pending", deadline: undefined, tagIds: [], attachmentUrl: null, }); const [isUploading, setIsUploading] = useState(false); const [uploadProgress, setUploadProgress] = useState(0); useEffect(() => { if (todo) { setFormData({ title: todo.title, description: todo.description || "", status: todo.status, deadline: todo.deadline, tagIds: todo.tagIds || [], attachmentUrl: todo.attachmentUrl || null, }); } else { setFormData({ title: "", description: "", status: "pending", deadline: undefined, tagIds: [], attachmentUrl: null, }); } }, [todo]); const handleChange = ( e: React.ChangeEvent ) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); }; const handleSelectChange = (name: string, value: string) => { setFormData((prev) => ({ ...prev, [name]: value })); }; const handleTagsChange = (selected: string[]) => { setFormData((prev) => ({ ...prev, tagIds: selected })); }; // Upload new attachment const handleFileChange = async (e: React.ChangeEvent) => { // Only one attachment is supported, so uploading a new one replaces the old if (!todo || !token) { toast.error("Cannot attach files until the todo is saved."); return; } const file = e.target.files?.[0]; if (!file) return; // Only allow images if (!file.type.startsWith("image/")) { toast.error("Only image files are allowed."); return; } setIsUploading(true); setUploadProgress(0); // Simulate progress for demo – replace if backend supports it const progressInterval = setInterval(() => { setUploadProgress((p) => Math.min(p + 10, 90)); }, 200); try { const response = await uploadAttachment(todo.id, file, token); clearInterval(progressInterval); setUploadProgress(100); toast.success(`Uploaded: "${response.fileName}"`); setFormData((f) => ({ ...f, attachmentUrl: response.fileUrl })); onAttachmentsChanged?.([response.fileUrl]); setTimeout(() => { setIsUploading(false); setUploadProgress(0); }, 500); } catch (err) { clearInterval(progressInterval); setIsUploading(false); setUploadProgress(0); console.error(err); toast.error( `Upload failed: ${err instanceof Error ? err.message : "Unknown error"}` ); } finally { e.target.value = ""; } }; // Remove an existing attachment const handleRemoveAttachment = async (attachmentId: string) => { // Only one attachment is supported, so attachmentId is ignored if (!todo || !token) { toast.error("Cannot remove attachments right now."); return; } try { await deleteAttachment(todo.id, attachmentId, token); // Only one attachment is supported now, so just clear the attachmentUrl setFormData((f) => ({ ...f, attachmentUrl: null })); onAttachmentsChanged?.([]); toast.success("Attachment removed."); } catch (err) { console.error(err); toast.error( `Delete failed: ${err instanceof Error ? err.message : "Unknown error"}` ); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); await onSubmit(formData); }; return (
{/* Title, Description, Status, Deadline, Tags... */}