"use client"; import { useState, useMemo } from "react"; import Link from "next/link"; import type { FileRecord } from "@/lib/store"; type SortOrder = "newest" | "oldest" | "name" | "size-desc" | "size-asc"; type TypeFilter = "all" | "backerup" | "config"; function formatBytes(n: number) { if (n < 1024) return `${n} B`; if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`; return `${(n / 1024 / 1024).toFixed(2)} MB`; } function formatDate(s: string) { return new Date(s).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric", }); } function SearchIcon() { return ( ); } function ArrowIcon() { return ( ); } function XIcon() { return ( ); } function SortIcon() { return ( ); } export default function BrowseClient({ records: allRecords, groups, }: { records: FileRecord[]; groups: string[]; }) { const [search, setSearch] = useState(""); const [selectedGroup, setSelectedGroup] = useState(null); const [typeFilter, setTypeFilter] = useState("all"); const [sort, setSort] = useState("newest"); const filtered = useMemo(() => { let r = allRecords; if (search.trim()) { const q = search.toLowerCase(); r = r.filter( (rec) => rec.displayName?.toLowerCase().includes(q) || rec.originalName.toLowerCase().includes(q) || rec.description?.toLowerCase().includes(q) || rec.containerName?.toLowerCase().includes(q) || rec.image?.toLowerCase().includes(q) || rec.group?.toLowerCase().includes(q) ); } if (selectedGroup) r = r.filter((rec) => rec.group === selectedGroup); if (typeFilter !== "all") r = r.filter((rec) => rec.type === typeFilter); const sorted = [...r]; switch (sort) { case "newest": sorted.sort((a, b) => new Date(b.uploadedAt).getTime() - new Date(a.uploadedAt).getTime()); break; case "oldest": sorted.sort((a, b) => new Date(a.uploadedAt).getTime() - new Date(b.uploadedAt).getTime()); break; case "name": sorted.sort((a, b) => (a.displayName ?? a.originalName).localeCompare(b.displayName ?? b.originalName) ); break; case "size-desc": sorted.sort((a, b) => b.size - a.size); break; case "size-asc": sorted.sort((a, b) => a.size - b.size); break; } return sorted; }, [allRecords, search, selectedGroup, typeFilter, sort]); const activeFilters = (search.trim() ? 1 : 0) + (selectedGroup ? 1 : 0) + (typeFilter !== "all" ? 1 : 0); function clearAll() { setSearch(""); setSelectedGroup(null); setTypeFilter("all"); setSort("newest"); } return (
{/* ── Search + Sort row ── */}
setSearch(e.target.value)} className="w-full rounded-xl border border-white/8 bg-white/4 pl-10 pr-4 py-2.5 text-sm text-slate-200 placeholder-slate-600 outline-none focus:border-cyan-500/40 focus:bg-white/6 transition-all" /> {search && ( )}
{/* ── Filter pills ── */}
{/* Type pills */} {(["all", "backerup", "config"] as TypeFilter[]).map((t) => ( ))} {groups.length > 0 && ( <>
{groups.map((g) => ( ))} )} {activeFilters > 0 && ( )}
{/* ── Results count ── */}

{filtered.length === allRecords.length ? `${allRecords.length} file${allRecords.length !== 1 ? "s" : ""} shared by the community` : `${filtered.length} of ${allRecords.length} files`}

{/* ── Cards ── */} {filtered.length === 0 ? (
🔍

No results found

Try adjusting your search or clearing some filters.

{activeFilters > 0 && ( )}
) : (
{filtered.map((r) => (
{/* Badges */}
{r.type === "backerup" ? ( .backerup ) : ( .json config )} {r.group && ( {r.group} )}
{/* Title */} {(r.displayName ?? r.containerName) ? (

{r.displayName ?? r.containerName}

) : (

{r.originalName}

)} {/* Image */} {r.image && (

{r.image}

)} {/* Description */} {r.description && (

{r.description}

)}
{/* Arrow */}
{/* Meta row */}
{formatBytes(r.size)} · {formatDate(r.uploadedAt)} {r.containerName && r.displayName && ( <> · {r.containerName} )}
))}
)}
); }