mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
146 lines
7.4 KiB
React
146 lines
7.4 KiB
React
// modules/admin/pages/assets/ViewDocumentAsset.jsx
|
|
|
|
import { useParams, useNavigate } from "react-router-dom";
|
|
import { ArrowLeft, Lock, Globe, FileText, Pencil } from "lucide-react";
|
|
import { useDateFormat } from "@/hooks/useDateFormat";
|
|
|
|
import { useAssetFetchState } from "@/hooks/useAssetFetchState";
|
|
import { useAssetPreviewSrc } from "@/hooks/useAssetPreviewSrc";
|
|
import { formatFileSize } from "@/utils/format.util";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Separator } from "@/components/ui/separator";
|
|
import FileZoomViewer from "@/components/generic/FileZoomViewer";
|
|
import AssetPageLoader from "@/components/generic/AssetLoader";
|
|
|
|
function MetaRow({ label, value }) {
|
|
if (!value && value !== 0) return null;
|
|
return (
|
|
<div className="flex items-start gap-3 py-2">
|
|
<span className="text-muted-foreground text-sm w-36 shrink-0">{label}</span>
|
|
<span className="text-sm font-medium break-all">{String(value)}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const PREVIEWABLE = ["pdf", "txt", "html", "htm", "csv", "md"];
|
|
|
|
export default function ViewDocumentAsset() {
|
|
const { assetId } = useParams();
|
|
const navigate = useNavigate();
|
|
const { fmtDateTime } = useDateFormat();
|
|
|
|
const { asset: selectedAsset, loading, notFound } = useAssetFetchState(assetId);
|
|
const { src: streamUrl, loading: previewLoading } = useAssetPreviewSrc(selectedAsset, { scope: "admin" });
|
|
|
|
if (loading) {
|
|
return <AssetPageLoader />;
|
|
}
|
|
|
|
if (notFound) {
|
|
return (
|
|
<div className="flex flex-col items-center justify-center h-96 gap-3 text-muted-foreground">
|
|
<p>File not found.</p>
|
|
<Button variant="outline" onClick={() => navigate("/admin/assets")}>Go Back</Button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const a = selectedAsset;
|
|
const ext = (a.extension ?? "").toLowerCase();
|
|
const canPreview = PREVIEWABLE.includes(ext);
|
|
const isPdf = ext === "pdf";
|
|
|
|
return (
|
|
<div className="max-w-7xl mx-auto px-4 py-6 space-y-6">
|
|
|
|
{/* ── Header ── */}
|
|
<div className="flex items-center gap-3">
|
|
<Button variant="ghost" size="icon" onClick={() => navigate("/admin/assets")}>
|
|
<ArrowLeft className="h-4 w-4" />
|
|
</Button>
|
|
<div className="flex-1 min-w-0">
|
|
<h1 className="text-xl font-semibold truncate">{a.display_name ?? a.original_name}</h1>
|
|
<p className="text-sm text-muted-foreground">{a.mime_type}</p>
|
|
</div>
|
|
<Button variant="outline" onClick={() => navigate(`/admin/assets/edit/${a.asset_id}`)}>
|
|
<Pencil className="h-3.5 w-3.5" />
|
|
Edit Info
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-5 gap-6">
|
|
|
|
{/* ── Document preview ── */}
|
|
<div className="lg:col-span-3">
|
|
{isPdf ? (
|
|
<div className="rounded-lg border overflow-hidden">
|
|
<FileZoomViewer
|
|
src={streamUrl}
|
|
mimeType={a.mime_type}
|
|
fileName={a.display_name ?? a.original_name}
|
|
loading={previewLoading}
|
|
/>
|
|
</div>
|
|
) : canPreview && streamUrl ? (
|
|
<div className="rounded-lg border overflow-hidden bg-white" style={{ height: 600 }}>
|
|
<iframe
|
|
src={streamUrl}
|
|
title={a.display_name ?? a.original_name}
|
|
className="w-full h-full"
|
|
// sandbox="allow-scripts allow-same-origin"
|
|
/>
|
|
</div>
|
|
) : (
|
|
<div className="rounded-lg border bg-muted/30 flex flex-col items-center justify-center gap-4 py-20">
|
|
<FileText className="h-16 w-16 text-muted-foreground/40" />
|
|
<p className="text-muted-foreground text-sm">
|
|
Preview not available for this file type.
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* ── Metadata panel ── */}
|
|
<div className="lg:col-span-2 space-y-4">
|
|
<div className="rounded-lg border bg-card p-4 space-y-1">
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">File Info</p>
|
|
<MetaRow label="Original Name" value={a.original_name} />
|
|
<MetaRow label="Extension" value={a.extension} />
|
|
<MetaRow label="File Size" value={formatFileSize(a.file_size)} />
|
|
<MetaRow label="MIME Type" value={a.mime_type} />
|
|
<Separator className="my-2" />
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">Storage</p>
|
|
<MetaRow label="Provider" value={a.storage_provider} />
|
|
<MetaRow label="Bucket" value={a.storage_bucket} />
|
|
<MetaRow label="Key" value={a.storage_key} />
|
|
<Separator className="my-2" />
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">Access</p>
|
|
<div className="flex items-center gap-2 py-1">
|
|
{a.is_public
|
|
? <><Globe className="h-3.5 w-3.5 text-green-500" /><Badge variant="outline" className="text-green-600 border-green-400">Public</Badge></>
|
|
: <><Lock className="h-3.5 w-3.5 text-yellow-500" /><Badge variant="outline" className="text-yellow-600 border-yellow-400">Private</Badge></>
|
|
}
|
|
</div>
|
|
<MetaRow label="Access Level" value={a.access_level} />
|
|
<MetaRow label="Owner Type" value={a.owner_type} />
|
|
<MetaRow label="Owner ID" value={a.owner_id} />
|
|
<Separator className="my-2" />
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">Timestamps</p>
|
|
<MetaRow label="Created By" value={a.creator?.full_name ?? a.createdBy} />
|
|
<MetaRow label="Created" value={a.createdAt ? fmtDateTime(a.createdAt) : null} />
|
|
<MetaRow label="Modified By" value={a.updater?.full_name ?? a.updatedBy} />
|
|
<MetaRow label="Modified" value={a.updatedAt ? fmtDateTime(a.updatedAt) : null} />
|
|
</div>
|
|
|
|
{a.description && (
|
|
<div className="rounded-lg border bg-card p-4">
|
|
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-2">Description</p>
|
|
<p className="text-sm text-foreground">{a.description}</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |