"use client"; import { useEffect, useRef, useState } from "react"; import { useTranslations } from "next-intl"; const MAX_BYTES = 512 * 1024 * 1024; // 512 MB interface Props { onClose: () => void; onUploaded: (fileId: string) => void; } function formatBytes(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(2)} MB`; } export default function UploadFileModal({ onClose, onUploaded }: Props) { const t = useTranslations("common"); const [file, setFile] = useState(null); const [dragging, setDragging] = useState(false); const [uploading, setUploading] = useState(false); const [error, setError] = useState(null); const inputRef = useRef(null); const overlayRef = useRef(null); // Escape key → onClose useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; document.addEventListener("keydown", handler); return () => document.removeEventListener("keydown", handler); }, [onClose]); function validateAndSet(picked: File) { setError(null); if (!picked.name.endsWith(".jsonl")) { setError(t("uploadModalError")); return; } if (picked.size > MAX_BYTES) { setError(t("uploadModalError")); return; } setFile(picked); } function handleInputChange(e: React.ChangeEvent) { const picked = e.target.files?.[0]; if (picked) validateAndSet(picked); // Reset input so the same file can be re-picked after Remove e.target.value = ""; } function handleDragOver(e: React.DragEvent) { e.preventDefault(); setDragging(true); } function handleDragLeave(e: React.DragEvent) { e.preventDefault(); setDragging(false); } function handleDrop(e: React.DragEvent) { e.preventDefault(); setDragging(false); const picked = e.dataTransfer.files?.[0]; if (picked) validateAndSet(picked); } async function handleUpload() { if (!file || uploading) return; setUploading(true); setError(null); try { const form = new FormData(); form.append("purpose", "batch"); // D22 hardcoded form.append("file", file); const res = await fetch("/api/v1/files", { method: "POST", body: form }); if (!res.ok) { setError(t("uploadModalError")); return; } const data = (await res.json()) as { id: string }; onUploaded(data.id); onClose(); } catch (err) { console.error("[UploadFileModal]", err); setError(t("uploadModalError")); } finally { setUploading(false); } } return (
{/* Overlay */} ); }