import { useState, useCallback } from "react"; /* ================= TYPES ================= */ export interface UploadItem { id: string; file: File; progress: number; // 0 → 100 status: "idle" | "uploading" | "done" | "error"; url?: string; error?: string; } /* ================= HOOK ================= */ export function useFileUpload() { const [uploads, setUploads] = useState([]); /* ---------- ADD FILE ---------- */ const addFiles = useCallback((files: FileList | File[]) => { const list = Array.from(files).map((file) => ({ id: crypto.randomUUID(), file, progress: 0, status: "idle" as const, })); setUploads((prev) => [...prev, ...list]); }, []); /* ---------- UPLOAD SINGLE FILE ---------- */ const uploadFile = useCallback(async (item: UploadItem) => { const form = new FormData(); form.append("file", item.file); setUploads((prev) => prev.map((u) => u.id === item.id ? { ...u, status: "uploading", progress: 0 } : u ) ); try { const xhr = new XMLHttpRequest(); xhr.open("POST", "/api/upload"); xhr.upload.onprogress = (e) => { if (!e.lengthComputable) return; const percent = Math.round((e.loaded / e.total) * 100); setUploads((prev) => prev.map((u) => u.id === item.id ? { ...u, progress: percent } : u ) ); }; const result: any = await new Promise((resolve, reject) => { xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.responseText)); } else { reject(new Error("Upload failed")); } }; xhr.onerror = () => reject(new Error("Network error")); xhr.send(form); }); setUploads((prev) => prev.map((u) => u.id === item.id ? { ...u, status: "done", progress: 100, url: result.url, } : u ) ); } catch (err: any) { setUploads((prev) => prev.map((u) => u.id === item.id ? { ...u, status: "error", error: err.message || "Upload error", } : u ) ); } }, []); /* ---------- UPLOAD ALL ---------- */ const uploadAll = useCallback(async () => { for (const item of uploads) { if (item.status === "idle") { await uploadFile(item); } } }, [uploads, uploadFile]); /* ---------- REMOVE FILE ---------- */ const remove = useCallback((id: string) => { setUploads((prev) => prev.filter((u) => u.id !== id)); }, []); /* ---------- RESET ---------- */ const reset = useCallback(() => { setUploads([]); }, []); return { uploads, addFiles, uploadFile, uploadAll, remove, reset, }; }