Lightbox: fix proxy 404, cap modal size, allow multi-Civi embed

Three quick fixes off first-deploy testing:

1. /api/staff/file 404'd for valid files. Refactor fileBelongsToOrg
   to SELECT the org's and activities' file columns and JS-compare
   instead of WHERE ... OR with custom field refs (APIv4 fragility
   around nested OR + dotted custom fields). Same ownership probe,
   same shape /api/staff/report itself uses to read file values.

2. Lightbox ballooned to full report height because the staff iframe
   auto-grows to fit content (often 3000+ px). Cap to a fixed
   640px x min(92vw, 900px) box so it stays a reasonable preview
   regardless of iframe document size.

3. Production frame-ancestors blocked crm.fci.coop from iframing
   survey.fci.coop -- the CSP only included the dev Civi origin
   derived from CIVI_BASE_URL. Add CIVI_FRAME_ALLOWED_ORIGINS
   (comma-separated) so one app deploy can be embedded by both
   dev and prod Civi. Falls back to CIVI_BASE_URL for single-Civi
   compatibility.

PRODUCTION_CUTOVER.md updated inline and in the change log.
This commit is contained in:
Joel Brock
2026-06-16 16:15:28 -07:00
parent 0019996b15
commit 5124010b8a
4 changed files with 124 additions and 64 deletions
+13 -8
View File
@@ -65,21 +65,26 @@ export function AttachmentLightbox({
const isPdf = mime === "application/pdf";
return (
// Sizing note: this dialog opens inside the staff-report iframe, which
// auto-grows to fit content (often 20004000 px tall). "h-full"/"vh"
// values inside that iframe resolve to the full iframe document, so the
// dialog would balloon. Cap to a fixed pixel box that fits comfortably
// on a typical laptop and still gives PDFs/images enough room.
<dialog
ref={ref}
onClick={onDialogClick}
aria-label={`Preview: ${filename}`}
className="m-0 h-full max-h-screen w-full max-w-screen-2xl rounded-none bg-transparent p-0 backdrop:bg-ink/70"
className="m-auto w-[min(92vw,900px)] rounded-md bg-transparent p-0 shadow-2xl backdrop:bg-ink/70"
>
<div className="flex h-full flex-col">
<header className="flex items-center justify-between gap-4 bg-paper px-4 py-3 shadow-sm sm:px-6">
<p className="min-w-0 truncate font-display text-base text-ink">
<div className="flex h-[640px] max-h-[85vh] flex-col overflow-hidden rounded-md">
<header className="flex items-center justify-between gap-4 bg-paper px-4 py-2.5 sm:px-5">
<p className="min-w-0 truncate font-display text-sm text-ink">
{filename}
</p>
<div className="flex flex-shrink-0 items-center gap-3">
<a
href={downloadHref}
className="text-sm font-medium text-leaf-700 underline decoration-rule underline-offset-4 hover:decoration-ink hover:text-leaf-800"
className="text-xs font-medium text-leaf-700 underline decoration-rule underline-offset-4 hover:decoration-ink hover:text-leaf-800"
target="_blank"
rel="noopener noreferrer"
>
@@ -88,14 +93,14 @@ export function AttachmentLightbox({
<button
type="button"
onClick={onClose}
className="rounded px-2 py-1 text-sm font-medium text-ink-soft hover:bg-rule-soft/40 focus:outline-none focus-visible:ring-2 focus-visible:ring-leaf-700"
className="rounded px-2 py-1 text-xs font-medium text-ink-soft hover:bg-rule-soft/40 focus:outline-none focus-visible:ring-2 focus-visible:ring-leaf-700"
aria-label="Close preview"
>
Close
</button>
</div>
</header>
<div className="flex flex-1 items-center justify-center overflow-hidden bg-ink/90 p-4">
<div className="flex flex-1 items-center justify-center overflow-hidden bg-ink/90 p-3">
{isImage ? (
// eslint-disable-next-line @next/next/no-img-element
<img
@@ -107,7 +112,7 @@ export function AttachmentLightbox({
<iframe
src={previewSrc}
title={filename}
className="h-full w-full max-w-screen-lg border-0 bg-paper"
className="h-full w-full border-0 bg-paper"
/>
) : (
// Defensive: FileLink shouldn't open the lightbox for non-previewable