import { useEffect, useState } from "react"; import { Link, useNavigate, useParams } from "react-router"; import { API_URL } from "../config/api.ts"; import type { Dump, UpdateDumpRequest } from "../model.ts"; import { deserializeDump } from "../model.ts"; import { useRequiredAuth } from "../hooks/useAuth.ts"; import { formatBytes } from "../utils/format.ts"; import { PageShell } from "../components/PageShell.tsx"; import { PageError } from "../components/PageError.tsx"; import { ConfirmModal } from "../components/ConfirmModal.tsx"; import RichContentCard from "../components/RichContentCard.tsx"; import FilePreview from "../components/FilePreview.tsx"; type DumpEditState = | { status: "loading" } | { status: "error"; error: string } | { status: "loaded"; dump: Dump }; export function DumpEdit() { const { selectedDump } = useParams(); const navigate = useNavigate(); const { authFetch } = useRequiredAuth(); const [state, setState] = useState({ status: "loading" }); const [url, setUrl] = useState(""); const [comment, setComment] = useState(""); const [newFile, setNewFile] = useState(null); const [confirmDelete, setConfirmDelete] = useState(false); useEffect(() => { if (!selectedDump) return; setState({ status: "loading" }); (async () => { try { const res = await fetch(`${API_URL}/api/dumps/${selectedDump}`, { cache: "no-store", }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const apiResponse = await res.json(); if (apiResponse.success) { const dump: Dump = deserializeDump(apiResponse.data); setUrl(dump.url ?? ""); setComment(dump.comment ?? ""); setState({ status: "loaded", dump }); } else { setState({ status: "error", error: apiResponse.error.message }); } } catch (err) { setState({ status: "error", error: err instanceof Error ? err.message : "Load failed", }); } })(); }, [selectedDump]); const handleSave = async () => { if (state.status !== "loaded") return; let res: Response; if (state.dump.kind === "file" && newFile) { const formData = new FormData(); formData.append("file", newFile); if (comment.trim()) formData.append("comment", comment.trim()); res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}/file`, { method: "PUT", body: formData, }); } else { const body: UpdateDumpRequest = state.dump.kind === "url" ? { url: url.trim() || undefined, comment: comment.trim() || undefined } : { comment: comment.trim() || undefined }; res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}`, { method: "PUT", body: JSON.stringify(body), }); } if (!res.ok) { setState({ status: "error", error: `Update failed (${res.status})` }); return; } const apiResponse = await res.json(); if (!apiResponse.success) { setState({ status: "error", error: apiResponse.error?.message ?? "Update failed", }); return; } const updatedDump: Dump = deserializeDump(apiResponse.data); setState({ status: "loaded", dump: updatedDump }); setNewFile(null); navigate(`/dumps/${updatedDump.id}`, { state: { dump: updatedDump } }); }; const handleDelete = async () => { if (state.status !== "loaded") return; const res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}`, { method: "DELETE", }); if (!res.ok) { setState({ status: "error", error: `Delete failed (${res.status})` }); return; } navigate("/", { state: { deletedDumpId: state.dump.id } }); }; if (state.status === "loading") { return (

Loading dump…

); } if (state.status === "error") { return ( } /> ); } const { dump } = state; return (

Editing

{dump.title}

{dump.kind === "file" ? : dump.richContent ? : dump.url && ( {dump.url} )}
{ e.preventDefault(); handleSave(); }} > {dump.kind === "url" ? (
setUrl(e.currentTarget.value)} placeholder="https://..." required />
) : (

{dump.fileName} {dump.fileSize != null && ` — ${formatBytes(dump.fileSize)}`}

setNewFile(e.target.files?.[0] ?? null)} /> {newFile && (

{newFile.name} — {formatBytes(newFile.size)}

)}
)}