"use client";
import { useState } from "react";
import { AttachmentLightbox } from "./AttachmentLightbox";
import { categoryFromMime, resolveMime } from "@/lib/mime.mjs";
/**
* Render an attachment row in the staff report with the right affordance
* for its type:
*
* - image / pdf -> button opens the inline lightbox
* - office -> download link + "View in Google Docs" secondary link
* - other -> plain download link
*
* The proxy URL is `/api/staff/file?id=&org=&key=` (re-streams with
* Content-Disposition: inline for previews, or `&dl=1` for downloads). The
* Civi-signed URL (carrying its short-lived fcs JWT) is passed straight to
* Google's Docs Viewer for office files; we deliberately don't proxy that
* one because Google's servers must fetch it without our staff key.
*/
export function FileLink({
fileId,
fileName,
civiSignedUrl,
mime: explicitMime,
org,
authKey,
civiBaseUrl,
}: {
fileId: number | string;
fileName: string;
/** From Attachment.get (includes fcs). Used for office Google Viewer + download fallback. */
civiSignedUrl?: string;
mime?: string;
org: number;
authKey: string;
civiBaseUrl: string;
}) {
const [open, setOpen] = useState(false);
const mime = resolveMime(explicitMime, fileName);
const category = categoryFromMime(mime);
const proxyBase =
`/api/staff/file?id=${encodeURIComponent(String(fileId))}` +
`&org=${encodeURIComponent(String(org))}` +
`&key=${encodeURIComponent(authKey)}`;
const previewSrc = proxyBase;
// Prefer Civi's signed URL for downloads when present (one fewer hop
// through our Lambda); the proxy is the fallback.
const downloadHref = civiSignedUrl
? absUrl(civiSignedUrl, civiBaseUrl)
: `${proxyBase}&dl=1`;
const linkClass =
"text-ink underline decoration-rule underline-offset-4 hover:decoration-ink";
if (category === "image" || category === "pdf") {
return (
<>
setOpen(false)}
previewSrc={previewSrc}
downloadHref={downloadHref}
filename={fileName}
mime={mime}
/>
>
);
}
if (category === "office") {
// Google Docs Viewer renders DOC/DOCX/XLS/XLSX in a new tab. It fetches
// the source URL server-side, so the URL must be reachable without our
// staff key — that's why we pass the Civi-signed URL straight through.
const gview = civiSignedUrl
? `https://docs.google.com/viewer?url=${encodeURIComponent(absUrl(civiSignedUrl, civiBaseUrl))}`
: null;
return (
{fileName}
{gview && (
View in Google Docs
)}
);
}
// "other" — unknown types: just a download link.
return (
{fileName}
);
}
function absUrl(u: string, base: string): string {
if (u.startsWith("http")) return u;
if (!base) return u;
return `${base.replace(/\/+$/, "")}${u.startsWith("/") ? "" : "/"}${u}`;
}