import { escapeHtml, formatBytes, timeAgo } from "./format.js"; const fileList = document.getElementById("file-list"); const uploadSection = document.getElementById("upload-section"); const uploadForm = document.getElementById("upload-form"); const uploadInfinite = document.getElementById("upload-infinite"); const uploadMaxDownloads = document.getElementById("upload-max-downloads"); let currentUser = null; function getDownloadUrl(fileId) { return `${window.location.origin}/api/file-share/${fileId}/download`; } uploadInfinite?.addEventListener("change", () => { if (uploadInfinite.checked) { uploadMaxDownloads.value = ""; uploadMaxDownloads.disabled = true; } else { uploadMaxDownloads.disabled = false; uploadMaxDownloads.focus(); } }); if (uploadMaxDownloads) uploadMaxDownloads.disabled = true; async function loadCurrentUser() { try { const res = await fetch("/api/auth/me"); if (!res.ok) { window.location.href = "/"; return; } currentUser = await res.json(); if (currentUser.role === "viewer") { window.location.href = "/"; return; } } catch { window.location.href = "/"; } } async function loadFiles() { try { const res = await fetch("/api/file-share"); if (!res.ok) { fileList.innerHTML = `Failed to load files`; return; } const data = await res.json(); if (data.canUpload && uploadSection) { uploadSection.classList.remove("hidden"); } if (!data.files || data.files.length === 0) { fileList.innerHTML = ` No files shared yet `; return; } fileList.innerHTML = data.files .map((f) => { const isOwner = currentUser && f.uploadedBy === currentUser.userId; const isAdmin = currentUser && currentUser.role === "admin"; const canManage = isOwner || isAdmin; const expired = f.expiresAt && f.expiresAt < Date.now(); const limitReached = f.maxDownloads !== null && f.downloadCount >= f.maxDownloads; let statusBadges = ""; if (f.hasPassword) { statusBadges += `Password `; } if (expired) { statusBadges += `Expired `; } else if (limitReached) { statusBadges += `Limit Reached `; } else if (f.expiresAt) { statusBadges += `Timed `; } if (!statusBadges) { statusBadges = `Active`; } const downloadStr = f.maxDownloads !== null ? `${f.downloadCount} / ${f.maxDownloads}` : `${f.downloadCount} / ∞`; return `
${escapeHtml(f.filename)} ${f.description ? `${escapeHtml(f.description)}` : ""}
${formatBytes(f.size)} ${escapeHtml(f.uploadedByUsername)} ${downloadStr} ${statusBadges} ${timeAgo(f.createdAt)}
${canManage ? ` ` : ""}
`; }) .join(""); } catch (err) { console.error("Load files error:", err); fileList.innerHTML = `Failed to load files`; } } fileList?.addEventListener("click", (e) => { const btn = e.target.closest("[data-file-action]"); if (!btn) return; if (btn.dataset.fileAction === "edit") openEditModal(btn); if (btn.dataset.fileAction === "delete") deleteFile(btn.dataset.fileId); }); async function deleteFile(fileId) { try { const res = await fetch(`/api/file-share/${fileId}`, { method: "DELETE" }); if (res.ok) { if (window.showToast) window.showToast("File deleted", "success"); loadFiles(); } else { const data = await res.json().catch(() => ({})); alert(data.error || "Failed to delete file"); } } catch (err) { console.error("Delete error:", err); alert("Network error. Please try again."); } } const editModal = document.getElementById("edit-modal"); const editFileId = document.getElementById("edit-file-id"); const editPassword = document.getElementById("edit-password"); const editMaxDownloads = document.getElementById("edit-max-downloads"); const editInfinite = document.getElementById("edit-infinite"); const editExpiry = document.getElementById("edit-expiry"); const editDescription = document.getElementById("edit-description"); function openEditModal(btn) { editFileId.value = btn.dataset.fileId; editPassword.value = ""; editDescription.value = btn.dataset.description || ""; const maxDl = btn.dataset.maxDownloads; if (maxDl === "" || maxDl === "null") { editInfinite.checked = true; editMaxDownloads.value = ""; editMaxDownloads.disabled = true; } else { editInfinite.checked = false; editMaxDownloads.value = maxDl; editMaxDownloads.disabled = false; } const expiresAt = btn.dataset.expiresAt; if (expiresAt && expiresAt !== "null" && expiresAt !== "") { const d = new Date(parseInt(expiresAt)); editExpiry.value = d.toISOString().slice(0, 16); } else { editExpiry.value = ""; } editModal.classList.remove("hidden"); } editInfinite?.addEventListener("change", () => { if (editInfinite.checked) { editMaxDownloads.value = ""; editMaxDownloads.disabled = true; } else { editMaxDownloads.disabled = false; editMaxDownloads.focus(); } }); document.getElementById("edit-cancel")?.addEventListener("click", () => { editModal.classList.add("hidden"); }); editModal?.addEventListener("click", (e) => { if (e.target === editModal) editModal.classList.add("hidden"); }); document.getElementById("edit-save")?.addEventListener("click", async () => { const fileId = editFileId.value; const body = {}; const pw = editPassword.value; if (pw !== "") { body.password = pw; } if (editInfinite.checked) { body.maxDownloads = null; } else { const val = parseInt(editMaxDownloads.value, 10); if (!isNaN(val) && val > 0) { body.maxDownloads = val; } } if (editExpiry.value) { body.expiresAt = new Date(editExpiry.value).getTime(); } else { body.expiresAt = null; } body.description = editDescription.value || null; try { const res = await fetch(`/api/file-share/${fileId}`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); if (res.ok) { editModal.classList.add("hidden"); if (window.showToast) window.showToast("Settings updated", "success"); loadFiles(); } else { const data = await res.json().catch(() => ({})); alert(data.error || "Failed to update"); } } catch (err) { console.error("Edit error:", err); alert("Network error. Please try again."); } }); uploadForm?.addEventListener("submit", async (e) => { e.preventDefault(); const fileInput = document.getElementById("upload-file"); const file = fileInput.files[0]; if (!file) return; const btn = document.getElementById("upload-btn"); btn.disabled = true; btn.innerHTML = ' Uploading...'; const formData = new FormData(); formData.append("file", file); const password = document.getElementById("upload-password").value; if (password) formData.append("password", password); if (!uploadInfinite.checked) { const maxDl = uploadMaxDownloads.value; if (maxDl) formData.append("maxDownloads", maxDl); } const expiry = document.getElementById("upload-expiry").value; if (expiry) { formData.append("expiresAt", String(new Date(expiry).getTime())); } const description = document.getElementById("upload-description").value; if (description) formData.append("description", description); try { const res = await fetch("/api/file-share/upload", { method: "POST", body: formData, }); const data = await res.json(); if (res.ok) { if (window.showToast) window.showToast(`"${data.filename}" uploaded successfully!`, "success"); uploadForm.reset(); uploadInfinite.checked = true; uploadMaxDownloads.disabled = true; loadFiles(); } else { alert(data.error || "Upload failed"); } } catch (err) { console.error("Upload error:", err); alert("Network error. Please try again."); } finally { btn.disabled = false; btn.innerHTML = ' Upload'; } }); (async () => { await loadCurrentUser(); await loadFiles(); })();