import { useMemo, useState } from "react"; import Button from "../../components/Button"; import Card from "../../components/Card"; import PageTitle from "../../components/PageTitle"; import StatusBadge from "../../components/StatusBadge"; import ModuleSubnav, { type ModuleSubnavGroup } from "../../layout/ModuleSubnav"; type StorageRecord = { id: string; name: string; description: string; type: string; scope: string; status: string; files: number; used: string; retention: string; updatedAt: string; }; type StorageSection = "browse" | "upload" | "settings" | "retention" | "bulk" | "activity"; const storages: StorageRecord[] = [ { id: "campaign-files", name: "Campaign files", description: "Files uploaded or referenced for campaign attachments.", type: "Local path / planned object storage", scope: "Campaigns", status: "available", files: 124, used: "2.4 GB", retention: "Keep sent evidence", updatedAt: "2026-06-08 15:36" }, { id: "template-assets", name: "Template assets", description: "Images and reusable assets for message templates.", type: "Planned object storage", scope: "Templates", status: "planned", files: 8, used: "34 MB", retention: "Manual cleanup", updatedAt: "2026-06-06 10:12" }, { id: "shared-library", name: "Shared library", description: "Tenant or group-wide files available to multiple campaigns.", type: "Planned object storage", scope: "Tenant / groups", status: "planned", files: 0, used: "0 MB", retention: "Policy pending", updatedAt: "Not connected" } ]; const storageSubnav = (onBack: () => void): ModuleSubnavGroup[] => [ { items: [{ actionId: "file-storages", label: "← File storages", primary: true, onClick: onBack }] }, { title: "STORAGE", items: [ { id: "browse", label: "Browse" }, { id: "upload", label: "Upload" }, { id: "settings", label: "Settings" }, { id: "retention", label: "Retention" }, { id: "bulk", label: "Bulk actions" }, { id: "activity", label: "Activity" } ] } ]; const demoFiles = [ { name: "statement_1001.pdf", path: "/2026/05/statement_1001.pdf", size: "142 KB", updatedAt: "2026-06-08 15:36", status: "ready" }, { name: "statement_1002.pdf", path: "/2026/05/statement_1002.pdf", size: "148 KB", updatedAt: "2026-06-08 15:36", status: "ready" }, { name: "global_notice.pdf", path: "/shared/global_notice.pdf", size: "81 KB", updatedAt: "2026-06-06 09:44", status: "ready" } ]; export default function FilesPage() { const [selectedStorageId, setSelectedStorageId] = useState(null); const [active, setActive] = useState("browse"); const selectedStorage = useMemo( () => storages.find((storage) => storage.id === selectedStorageId) ?? null, [selectedStorageId] ); function openStorage(storageId: string) { setSelectedStorageId(storageId); setActive("browse"); } if (selectedStorage) { return (
setSelectedStorageId(null))} onSelect={setActive} />
{selectedStorage.name}

{selectedStorage.description}

{active === "browse" && } {active === "upload" && } {active === "settings" && } {active === "retention" && } {active === "bulk" && } {active === "activity" && }
); } return (
Files

Manage file storages first. Open a storage to browse content, upload files and configure retention.

File storages

Storage endpoints are placeholders until the backend model is added
} >
{storages.map((storage) => ( ))}
Storage Type Scope Files Used Retention Updated
{storage.name} {storage.description}
{storage.type} {storage.scope} {storage.files} {storage.used} {storage.retention} {storage.updatedAt}
); } function StorageBrowse({ storage }: { storage: StorageRecord }) { return ( } >
{(storage.id === "campaign-files" ? demoFiles : []).map((file) => ( ))} {storage.id !== "campaign-files" && }
NamePathSizeUpdatedStatus
{file.name} {file.path} {file.size} {file.updatedAt}
Files will appear here when this storage is connected.
); } function StorageUpload({ storage }: { storage: StorageRecord }) { return ( Select files…}>

Upload will target {storage.name}. The backend will later provide chunked upload, duplicate handling and progress state.

Drag and drop upload area Duplicate handling: ask, replace, keep both Optional file tagging after upload
); } function StorageSettings({ storage }: { storage: StorageRecord }) { return (
Type
{storage.type}
Scope
{storage.scope}
Status

This view is prepared for local path, Garage/S3 and tenant/group/user storage settings.

Storage backendAccess policyQuotaEncryption / lifecycle
); } function StorageRetention({ storage }: { storage: StorageRecord }) { return ( Save policy}>

Current policy: {storage.retention}. Retention must respect audit-safe campaigns and sent attachments.

Keep files for sent campaigns Prune unused draft uploads after a configurable period Export manifest before destructive cleanup
); } function StorageBulkActions() { return (

Bulk download and delete should be available from the Browse view as well as from a dedicated filtered action view.

); } function StorageActivity() { return (

Storage activity will show uploads, downloads, deletions and retention cleanup runs once backend audit events are available.

Last uploadLast bulk deleteRetention cleanup result
); }