Use it in Next.js
app/upload/Uploader.tsx
"use client";
// Before: <Dropzone getUploadParams={() => ({ url: "/api/upload" })} onChangeStatus={...} onSubmit={...} />
import { UploadDropzone, type Uploader, type UploadItem } from "@/components/upload-dropzone/UploadDropzone";
// What getUploadParams used to return: where the file goes and what rides along with it.
function uploadParams(file: File) {
return { url: "/api/upload", fields: { name: file.name }, headers: {} as Record<string, string> };
}
// XMLHttpRequest, because fetch still has no upload progress event.
const upload: Uploader = (file, onProgress, signal) =>
new Promise<void>((resolve, reject) => {
const { url, fields, headers } = uploadParams(file);
const body = new FormData();
for (const [key, value] of Object.entries(fields)) body.append(key, value);
body.append("file", file);
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
for (const [key, value] of Object.entries(headers)) xhr.setRequestHeader(key, value);
xhr.upload.onprogress = (e) => {
if (e.lengthComputable) onProgress((e.loaded / e.total) * 100);
};
xhr.onload = () => (xhr.status < 300 ? resolve() : reject(new Error(`Upload failed (${xhr.status})`)));
xhr.onerror = () => reject(new Error("Network error"));
xhr.onabort = () => reject(new DOMException("Upload cancelled", "AbortError"));
// removing a row aborts its upload, the way RDU's cancel button did
signal.addEventListener("abort", () => xhr.abort());
xhr.send(body);
});
export default function Uploader() {
return (
<UploadDropzone
upload={upload}
accept="image/*,audio/*,video/*"
maxSize={20 * 1024 * 1024}
hint="up to 20 MB each"
chips={["JPG", "PNG", "MP3", "MP4"]}
onAllDone={(items: UploadItem[]) => {
// RDU's onSubmit got the finished files; here they arrive once every row is done
console.log(items.filter((i) => i.status === "done").map((i) => i.name));
}}
/>
);
}
app/api/upload/route.ts
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const form = await req.formData();
const file = form.get("file");
if (!(file instanceof File)) return NextResponse.json({ error: "No file" }, { status: 400 });
// hand the file to S3, R2, Supabase Storage or your disk here
const bytes = Buffer.from(await file.arrayBuffer());
return NextResponse.json({ name: file.name, size: bytes.length });
}