// /var/www/makearmy.io/app/app/files/page.tsx "use client"; import Link from "next/link"; import { useEffect, useMemo, useState } from "react"; import { useSearchParams, useRouter } from "next/navigation"; type FileItem = { name: string; isDir: boolean; size: number; mtime: number; }; export default function FilesPage() { const search = useSearchParams(); const router = useRouter(); const path = useMemo(() => search.get("path") || "/", [search]); const [items, setItems] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { let cancelled = false; async function load() { setLoading(true); setError(null); try { const res = await fetch( `/api/files/list?path=${encodeURIComponent(path)}` ); if (!res.ok) { if (!cancelled) setError(`HTTP ${res.status}`); return; } const json = await res.json(); if (!cancelled) setItems(json.items || []); } catch (e: any) { if (!cancelled) setError(e?.message || String(e)); } finally { if (!cancelled) setLoading(false); } } load(); return () => { cancelled = true; }; }, [path]); const upPath = useMemo(() => { if (path === "/") return null; const parts = path.replace(/\/+$/, "").split("/").filter(Boolean); parts.pop(); return "/" + parts.join("/"); }, [path]); return (
Path: {path} {upPath && ( <> • Up one level )}
{loading &&
Loading…
} {error && (
Error loading files: {error}
)} {!loading && !error && items && ( {items.map((it) => { const href = it.isDir ? `/files?path=${encodeURIComponent( (path.endsWith("/") ? path : path + "/") + it.name )}` : `/api/files/raw?path=${encodeURIComponent( (path.endsWith("/") ? path : path + "/") + it.name )}`; const dl = it.isDir ? null : `/api/files/download?path=${encodeURIComponent( (path.endsWith("/") ? path : path + "/") + it.name )}`; return ( ); })}
Name Type Size Modified
{it.name} {it.isDir ? "Dir" : "File"} {it.isDir ? "-" : `${it.size.toLocaleString()} B`} {new Date(it.mtime).toLocaleString()} {!it.isDir && dl && ( Download )}
)}
); }