"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}`; }