diff --git a/README.md b/README.md index d18cb4f..91e80d3 100644 --- a/README.md +++ b/README.md @@ -408,9 +408,12 @@ updating as the admin edits `sellerName`/address/`taxRatePercent`/ - **`app/company-settings-preview/page.tsx`** + **`components/LiveCompanySettingsPreviewClient.tsx`** — same entrypoint pattern as `/email-preview/[type]` (Draft Mode via - `app/api/preview/route.ts`, never a real visitor destination), but no - `[type]` segment — there's only one kind of document here, unlike the 6 - email types. + `app/api/preview/route.ts`), but no `[type]` segment — there's only one + kind of document here, unlike the 6 email types. **Actually gated on + `draftMode().isEnabled`** (calls `notFound()` otherwise), unlike + `/email-preview` — this data includes a real bank IBAN/address once + filled in, not just marketing email copy, so it must not render for an + unauthenticated visitor who happens to find the URL. - **`@react-pdf/renderer`'s ``** (not `renderToBuffer()`) is what makes this a *live* preview rather than a static download — it's a browser-only component that renders a `Document` straight into an diff --git a/app/company-settings-preview/page.tsx b/app/company-settings-preview/page.tsx index a37f8ba..574df16 100644 --- a/app/company-settings-preview/page.tsx +++ b/app/company-settings-preview/page.tsx @@ -1,5 +1,6 @@ import type { Metadata } from "next"; import { draftMode } from "next/headers"; +import { notFound } from "next/navigation"; import { getCompanySettings, type CompanySettings } from "../lib/payload"; import { LiveCompanySettingsPreviewClient } from "./components/LiveCompanySettingsPreviewClient"; @@ -22,13 +23,18 @@ const FALLBACK: CompanySettings = { // Entered exclusively via CompanySettings.ts's admin.livePreview.url (a // Payload-admin-only iframe target, see buildPreviewUrl()/api/preview) — -// not a page a real visitor would ever land on. Unlike email-templates -// there's no draft/published distinction here (company-settings has no -// content-versioning concept, it's just the current row) — the initial -// fetch is the same live data getCompanySettings() always returns, -// useLivePreview() takes over from there as the admin edits fields. +// gated on Draft Mode actually being enabled, unlike email-templates' +// preview: this data includes a real bank IBAN/address once filled in, +// not just marketing email copy, so this page must not render for an +// unauthenticated visitor who happens to find the URL. Unlike +// email-templates there's no draft/published distinction in the data +// itself (company-settings has no content-versioning concept, it's just +// the current row) — the initial fetch is the same live data +// getCompanySettings() always returns, useLivePreview() takes over from +// there as the admin edits fields. export default async function CompanySettingsPreviewPage() { - await draftMode(); + const draft = await draftMode(); + if (!draft.isEnabled) notFound(); const initialSettings = (await getCompanySettings()) ?? FALLBACK; return ; }