From f928ac1c7839286114e8cce75b0dd120d011bd62 Mon Sep 17 00:00:00 2001 From: sax3l Date: Mon, 2 Nov 2026 15:16:10 +0100 Subject: [PATCH] chore(portal): retire the dead metadata-only upload page /portal/files only sent name/mime/size and always hit the 501 storage stub. Redirect it to /portal/dokument (real bytes) and remove it from both navs. --- app/portal/files/page.tsx | 180 +----------------------------------- app/portal/page.tsx | 1 - components/portal-shell.tsx | 1 - 3 files changed, 5 insertions(+), 177 deletions(-) diff --git a/app/portal/files/page.tsx b/app/portal/files/page.tsx index c00f00f..06f08cb 100644 --- a/app/portal/files/page.tsx +++ b/app/portal/files/page.tsx @@ -1,180 +1,10 @@ -"use client"; - -import { useCallback, useEffect, useRef, useState } from "react"; -import { useT } from "@/components/locale-provider"; -import { PortalShell } from "@/components/portal-shell"; -import { LoadingSkeleton, EmptyState, ErrorState } from "@/components/states"; -import { formatSEK } from "@/lib/data"; +import { redirect } from 'next/navigation'; /** - * /portal/files — kundens filer. En kvadratisk mono drag-drop-zon + fillista. - * Vid släpp: POST /api/uploads { name, mime, bytes }. Om lagring inte är kopplad - * svarar endpointen 501 → lugn not "aktiveras vid lagring", aldrig en feltoast. - * Uppladdade filer matar matchning & berikning. + * The old `/portal/files` page only sent metadata and always hit the 501 + * storage stub. Real uploads now live at `/portal/dokument`; keep the old URL + * working instead of leaving a second, non-functional upload surface. */ - -interface FileRow { - file_id: string; - name: string; - mime: string; - bytes: number; - status: string; // received · matching · enriched - uploaded_at: string; -} - -const PROV_BY_STATUS: Record = { - enriched: "var(--prov-3)", - matching: "var(--prov-2)", - received: "var(--prov-1)", -}; - -function fmtBytes(b: number): string { - if (b < 1024) return `${b} B`; - if (b < 1024 * 1024) return `${(b / 1024).toFixed(0)} kB`; - return `${(b / (1024 * 1024)).toFixed(1)} MB`; -} - export default function FilesPage() { - const t = useT(); - const [files, setFiles] = useState(null); - const [error, setError] = useState(false); - const [dragging, setDragging] = useState(false); - const [busy, setBusy] = useState(false); - const [storageOff, setStorageOff] = useState(false); - const inputRef = useRef(null); - - const load = useCallback(async () => { - setError(false); - try { - const r = await fetch("/api/uploads", { cache: "no-store" }); - if (r.status === 501) { setStorageOff(true); setFiles([]); return; } - setFiles(await r.json()); - } catch { - setError(true); - } - }, []); - useEffect(() => { void load(); }, [load]); - - const upload = useCallback(async (list: FileList | File[]) => { - const arr = Array.from(list); - if (arr.length === 0 || busy) return; - setBusy(true); - try { - for (const f of arr) { - const r = await fetch("/api/uploads", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ name: f.name, mime: f.type || "application/octet-stream", bytes: f.size }), - }); - // Env-guarded: storage not wired yet → calm note, no error. - if (r.status === 501) { setStorageOff(true); break; } - } - } catch { - // Network hiccup degrades to the storage note, never a hard error toast. - setStorageOff(true); - } - setBusy(false); - void load(); - }, [busy, load]); - - function onDrop(e: React.DragEvent) { - e.preventDefault(); - setDragging(false); - if (e.dataTransfer?.files?.length) void upload(e.dataTransfer.files); - } - - function openPicker() { inputRef.current?.click(); } - - return ( - - {/* dropzone */} -
{ if (e.key === "Enter" || e.key === " ") { e.preventDefault(); openPicker(); } }} - onDragOver={(e) => { e.preventDefault(); setDragging(true); }} - onDragLeave={() => setDragging(false)} - onDrop={onDrop} - className="relative flex aspect-[3/1] w-full cursor-pointer flex-col items-center justify-center border border-dashed bg-background text-center transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background" - style={{ - borderColor: dragging ? "var(--accent-red)" : "var(--border)", - backgroundColor: dragging ? "color-mix(in srgb, var(--accent-red) 4%, var(--background))" : undefined, - }} - > - -

- {busy - ? t({ en: "uploading…", sv: "laddar upp…" }) - : dragging - ? t({ en: "drop here", sv: "släpp här" }) - : t({ en: "drag here · or click", sv: "dra hit · eller klicka" })} -

-

- {t({ en: "CSV, Excel, lists.", sv: "CSV, Excel, listor." })} -
{t({ en: "Fed straight into matching & enrichment.", sv: "Matas in i matchning & berikning." })} -

- { if (e.target.files) void upload(e.target.files); e.target.value = ""; }} - /> -
- - {storageOff ? ( -
- -

- {t({ en: "File upload activates once storage is connected.", sv: "Filuppladdning aktiveras när lagring kopplas." })} -

-
- ) : null} - - {/* file list */} -
- {error ? ( - - ) : !files ? ( - - ) : files.length === 0 ? ( - - ) : ( -
-
- {t({ en: "File", sv: "Fil" })}{t({ en: "Type", sv: "Typ" })}{t({ en: "Size", sv: "Storlek" })}{t({ en: "Status", sv: "Status" })} -
- {files.map((f) => ( -
- {f.name} - {f.mime.split("/").pop()} - {fmtBytes(f.bytes)} - - - {f.status} - -
- ))} -
- )} -
- -

- {t({ en: "Uploads are deduplicated against your file · no cost until you order", sv: "Uppladdat dedupliceras mot din fil · ingen kostnad förrän du beställer" })}{files && files.length ? ` · ${formatSEK(0)} ${t({ en: "so far", sv: "hittills" })}` : ""} -

-
- ); + redirect('/portal/dokument'); } diff --git a/app/portal/page.tsx b/app/portal/page.tsx index 6715b90..99e63c0 100644 --- a/app/portal/page.tsx +++ b/app/portal/page.tsx @@ -38,7 +38,6 @@ const NAV: { label: { en: string; sv: string }; href: string }[] = [ { label: { en: "Subscriptions", sv: "Prenumerationer" }, href: "/portal/subscriptions" }, { label: { en: "Documents", sv: "Dokument" }, href: "/portal/dokument" }, { label: { en: "Credits", sv: "Krediter" }, href: "/portal/krediter" }, - { label: { en: "Files", sv: "Filer" }, href: "/portal/files" }, { label: { en: "Integrations", sv: "Integrationer" }, href: "/portal/integrationer" }, { label: { en: "Settings", sv: "Inställningar" }, href: "/portal/settings" }, { label: { en: "Admin", sv: "Admin" }, href: "/admin" }, diff --git a/components/portal-shell.tsx b/components/portal-shell.tsx index 1d952ef..4f0de4a 100644 --- a/components/portal-shell.tsx +++ b/components/portal-shell.tsx @@ -12,7 +12,6 @@ const CUSTOMER_NAV: NavItem[] = [ { label: { en: "Subscriptions", sv: "Prenumerationer" }, href: "/portal/subscriptions" }, { label: { en: "Documents", sv: "Dokument" }, href: "/portal/dokument" }, { label: { en: "Credits", sv: "Krediter" }, href: "/portal/krediter" }, - { label: { en: "Files", sv: "Filer" }, href: "/portal/files" }, { label: { en: "Integrations", sv: "Integrationer" }, href: "/portal/integrationer" }, { label: { en: "Settings", sv: "Inställningar" }, href: "/portal/settings" }, ]; -- 2.54.0