payload-plugin-marketing 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -19
- package/dist/admin/client.cjs +3 -0
- package/dist/admin/client.cjs.map +1 -0
- package/dist/admin/client.d.ts +7 -0
- package/dist/admin/client.d.ts.map +1 -0
- package/dist/admin/client.js +3 -0
- package/dist/admin/client.js.map +1 -0
- package/dist/admin/components/audience-buttons.d.ts.map +1 -1
- package/dist/admin/components/broadcast-list.d.ts.map +1 -1
- package/dist/admin/components/broadcasts-table.d.ts.map +1 -1
- package/dist/admin/components/contacts-table.d.ts.map +1 -1
- package/dist/admin/components/create-broadcast-button.d.ts +9 -1
- package/dist/admin/components/create-broadcast-button.d.ts.map +1 -1
- package/dist/admin/components/marketing-components.d.ts +0 -6
- package/dist/admin/components/marketing-components.d.ts.map +1 -1
- package/dist/admin/components/marketing-view-shell.d.ts.map +1 -1
- package/dist/admin/components/payload-modal.d.ts +8 -8
- package/dist/admin/components/payload-modal.d.ts.map +1 -1
- package/dist/admin/constants.cjs +2 -0
- package/dist/admin/constants.cjs.map +1 -0
- package/dist/admin/constants.d.ts +2 -0
- package/dist/admin/constants.d.ts.map +1 -0
- package/dist/admin/constants.js +2 -0
- package/dist/admin/constants.js.map +1 -0
- package/dist/admin/index.cjs +1 -1
- package/dist/admin/index.cjs.map +1 -1
- package/dist/admin/index.d.ts +3 -3
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/locale-options.d.ts +7 -0
- package/dist/admin/locale-options.d.ts.map +1 -0
- package/dist/admin/server.cjs +2 -0
- package/dist/admin/server.cjs.map +1 -0
- package/dist/admin/server.d.ts +2 -0
- package/dist/admin/server.d.ts.map +1 -0
- package/dist/admin/server.js +2 -0
- package/dist/admin/server.js.map +1 -0
- package/dist/admin/use-marketing-api.d.ts.map +1 -1
- package/dist/{chunk-S2EABBIN.js → chunk-G6DIJ7B2.js} +1 -1
- package/dist/chunk-G6DIJ7B2.js.map +1 -0
- package/dist/email-broadcast-template.d.ts +15 -0
- package/dist/email-broadcast-template.d.ts.map +1 -0
- package/dist/endpoints/marketing-endpoints.d.ts.map +1 -1
- package/dist/form-builder/index.cjs.map +1 -1
- package/dist/form-builder/index.js +1 -1
- package/dist/form-builder/normalize-placeholder-rows.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/marketing-integration.d.ts +2 -1
- package/dist/marketing-integration.d.ts.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -2
- package/dist/chunk-S2EABBIN.js.map +0 -1
- package/dist/chunk-SX3OTOU2.js +0 -2
- package/dist/chunk-SX3OTOU2.js.map +0 -1
package/dist/admin/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/index.ts","../../src/admin/components/marketing-components.tsx","../../src/admin/use-marketing-api.ts","../../src/admin/paths.ts","../../src/admin/components/audience-detail.tsx","../../src/marketing-integration.ts","../../src/admin/components/contacts-table.tsx","../../src/admin/date-format.ts","../../src/admin/components/payload-modal.tsx","../../src/admin/components/marketing-view-shell.tsx","../../src/admin/components/view-params.ts","../../src/admin/components/audience-list.tsx","../../src/admin/components/audience-buttons.tsx","../../src/admin/components/broadcast-list.tsx","../../src/admin/components/broadcasts-table.tsx","../../src/admin/components/create-broadcast-button.tsx"],"sourcesContent":["export const defaultAdminComponentPath = \"payload-plugin-marketing/admin\"\n\nexport {\n AudienceSelect,\n AudienceTable,\n BroadcastsTable,\n ContactsTable,\n MarketingMenu,\n} from \"./components/marketing-components\"\nexport { AudienceDetail, AudienceList, BroadcastList } from \"./components/views\"\n","\"use client\"\n\nimport React from \"react\"\nimport { Link, NavGroup, SelectField } from \"@payloadcms/ui\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingAudience } from \"../../types\"\nimport type { TextFieldClientComponent } from \"payload\"\nimport { marketingAdminHref } from \"../paths\"\n\nfunction parseAudiences(payload: unknown): MarketingAudience[] {\n if (!Array.isArray(payload)) return []\n const out: MarketingAudience[] = []\n for (const item of payload) {\n if (!item || typeof item !== \"object\") continue\n const rec = item as Record<string, unknown>\n const id = rec.id\n const name = rec.name\n if (typeof id === \"string\" && typeof name === \"string\") {\n out.push({ id, name })\n }\n }\n return out\n}\n\nexport const AudienceSelect: TextFieldClientComponent = ({ field, path, readOnly }) => {\n const { requestJson } = useMarketingApi()\n const [audiences, setAudiences] = React.useState<MarketingAudience[]>([])\n const [loadError, setLoadError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n let cancelled = false\n void (async () => {\n try {\n const data = await requestJson(\"/marketing/audiences\")\n if (!cancelled) {\n setAudiences(parseAudiences(data))\n setLoadError(null)\n }\n } catch (err) {\n if (!cancelled) {\n setLoadError(err instanceof Error ? err.message : \"Failed to load audiences\")\n }\n }\n })()\n return () => {\n cancelled = true\n }\n }, [requestJson])\n\n return (\n <div className=\"field-type relative\">\n {loadError ? (\n <p className=\"text-red-500\" role=\"alert\">\n {loadError}\n </p>\n ) : null}\n <SelectField\n field={{\n label: typeof field.label === \"string\" ? field.label : \"Audience\",\n name: field.name,\n options: audiences.map((a) => ({ label: a.name, value: a.id })),\n required: field.required === true,\n type: \"select\",\n }}\n path={path}\n readOnly={readOnly}\n />\n </div>\n )\n}\n\nexport function MarketingMenu({ basePath = \"\" }: { basePath?: string }) {\n return (\n <NavGroup isOpen label=\"Marketing\">\n <Link className=\"nav__link\" href={marketingAdminHref(basePath, \"audience\")}>\n Audience\n </Link>\n <Link className=\"nav__link\" href={marketingAdminHref(basePath, \"broadcast\")}>\n Broadcast\n </Link>\n </NavGroup>\n )\n}\n\nexport function AudienceTable({ audiences }: { audiences: Array<{ id: string; name: string }> }) {\n return (\n <table>\n <tbody>\n {audiences.map((audience) => (\n <tr key={audience.id}>\n <td>{audience.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function ContactsTable({ contacts }: { contacts: Array<{ email: string; id: string }> }) {\n return (\n <table>\n <tbody>\n {contacts.map((contact) => (\n <tr key={contact.id}>\n <td>{contact.email}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function BroadcastsTable({\n broadcasts,\n}: {\n broadcasts: Array<{ id: string; name: string }>\n}) {\n return (\n <table>\n <tbody>\n {broadcasts.map((broadcast) => (\n <tr key={broadcast.id}>\n <td>{broadcast.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n","\"use client\"\n\nimport { useConfig } from \"@payloadcms/ui\"\nimport { useCallback, useMemo } from \"react\"\n\nexport function useMarketingApi() {\n const context = useConfig() as unknown as {\n routes?: { api?: string }\n serverURL?: string\n }\n\n const base = useMemo(() => `${context.serverURL ?? \"\"}${context.routes?.api ?? \"/api\"}`, [\n context.routes?.api,\n context.serverURL,\n ])\n\n const requestJson = useCallback(\n async (pathSegment: string, init?: RequestInit): Promise<unknown> => {\n const { headers: _headersIgnored, ...restInit } = init ?? {}\n const headers = new Headers(init?.headers)\n if (\n restInit.body !== undefined &&\n restInit.body !== \"\" &&\n restInit.body !== null\n ) {\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\")\n }\n }\n\n const res = await fetch(`${base}${pathSegment}`, {\n ...restInit,\n credentials: \"include\",\n headers,\n })\n\n if (!res.ok) {\n let detail = `${res.status} ${res.statusText}`\n try {\n const parsed = (await res.json()) as { message?: string }\n if (typeof parsed.message === \"string\") detail = parsed.message\n } catch {\n //\n }\n throw new Error(detail)\n }\n\n if (res.status === 204) {\n return undefined\n }\n\n try {\n return await res.json()\n } catch {\n return undefined\n }\n },\n [base],\n )\n\n return { base, requestJson }\n}\n","export function joinAdminSegments(adminRoute: string, ...segments: string[]): string {\n const trimmedAdmin = adminRoute.replace(/\\/+$/, \"\") || \"\"\n const body = segments\n .flatMap((s) => String(s).split(\"/\"))\n .map((segment) => segment.replace(/^\\/+|\\/+$/g, \"\"))\n .filter(Boolean)\n .join(\"/\")\n const combined = trimmedAdmin === \"\" ? `/${body}` : `${trimmedAdmin}/${body}`\n return combined.replace(/\\/{2,}/g, \"/\")\n}\n\n/** Absolute admin hrefs for marketing custom views (`/admin`, optional plugin `basePath`, then path segments). */\nexport function marketingAdminHref(basePath: string | undefined, ...segments: string[]): string {\n const normalized = basePath?.replace(/^\\/+|\\/+$/g, \"\") ?? \"\"\n const parts = [normalized, ...segments].filter(Boolean)\n return joinAdminSegments(\"/admin\", ...parts)\n}\n","import { Suspense } from \"react\"\nimport { notFound } from \"next/navigation\"\nimport { Gutter, Link } from \"@payloadcms/ui\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { ContactsTable, EditContactButton } from \"./contacts-table\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\nimport { marketingAudienceIdFromParams } from \"./view-params\"\n\nimport type { AdminViewServerProps } from \"payload\"\n\nexport type AudienceDetailViewProps = AdminViewServerProps & {\n basePath?: string\n}\n\nexport default function AudienceDetail({\n initPageResult,\n params,\n searchParams,\n}: AudienceDetailViewProps) {\n const audienceId = marketingAudienceIdFromParams(params)\n\n if (!audienceId) {\n throw new Error(\"No audience id in route params\")\n }\n\n return (\n <MarketingViewShell initPageResult={initPageResult} params={params} searchParams={searchParams}>\n <Gutter>\n <AudienceDetailBody audienceId={audienceId} initPageResult={initPageResult} />\n </Gutter>\n </MarketingViewShell>\n )\n}\n\nasync function AudienceDetailBody({\n audienceId,\n initPageResult,\n}: {\n audienceId: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const integration = tryGetMarketingIntegration(initPageResult.req.payload)\n if (!integration) {\n return (\n <p role=\"alert\">\n Marketing plugin is not configured (missing adapter on Payload config).\n </p>\n )\n }\n\n const effective = resolveMarketingPermissions(integration.permissions)\n if (!effective.audiences.read) {\n return <p role=\"alert\">You do not have permission to view this audience.</p>\n }\n\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const audience = await adapter.audiences.get(audienceId)\n if (!audience) {\n notFound()\n }\n\n const audienceDashboardUrl = adapter.urls?.audience?.(audienceId)\n\n return (\n <>\n <header className=\"flex flex-col gap-4\">\n <h1>{audience.name}</h1>\n {audienceDashboardUrl ? (\n <Link href={audienceDashboardUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n Open this audience in {adapter.label}\n </Link>\n ) : null}\n </header>\n\n <div className=\"mt-12 flex flex-col gap-6\">\n {effective.contacts.write ? (\n <div>\n <EditContactButton audienceId={audienceId} contact={null} />\n </div>\n ) : null}\n {effective.contacts.read ? (\n <Suspense fallback={<div aria-busy style={{ minHeight: \"12rem\" }} />}>\n <DetailContacts audienceId={audienceId} initPageResult={initPageResult} />\n </Suspense>\n ) : (\n <p role=\"alert\">You do not have permission to list contacts.</p>\n )}\n </div>\n </>\n )\n}\n\nasync function DetailContacts({\n audienceId,\n initPageResult,\n}: {\n audienceId: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const contacts = await adapter.contacts.list({ audienceId })\n return <ContactsTable audienceId={audienceId} contacts={contacts} />\n}\n","import type {\n MarketingAdapter,\n MarketingEffectivePermissions,\n MarketingPluginPermissions,\n} from \"./types\"\nimport type { Payload, PayloadRequest } from \"payload\"\n\nexport const MARKETING_CUSTOM_CONFIG_KEY = \"payloadPluginMarketing\"\n\nexport interface MarketingIntegrationState {\n adapter: MarketingAdapter\n adminBasePath: string\n permissions?: MarketingPluginPermissions\n}\n\nfunction effectiveResource(slice: { read?: boolean; write?: boolean } | undefined): {\n read: boolean\n write: boolean\n} {\n return {\n read: slice?.read ?? true,\n write: slice?.write ?? true,\n }\n}\n\n/** Resolves endpoint access flags. If `permissions` is absent (plugin option omitted), all actions are allowed for authenticated users. */\nexport function resolveMarketingPermissions(\n permissions: MarketingPluginPermissions | undefined,\n): MarketingEffectivePermissions {\n if (!permissions) {\n return {\n audiences: { read: true, write: true },\n broadcasts: { read: true, write: true },\n contacts: { read: true, write: true },\n }\n }\n return {\n audiences: effectiveResource(permissions.audiences),\n contacts: effectiveResource(permissions.contacts),\n broadcasts: effectiveResource(permissions.broadcasts),\n }\n}\n\nexport function marketingMetaAllowed(effective: MarketingEffectivePermissions): boolean {\n return effective.audiences.read || effective.contacts.read || effective.broadcasts.read\n}\n\nfunction readIntegration(payload: Payload): MarketingIntegrationState | undefined {\n const custom = payload.config.custom as Record<string, unknown> | undefined\n if (!custom || typeof custom !== \"object\") {\n return undefined\n }\n const slice = custom[MARKETING_CUSTOM_CONFIG_KEY] as MarketingIntegrationState | undefined\n if (!slice?.adapter) {\n return undefined\n }\n return slice\n}\n\nexport function getMarketingIntegration(payload: Payload): MarketingIntegrationState {\n const state = readIntegration(payload)\n if (!state) {\n throw new Error(\n `${MARKETING_CUSTOM_CONFIG_KEY}: adapter missing on Payload config. Is marketingPlugin() registered?`,\n )\n }\n return state\n}\n\nexport function tryGetMarketingIntegration(payload: Payload): MarketingIntegrationState | undefined {\n return readIntegration(payload)\n}\n\nexport function getMarketingIntegrationFromRequest(req: PayloadRequest): MarketingIntegrationState {\n return getMarketingIntegration(req.payload)\n}\n","\"use client\"\n\nimport React from \"react\"\nimport {\n CheckboxField,\n Form,\n Pagination,\n Table,\n TextField,\n toast,\n useModal,\n useTranslation,\n Button as PayloadButton,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\nimport ReactRaw from \"react\"\nimport { useTransition } from \"react\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n} from \"./payload-modal\"\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingContact } from \"../../types\"\n\nimport type { Data, FormState } from \"payload\"\n\ninterface ContactsTableProps {\n audienceId: string\n contacts: MarketingContact[]\n}\n\nexport function ContactsTable({ audienceId, contacts }: ContactsTableProps) {\n const [page, setPage] = React.useState(1)\n const [limit] = React.useState(100)\n const currentPage = React.useMemo(\n () => contacts.slice((page - 1) * limit, page * limit),\n [contacts, limit, page],\n )\n\n return (\n <>\n <Table\n columns={[\n {\n Heading: \"First name\",\n accessor: \"firstName\",\n active: true,\n field: { name: \"firstName\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{contact.firstName ?? \"—\"}</div>\n )),\n },\n {\n Heading: \"Last name\",\n accessor: \"lastName\",\n active: true,\n field: { name: \"lastName\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{contact.lastName ?? \"—\"}</div>\n )),\n },\n {\n Heading: \"Email\",\n accessor: \"email\",\n active: true,\n field: { name: \"email\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{contact.email}</div>\n )),\n },\n {\n Heading: \"Created\",\n accessor: \"createdAt\",\n active: true,\n field: { name: \"createdAt\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{formatMarketingDate(contact.createdAt)}</div>\n )),\n },\n {\n Heading: \"Status\",\n accessor: \"subscribed\",\n active: true,\n field: { name: \"subscribed\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id} className=\"flex items-center gap-4 flex-wrap\">\n <span>{contact.subscribed !== false ? \"✅ subscribed\" : \"❌ unsubscribed\"}</span>\n <EditContactButton audienceId={audienceId} contact={contact} />\n <DeleteContactButton\n audienceId={audienceId}\n contactEmail={contact.email}\n contactId={contact.id}\n />\n </div>\n )),\n },\n ]}\n data={currentPage as unknown as Record<string, unknown>[]}\n />\n <Pagination\n hasNextPage={page * limit < contacts.length}\n hasPrevPage={page > 1}\n limit={limit}\n onChange={(p) => {\n setPage(p)\n }}\n page={page}\n totalPages={Math.ceil(contacts.length / limit)}\n />\n </>\n )\n}\n\nfunction DeleteContactButton({\n audienceId,\n contactId,\n contactEmail,\n}: {\n audienceId: string\n contactEmail: string\n contactId: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `delete-contact_${contactId}`\n\n async function confirmDelete(): Promise<void> {\n await requestJson(`/marketing/audiences/${encodeURIComponent(audienceId)}/contacts/${encodeURIComponent(contactId)}`, {\n method: \"DELETE\",\n })\n toast.success(t(\"general:deletedSuccessfully\"))\n modal.closeModal(modalSlug)\n router.refresh()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent>\n <PayloadModalBody>\n <h1>{t(\"general:confirmDeletion\")}</h1>\n <p>{`Remove contact ${contactEmail}?`}</p>\n </PayloadModalBody>\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton\n buttonStyle=\"error\"\n onClick={() => {\n void confirmDelete().catch((err: unknown) =>\n toast.error(err instanceof Error ? err.message : \"Delete failed\"),\n )\n }}\n >\n {t(\"general:confirm\")}\n </PayloadButton>\n </PayloadModalFooter>\n </PayloadModalContent>\n </PayloadModal>\n <button onClick={() => modal.openModal(modalSlug)} type=\"button\">\n {t(\"general:delete\")}\n </button>\n </>\n )\n}\n\nexport function EditContactButton({\n audienceId,\n contact,\n}: {\n audienceId: string\n contact: MarketingContact | null\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const id = ReactRaw.useId()\n const slug = contact ? `edit-contact_${contact.id}` : `create-contact_${audienceId}_${id}`\n\n const ButtonComp = contact ? \"button\" : PayloadButton\n\n return (\n <>\n <EditContactModalWrapper audienceId={audienceId} contact={contact} modalSlug={slug} />\n <ButtonComp {...(contact ? {} : { size: \"large\" })} onClick={() => modal.openModal(slug)} type=\"button\">\n {contact ? t(\"general:edit\") : t(\"general:createNew\")}\n </ButtonComp>\n </>\n )\n}\n\nfunction EditContactModalWrapper({\n audienceId,\n contact,\n modalSlug,\n}: {\n audienceId: string\n contact: MarketingContact | null\n modalSlug: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const [, startTransition] = useTransition()\n\n const submit = (fields: FormState, data: Data) => {\n const email = data.email as string\n const firstName = String(data.firstName ?? \"\")\n const lastName = String(data.lastName ?? \"\")\n const subscribed = Boolean(data.subscribed)\n\n startTransition(() => {\n void (async () => {\n try {\n await requestJson(\"/marketing/contacts\", {\n body: JSON.stringify({\n audienceId,\n email,\n firstName,\n id: contact?.id,\n lastName,\n subscribed,\n }),\n method: \"POST\",\n })\n toast.success(contact ? \"Contact updated.\" : \"Contact created.\")\n modal.closeModal(modalSlug)\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Save failed\")\n }\n })()\n })\n }\n\n return (\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent style={{ width: \"100%\", maxWidth: \"32rem\" }}>\n <PayloadModalBody>\n <h1>{contact ? t(\"general:edit\") : t(\"general:createNew\")}</h1>\n <Form\n className=\"flex w-full flex-col gap-6\"\n initialState={{\n email: {\n value: contact?.email ?? \"\",\n },\n firstName: {\n value: contact?.firstName ?? \"\",\n },\n lastName: {\n value: contact?.lastName ?? \"\",\n },\n subscribed: {\n value: contact?.subscribed !== false,\n },\n }}\n onSubmit={submit}\n waitForAutocomplete\n >\n <TextField\n field={{\n label: t(\"general:email\"),\n name: \"email\",\n required: true,\n type: \"text\",\n }}\n path=\"email\"\n validate={(v) => (typeof v === \"string\" && v.includes(\"@\") ? true : \"Valid email required\")}\n />\n <TextField\n field={{\n label: \"First name\",\n name: \"firstName\",\n type: \"text\",\n }}\n path=\"firstName\"\n />\n <TextField\n field={{\n label: \"Last name\",\n name: \"lastName\",\n type: \"text\",\n }}\n path=\"lastName\"\n />\n <CheckboxField\n field={{\n label: \"Subscribed\",\n name: \"subscribed\",\n }}\n path=\"subscribed\"\n />\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton size=\"large\" type=\"submit\">\n {contact ? t(\"general:save\") : t(\"general:create\")}\n </PayloadButton>\n </PayloadModalFooter>\n </Form>\n </PayloadModalBody>\n </PayloadModalContent>\n </PayloadModal>\n )\n}\n","export function formatMarketingDate(iso?: string | null): string {\n if (!iso) return \"—\"\n const d = new Date(iso)\n return Number.isNaN(d.valueOf())\n ? String(iso)\n : new Intl.DateTimeFormat(undefined, { dateStyle: \"medium\" }).format(d)\n}\n","\"use client\"\n\nimport React from \"react\"\nimport { Button, Modal, useModal, useTranslation } from \"@payloadcms/ui\"\n\nconst PayloadModalContext = React.createContext({ modalSlug: \"\" })\n\ninterface PayloadModalProps extends React.ComponentProps<typeof Modal> {\n children: React.ReactNode\n}\n\nfunction PayloadModal({ children, className: _className, slug: modalSlug, ...props }: PayloadModalProps) {\n const [loaded, setLoaded] = React.useState(false)\n\n React.useEffect(() => {\n setLoaded(true)\n }, [])\n\n return (\n <PayloadModalContext.Provider value={{ modalSlug }}>\n {loaded && (\n <Modal slug={modalSlug} {...props}>\n {children}\n </Modal>\n )}\n </PayloadModalContext.Provider>\n )\n}\n\nfunction PayloadModalContent({ children, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"payload-modal-content\" {...props}>\n {children}\n </div>\n )\n}\n\nfunction PayloadModalBody({ children, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"payload-modal-body\" {...props}>\n {children}\n </div>\n )\n}\n\nfunction PayloadModalTitle({ children, ...props }: React.ComponentProps<\"h1\">) {\n return (\n <h1 data-slot=\"payload-modal-title\" {...props}>\n {children}\n </h1>\n )\n}\n\nfunction PayloadModalFooter({ children, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"payload-modal-footer\" {...props}>\n {children}\n </div>\n )\n}\n\nfunction PayloadModalClose({ children, className: _className, ...props }: React.ComponentProps<typeof Button>) {\n const { t } = useTranslation()\n const { modalSlug } = React.useContext(PayloadModalContext)\n const modal = useModal()\n\n return (\n <Button\n buttonStyle=\"secondary\"\n data-slot=\"payload-modal-close\"\n size=\"large\"\n {...props}\n onClick={(e) => {\n modal.closeModal(modalSlug)\n props.onClick?.(e)\n }}\n >\n {children ?? t(\"general:cancel\")}\n </Button>\n )\n}\n\nexport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n}\n","import { DefaultTemplate } from \"@payloadcms/next/templates\"\nimport type { AdminViewServerProps } from \"payload\"\nimport type { ReactNode } from \"react\"\n\ntype ShellProps = Pick<AdminViewServerProps, \"initPageResult\" | \"params\" | \"searchParams\"> & {\n children: ReactNode\n}\n\nexport function MarketingViewShell({ children, initPageResult, params, searchParams }: ShellProps) {\n return (\n <DefaultTemplate\n i18n={initPageResult.req.i18n}\n locale={initPageResult.locale}\n params={params}\n payload={initPageResult.req.payload}\n permissions={initPageResult.permissions}\n searchParams={searchParams}\n user={initPageResult.req.user ?? undefined}\n visibleEntities={initPageResult.visibleEntities}\n >\n {children}\n </DefaultTemplate>\n )\n}\n","import type { AdminViewServerProps } from \"payload\"\n\nfunction firstString(value: string | string[] | undefined): string | undefined {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim()\n }\n if (Array.isArray(value) && typeof value[0] === \"string\" && value[0].trim()) {\n return value[0].trim()\n }\n return undefined\n}\n\n/** Resolve audience id from custom admin view params (`:id` or URL segments). */\nexport function marketingAudienceIdFromParams(\n params: AdminViewServerProps[\"params\"] | undefined,\n): string | undefined {\n if (!params) {\n return undefined\n }\n\n const fromId = firstString(params.id)\n if (fromId) {\n return fromId\n }\n\n const segmentsRaw = params.segments\n const segmentList: string[] = Array.isArray(segmentsRaw)\n ? segmentsRaw.filter((s): s is string => typeof s === \"string\" && s.length > 0)\n : typeof segmentsRaw === \"string\"\n ? segmentsRaw.split(\"/\").filter(Boolean)\n : []\n\n if (segmentList.length === 0) {\n return undefined\n }\n\n const audienceIdx = segmentList.lastIndexOf(\"audience\")\n if (audienceIdx >= 0 && segmentList[audienceIdx + 1]) {\n return segmentList[audienceIdx + 1]\n }\n\n const last = segmentList[segmentList.length - 1]\n if (last === \"audience\") {\n return undefined\n }\n return last\n}\n","import { Suspense } from \"react\"\nimport { Gutter, Link, Table } from \"@payloadcms/ui\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { marketingAdminHref } from \"../paths\"\nimport { CreateAudienceButton, DeleteAudienceButton } from \"./audience-buttons\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\n\nexport type AudienceListViewProps = AdminViewServerProps & {\n basePath?: string\n}\n\nexport default function AudienceList({\n basePath = \"\",\n initPageResult,\n params,\n searchParams,\n}: AudienceListViewProps) {\n return (\n <MarketingViewShell initPageResult={initPageResult} params={params} searchParams={searchParams}>\n <Gutter>\n <AudienceListBody basePath={basePath} initPageResult={initPageResult} />\n </Gutter>\n </MarketingViewShell>\n )\n}\n\nfunction AudienceListBody({\n basePath,\n initPageResult,\n}: {\n basePath: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const integration = tryGetMarketingIntegration(initPageResult.req.payload)\n if (!integration) {\n return (\n <p role=\"alert\">\n Marketing plugin is not configured (missing adapter on Payload config).\n </p>\n )\n }\n\n const effective = resolveMarketingPermissions(integration.permissions)\n if (!effective.audiences.read) {\n return <p role=\"alert\">You do not have permission to view audiences.</p>\n }\n\n const audiencesUrl = integration.adapter.urls?.audiences\n\n return (\n <>\n <header className=\"flex flex-col gap-4\">\n <h1>Audiences</h1>\n {audiencesUrl ? (\n <Link href={audiencesUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n View audiences in {integration.adapter.label}\n </Link>\n ) : null}\n </header>\n\n <div className=\"mt-4 flex flex-col gap-8\">\n {effective.audiences.write ? (\n <div>\n <CreateAudienceButton />\n </div>\n ) : null}\n <Suspense fallback={<div aria-busy style={{ minHeight: \"4rem\" }} />}>\n <AudienceTableRows\n audiencesWrite={effective.audiences.write}\n basePath={basePath}\n initPageResult={initPageResult}\n />\n </Suspense>\n </div>\n </>\n )\n}\n\nasync function AudienceTableRows({\n audiencesWrite,\n basePath,\n initPageResult,\n}: {\n audiencesWrite: boolean\n basePath: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const audiences = await adapter.audiences.list()\n\n const nameColumn = {\n Heading: \"Name\",\n accessor: \"name\",\n active: true,\n field: { name: \"name\", type: \"text\" as const },\n renderedCells: audiences.map((audience) => (\n <div key={audience.id}>\n <Link href={marketingAdminHref(basePath, \"audience\", audience.id)}>{audience.name}</Link>\n </div>\n )),\n }\n\n const deleteColumn = {\n Heading: \"\",\n accessor: \"\",\n active: true,\n field: { name: \"_delete\", type: \"text\" as const },\n renderedCells: audiences.map((audience) => (\n <div key={audience.id}>\n <DeleteAudienceButton audienceId={audience.id} audienceName={audience.name} />\n </div>\n )),\n }\n\n return (\n <Table\n columns={audiencesWrite ? [nameColumn, deleteColumn] : [nameColumn]}\n data={audiences as unknown as Record<string, unknown>[]}\n />\n )\n}\n","\"use client\"\n\nimport { useTransition } from \"react\"\nimport {\n Button,\n Form,\n TextField,\n toast,\n useModal,\n useTranslation,\n Button as PayloadButton,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\n\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { Data, FormState } from \"payload\"\n\nconst createAudienceSlug = \"create-audience\"\n\nexport function CreateAudienceButton() {\n const modal = useModal()\n const { t } = useTranslation()\n\n return (\n <>\n <CreateAudienceModal />\n <Button onClick={() => modal.openModal(createAudienceSlug)} size=\"large\" type=\"button\">\n {t(\"general:createNew\")}\n </Button>\n </>\n )\n}\n\nfunction CreateAudienceModal() {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const [isPending, startTransition] = useTransition()\n\n const submit = (fields: FormState, data: Data) => {\n const row = data as Record<string, unknown>\n const nameRaw: unknown = row.audienceName\n const name = typeof nameRaw === \"string\" ? nameRaw.trim() : \"\"\n startTransition(() => {\n void (async () => {\n try {\n if (!name) {\n throw new Error(\"Name is required.\")\n }\n await requestJson(\"/marketing/audiences\", {\n body: JSON.stringify({ name }),\n method: \"POST\",\n })\n modal.closeModal(createAudienceSlug)\n toast.success(t(\"general:successfullyCreated\"))\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Create failed\")\n }\n })()\n })\n }\n\n return (\n <PayloadModal closeOnBlur slug={createAudienceSlug}>\n <PayloadModalContent style={{ width: \"100%\", maxWidth: \"24rem\" }}>\n <Form initialState={{}} onSubmit={submit} waitForAutocomplete>\n <PayloadModalBody>\n <PayloadModalTitle>{t(\"general:createNew\")}</PayloadModalTitle>\n <TextField\n field={{\n name: \"audienceName\",\n required: true,\n type: \"text\",\n }}\n path=\"audienceName\"\n validate={(v) => (typeof v === \"string\" && v.trim().length > 0 ? true : \"Name is required\")}\n />\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <Button disabled={isPending} size=\"large\" type=\"submit\">\n {t(\"general:confirm\")}\n </Button>\n </PayloadModalFooter>\n </PayloadModalBody>\n </Form>\n </PayloadModalContent>\n </PayloadModal>\n )\n}\n\nexport function DeleteAudienceButton({\n audienceId,\n audienceName,\n}: {\n audienceId: string\n audienceName: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `delete-audience_${audienceId}`\n\n async function confirmDelete(): Promise<void> {\n await requestJson(`/marketing/audiences/${encodeURIComponent(audienceId)}`, {\n method: \"DELETE\",\n })\n toast.success(t(\"general:deletedSuccessfully\"))\n modal.closeModal(modalSlug)\n router.refresh()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent>\n <PayloadModalBody>\n <PayloadModalTitle>{t(\"general:confirmDeletion\")}</PayloadModalTitle>\n <p>{`Remove audience \"${audienceName}\"?`}</p>\n </PayloadModalBody>\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton\n buttonStyle=\"error\"\n onClick={() => {\n void confirmDelete().catch((err: unknown) =>\n toast.error(err instanceof Error ? err.message : \"Delete failed\"),\n )\n }}\n >\n {t(\"general:confirm\")}\n </PayloadButton>\n </PayloadModalFooter>\n </PayloadModalContent>\n </PayloadModal>\n <button onClick={() => modal.openModal(modalSlug)} type=\"button\">\n {t(\"general:delete\")}\n </button>\n </>\n )\n}\n","import { Suspense } from \"react\"\nimport { Gutter, Link } from \"@payloadcms/ui\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { BroadcastsTable } from \"./broadcasts-table\"\nimport { CreateBroadcastButton } from \"./create-broadcast-button\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\nimport type { MarketingBroadcastRow } from \"./broadcasts-table\"\n\nexport type BroadcastListViewProps = AdminViewServerProps & {\n basePath?: string\n}\n\nexport default function BroadcastList({\n initPageResult,\n params,\n searchParams,\n}: BroadcastListViewProps) {\n return (\n <MarketingViewShell initPageResult={initPageResult} params={params} searchParams={searchParams}>\n <Gutter>\n <BroadcastListBody initPageResult={initPageResult} />\n </Gutter>\n </MarketingViewShell>\n )\n}\n\nfunction BroadcastListBody({\n initPageResult,\n}: {\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const integration = tryGetMarketingIntegration(initPageResult.req.payload)\n if (!integration) {\n return (\n <p role=\"alert\">\n Marketing plugin is not configured (missing adapter on Payload config).\n </p>\n )\n }\n\n const effective = resolveMarketingPermissions(integration.permissions)\n if (!effective.broadcasts.read) {\n return <p role=\"alert\">You do not have permission to view broadcasts.</p>\n }\n\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const broadcastsUrl = adapter.urls?.broadcasts\n\n return (\n <>\n <header className=\"flex flex-col gap-4\">\n <h1>Campaigns</h1>\n {broadcastsUrl ? (\n <Link href={broadcastsUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n View campaigns in {adapter.label}\n </Link>\n ) : null}\n </header>\n\n <div className=\"mt-4 flex flex-col gap-8\">\n {effective.broadcasts.write ? (\n <div>\n <Suspense fallback={<div aria-busy style={{ minHeight: \"2.5rem\" }} />}>\n <CreateBroadcastRegion initPageResult={initPageResult} />\n </Suspense>\n </div>\n ) : null}\n <Suspense fallback={<div aria-busy style={{ minHeight: \"4rem\" }} />}>\n <BroadcastTableRegion initPageResult={initPageResult} />\n </Suspense>\n </div>\n </>\n )\n}\n\nasync function CreateBroadcastRegion({\n initPageResult,\n}: {\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const audiences = await adapter.audiences.list()\n return <CreateBroadcastButton audiences={audiences} provider={adapter.provider} />\n}\n\nasync function BroadcastTableRegion({\n initPageResult,\n}: {\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const rows = await adapter.broadcasts.list()\n const broadcasts: MarketingBroadcastRow[] = rows.map((b) => ({\n ...b,\n externalDashboardUrl: adapter.urls?.broadcast?.(b.id),\n }))\n\n return <BroadcastsTable broadcasts={broadcasts} />\n}\n","\"use client\"\n\nimport React from \"react\"\nimport {\n Button as PayloadButton,\n DateTimeField,\n Form,\n Pagination,\n Pill,\n Table,\n toast,\n useModal,\n useTranslation,\n} from \"@payloadcms/ui\"\nimport Link from \"next/link\"\nimport { useRouter } from \"next/navigation\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingBroadcast } from \"../../types\"\nimport type { Data, FormState } from \"payload\"\n\nexport interface MarketingBroadcastRow extends MarketingBroadcast {\n externalDashboardUrl?: string\n}\n\ninterface BroadcastsTableProps {\n broadcasts: MarketingBroadcastRow[]\n}\n\nexport function BroadcastsTable({ broadcasts }: BroadcastsTableProps) {\n const [page, setPage] = React.useState(1)\n const [limit] = React.useState(100)\n const currentPage = React.useMemo(\n () => broadcasts.slice((page - 1) * limit, page * limit),\n [broadcasts, limit, page],\n )\n\n return (\n <>\n <Table\n columns={[\n {\n Heading: \"Campaign name\",\n accessor: \"name\",\n active: true,\n field: { name: \"name\", type: \"text\" },\n renderedCells: currentPage.map((b) => <div key={b.id}>{b.name}</div>),\n },\n {\n Heading: \"Schedule date\",\n accessor: \"scheduledAt\",\n active: true,\n field: { name: \"scheduledAt\", type: \"text\" },\n renderedCells: currentPage.map((b) => (\n <div key={b.id}>{formatMarketingDate(b.scheduledAt)}</div>\n )),\n },\n {\n Heading: \"Sent date\",\n accessor: \"sentAt\",\n active: true,\n field: { name: \"sentAt\", type: \"text\" },\n renderedCells: currentPage.map((b) => <div key={b.id}>{formatMarketingDate(b.sentAt)}</div>),\n },\n {\n Heading: \"Status\",\n accessor: \"status\",\n active: true,\n field: { name: \"status\", type: \"text\" },\n renderedCells: currentPage.map((broadcast) => (\n <div key={broadcast.id}>\n <BroadcastStatusPill status={broadcast.status} />\n </div>\n )),\n },\n {\n Heading: \"\",\n accessor: \"\",\n active: true,\n field: { name: \"_\", type: \"text\" },\n renderedCells: currentPage.map((broadcast) => (\n <div key={broadcast.id} className=\"flex items-center gap-4 flex-wrap\">\n {broadcast.externalDashboardUrl ? (\n <Link href={broadcast.externalDashboardUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n <Pill>dashboard ↗</Pill>\n </Link>\n ) : null}\n {broadcast.status === \"draft\" || broadcast.status === \"save\" ? (\n <>\n <DeleteBroadcastButton broadcastId={broadcast.id} broadcastName={broadcast.name} />\n <SendBroadcastButton broadcastId={broadcast.id} broadcastName={broadcast.name} />\n </>\n ) : null}\n </div>\n )),\n },\n ]}\n data={currentPage as unknown as Record<string, unknown>[]}\n />\n <Pagination\n hasNextPage={page * limit < broadcasts.length}\n hasPrevPage={page > 1}\n limit={limit}\n onChange={(p) => setPage(p)}\n page={page}\n totalPages={Math.ceil(broadcasts.length / limit)}\n />\n </>\n )\n}\n\nfunction BroadcastStatusPill({ status }: { status: string }) {\n switch (status) {\n case \"draft\":\n case \"save\": {\n return <Pill pillStyle=\"light-gray\">Draft</Pill>\n }\n case \"queued\": {\n return <Pill pillStyle=\"white\">Queued</Pill>\n }\n case \"sent\": {\n return <Pill pillStyle=\"success\">Sent</Pill>\n }\n default: {\n return <Pill>{status}</Pill>\n }\n }\n}\n\nfunction DeleteBroadcastButton({\n broadcastId,\n broadcastName,\n}: {\n broadcastId: string\n broadcastName: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `delete-broadcast_${broadcastId}`\n\n async function confirmDelete(): Promise<void> {\n await requestJson(`/marketing/broadcasts/${encodeURIComponent(broadcastId)}`, { method: \"DELETE\" })\n toast.success(t(\"general:deletedSuccessfully\"))\n modal.closeModal(modalSlug)\n router.refresh()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent>\n <PayloadModalBody>\n <PayloadModalTitle>{t(\"general:confirmDeletion\")}</PayloadModalTitle>\n <p>{`Delete draft broadcast \"${broadcastName}\"?`}</p>\n </PayloadModalBody>\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton\n buttonStyle=\"error\"\n onClick={() => {\n void confirmDelete().catch((err: unknown) =>\n toast.error(err instanceof Error ? err.message : \"Delete failed\"),\n )\n }}\n >\n {t(\"general:confirm\")}\n </PayloadButton>\n </PayloadModalFooter>\n </PayloadModalContent>\n </PayloadModal>\n <button onClick={() => modal.openModal(modalSlug)} type=\"button\">\n {t(\"general:delete\")}\n </button>\n </>\n )\n}\n\nexport function SendBroadcastButton({\n broadcastId,\n broadcastName,\n}: {\n broadcastId: string\n broadcastName: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `send-broadcast_${broadcastId}`\n\n const submit = (fields: FormState, data: Data) => {\n const row = data as Record<string, unknown>\n const scheduledRaw: unknown = row.scheduledAt\n let scheduledAt = \"\"\n if (typeof scheduledRaw === \"string\") {\n scheduledAt = scheduledRaw\n } else if (scheduledRaw instanceof Date) {\n scheduledAt = scheduledRaw.toISOString()\n }\n\n void (async () => {\n try {\n await requestJson(`/marketing/broadcasts/${encodeURIComponent(broadcastId)}/send`, {\n body: JSON.stringify({\n ...(scheduledAt && scheduledAt.trim() !== \"\"\n ? { scheduledAt: scheduledAt.trim() }\n : {}),\n }),\n method: \"POST\",\n })\n modal.closeModal(modalSlug)\n toast.success(t(\"general:success\"))\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Send failed\")\n }\n })()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent style={{ width: \"100%\", maxWidth: \"24rem\" }}>\n <PayloadModalBody>\n <PayloadModalTitle>{`Send “${broadcastName}”`}</PayloadModalTitle>\n <Form initialState={{}} onSubmit={submit} waitForAutocomplete>\n <DateTimeField\n field={{\n label: \"Schedule at (optional)\",\n name: \"scheduledAt\",\n required: false,\n }}\n path=\"scheduledAt\"\n />\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton size=\"large\" type=\"submit\">\n Send\n </PayloadButton>\n </PayloadModalFooter>\n </Form>\n </PayloadModalBody>\n </PayloadModalContent>\n </PayloadModal>\n <Pill pillStyle=\"dark\" onClick={() => modal.openModal(modalSlug)} size=\"small\">\n Send\n </Pill>\n </>\n )\n}\n","\"use client\"\n\nimport React from \"react\"\nimport {\n Button,\n Drawer,\n Form,\n SelectField,\n TextareaField,\n TextField,\n toast,\n useModal,\n useTranslation,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingAudience } from \"../../types\"\n\nimport type { Data, FormState } from \"payload\"\n\nconst modalSlug = \"create-marketing-broadcast\"\n\nexport function CreateBroadcastButton({\n audiences,\n provider,\n}: {\n audiences: MarketingAudience[]\n provider: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n\n return (\n <>\n <CreateBroadcastModal audiences={audiences} provider={provider} />\n <Button onClick={() => modal.openModal(modalSlug)} size=\"large\" type=\"button\">\n {t(\"general:createNew\")}\n </Button>\n </>\n )\n}\n\nfunction CreateBroadcastModal({\n audiences,\n provider,\n}: {\n audiences: MarketingAudience[]\n provider: string\n}) {\n const router = useRouter()\n const modal = useModal()\n const { t } = useTranslation()\n const { requestJson } = useMarketingApi()\n const [isPending, setIsPending] = React.useState(false)\n\n const showTemplateField = provider === \"mailchimp\"\n\n const submit = (fields: FormState, data: Data) => {\n const row = data as Record<string, unknown>\n const audienceIdRaw: unknown = row.audienceId\n const nameRaw: unknown = row.name\n const subjectRaw: unknown = row.subject\n const htmlRaw: unknown = row.htmlBody\n const templateIdRaw: unknown = row.templateId\n const replyToRaw: unknown = row.replyTo\n\n const audienceId = typeof audienceIdRaw === \"string\" ? audienceIdRaw : \"\"\n const name = typeof nameRaw === \"string\" ? nameRaw.trim() : \"\"\n const subject = typeof subjectRaw === \"string\" ? subjectRaw.trim() : \"\"\n const htmlBody = typeof htmlRaw === \"string\" ? htmlRaw.trim() : \"\"\n const templateId = typeof templateIdRaw === \"string\" ? templateIdRaw.trim() : \"\"\n const replyTo = typeof replyToRaw === \"string\" ? replyToRaw.trim() : \"\"\n\n setIsPending(true)\n void (async () => {\n try {\n if (!audienceId || !name || !subject) {\n throw new Error(\"Audience, name, and subject are required.\")\n }\n if (showTemplateField) {\n if (!templateId && !htmlBody) {\n throw new Error(\"Provide an HTML body or Mailchimp template id.\")\n }\n if (templateId && htmlBody) {\n throw new Error(\"Use either HTML body or Mailchimp template id, not both.\")\n }\n } else if (!htmlBody) {\n throw new Error(\"HTML body is required for this provider.\")\n }\n\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n html: htmlBody,\n name,\n replyTo,\n subject,\n templateId: templateId || undefined,\n }),\n method: \"POST\",\n })\n\n modal.closeModal(modalSlug)\n toast.success(t(\"general:successfullyCreated\", { label: \"Broadcast\" }))\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Create failed\")\n } finally {\n setIsPending(false)\n }\n })()\n }\n\n return (\n <Drawer slug={modalSlug} title={t(\"general:createNew\")}>\n <Form\n className=\"flex w-full flex-col gap-8\"\n initialState={{}}\n onSubmit={submit}\n waitForAutocomplete\n >\n <SelectField\n field={{\n label: \"Audience\",\n name: \"audienceId\",\n options: audiences.map((a) => ({ label: a.name, value: a.id })),\n required: true,\n }}\n path=\"audienceId\"\n />\n <TextField\n field={{\n label: \"Campaign name\",\n name: \"name\",\n required: true,\n type: \"text\",\n }}\n path=\"name\"\n />\n <TextField\n field={{\n label: \"Subject\",\n name: \"subject\",\n required: true,\n type: \"text\",\n }}\n path=\"subject\"\n />\n <TextField\n field={{\n label: \"Reply-to (optional)\",\n name: \"replyTo\",\n type: \"text\",\n }}\n path=\"replyTo\"\n />\n\n {showTemplateField ? (\n <TextField\n field={{\n admin: {\n description:\n \"Optional Mailchimp saved-template id (numeric string). Leave HTML empty when using templates.\",\n },\n label: \"Template id\",\n name: \"templateId\",\n required: false,\n type: \"text\",\n }}\n path=\"templateId\"\n />\n ) : null}\n\n <TextareaField\n field={{\n admin: {\n description: showTemplateField\n ? \"Optional plain HTML alternative to a Mailchimp template.\"\n : \"HTML broadcast body.\",\n },\n label: showTemplateField ? \"HTML body (optional with Mailchimp)\" : \"HTML body\",\n name: \"htmlBody\",\n required: !showTemplateField,\n }}\n path=\"htmlBody\"\n />\n\n <Button className=\"w-full\" disabled={isPending} type=\"submit\">\n {t(\"general:create\")}\n </Button>\n </Form>\n </Drawer>\n )\n}\n"],"mappings":"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","names":["admin_exports","__export","AudienceDetail","AudienceList","AudienceSelect","AudienceTable","BroadcastList","BroadcastsTable","ContactsTable","MarketingMenu","defaultAdminComponentPath","__toCommonJS","import_react","import_ui","import_ui","import_react","useMarketingApi","context","base","requestJson","pathSegment","init","_headersIgnored","restInit","headers","res","detail","parsed","joinAdminSegments","adminRoute","segments","trimmedAdmin","body","s","segment","marketingAdminHref","basePath","parts","import_jsx_runtime","parseAudiences","payload","out","item","rec","id","name","AudienceSelect","field","path","readOnly","requestJson","useMarketingApi","audiences","setAudiences","React","loadError","setLoadError","cancelled","data","err","a","MarketingMenu","basePath","marketingAdminHref","AudienceTable","audience","ContactsTable","contacts","contact","BroadcastsTable","broadcasts","broadcast","import_react","import_navigation","import_ui","MARKETING_CUSTOM_CONFIG_KEY","effectiveResource","slice","resolveMarketingPermissions","permissions","readIntegration","payload","custom","slice","MARKETING_CUSTOM_CONFIG_KEY","getMarketingIntegration","state","tryGetMarketingIntegration","import_react","import_ui","import_navigation","formatMarketingDate","iso","d","import_react","import_ui","import_jsx_runtime","PayloadModalContext","React","PayloadModal","children","_className","modalSlug","props","loaded","setLoaded","PayloadModalContent","PayloadModalBody","PayloadModalTitle","PayloadModalFooter","PayloadModalClose","t","modal","e","import_jsx_runtime","ContactsTable","audienceId","contacts","page","setPage","React","limit","currentPage","contact","formatMarketingDate","EditContactButton","DeleteContactButton","p","contactId","contactEmail","modal","t","router","requestJson","useMarketingApi","modalSlug","confirmDelete","PayloadModal","PayloadModalContent","PayloadModalBody","PayloadModalFooter","PayloadModalClose","PayloadButton","err","id","ReactRaw","slug","EditContactModalWrapper","startTransition","submit","fields","data","email","firstName","lastName","subscribed","v","import_templates","import_jsx_runtime","MarketingViewShell","children","initPageResult","params","searchParams","firstString","value","marketingAudienceIdFromParams","params","fromId","segmentsRaw","segmentList","s","audienceIdx","last","import_jsx_runtime","AudienceDetail","initPageResult","params","searchParams","audienceId","marketingAudienceIdFromParams","MarketingViewShell","AudienceDetailBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","audience","audienceDashboardUrl","EditContactButton","DetailContacts","contacts","ContactsTable","import_react","import_ui","import_react","import_ui","import_navigation","import_jsx_runtime","createAudienceSlug","CreateAudienceButton","modal","CreateAudienceModal","router","requestJson","useMarketingApi","isPending","startTransition","PayloadModal","PayloadModalContent","fields","data","nameRaw","name","err","PayloadModalBody","PayloadModalTitle","v","PayloadModalFooter","PayloadModalClose","DeleteAudienceButton","audienceId","audienceName","t","modalSlug","confirmDelete","PayloadButton","import_jsx_runtime","AudienceList","basePath","initPageResult","params","searchParams","MarketingViewShell","AudienceListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","audiencesUrl","CreateAudienceButton","AudienceTableRows","audiencesWrite","adapter","getMarketingIntegration","audiences","nameColumn","audience","marketingAdminHref","deleteColumn","DeleteAudienceButton","import_react","import_ui","import_react","import_ui","import_link","import_navigation","import_jsx_runtime","BroadcastsTable","broadcasts","page","setPage","React","limit","currentPage","b","formatMarketingDate","broadcast","BroadcastStatusPill","Link","DeleteBroadcastButton","SendBroadcastButton","p","status","broadcastId","broadcastName","modal","t","router","requestJson","useMarketingApi","modalSlug","confirmDelete","PayloadModal","PayloadModalContent","PayloadModalBody","PayloadModalTitle","PayloadModalFooter","PayloadModalClose","PayloadButton","err","submit","fields","data","scheduledRaw","scheduledAt","import_react","import_ui","import_navigation","import_jsx_runtime","modalSlug","CreateBroadcastButton","audiences","provider","modal","t","CreateBroadcastModal","router","requestJson","useMarketingApi","isPending","setIsPending","React","showTemplateField","submit","fields","data","row","audienceIdRaw","nameRaw","subjectRaw","htmlRaw","templateIdRaw","replyToRaw","audienceId","name","subject","htmlBody","templateId","replyTo","err","a","import_jsx_runtime","BroadcastList","initPageResult","params","searchParams","MarketingViewShell","BroadcastListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","broadcastsUrl","CreateBroadcastRegion","BroadcastTableRegion","audiences","CreateBroadcastButton","broadcasts","b","BroadcastsTable","defaultAdminComponentPath"]}
|
|
1
|
+
{"version":3,"sources":["../../src/admin/index.ts"],"sourcesContent":["export * from \"./constants\"\nexport * from \"./server\"\nexport * from \"./client\"\n"],"mappings":"iaAAA,IAAAA,EAAA,kBAAAC,EAAAD,GAAAE,EAAAF,EAAc,uBAAd,gBACAE,EAAAF,EAAc,oBADd,gBAEAE,EAAAF,EAAc,oBAFd","names":["admin_exports","__toCommonJS","__reExport"]}
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
1
|
+
export * from "./constants";
|
|
2
|
+
export * from "./server";
|
|
3
|
+
export * from "./client";
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA"}
|
package/dist/admin/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{b as F,d as S,e as I}from"../chunk-SX3OTOU2.js";import Z from"react";import{Link as ke,NavGroup as Ke,SelectField as Xe}from"@payloadcms/ui";import{useConfig as je}from"@payloadcms/ui";import{useCallback as We,useMemo as Ye}from"react";function h(){let e=je(),t=Ye(()=>`${e.serverURL??""}${e.routes?.api??"/api"}`,[e.routes?.api,e.serverURL]),n=We(async(a,o)=>{let{headers:r,...i}=o??{},s=new Headers(o?.headers);i.body!==void 0&&i.body!==""&&i.body!==null&&(s.has("Content-Type")||s.set("Content-Type","application/json"));let l=await fetch(`${t}${a}`,{...i,credentials:"include",headers:s});if(!l.ok){let u=`${l.status} ${l.statusText}`;try{let g=await l.json();typeof g.message=="string"&&(u=g.message)}catch{}throw new Error(u)}if(l.status!==204)try{return await l.json()}catch{return}},[t]);return{base:t,requestJson:n}}function Qe(e,...t){let n=e.replace(/\/+$/,"")||"",a=t.flatMap(r=>String(r).split("/")).map(r=>r.replace(/^\/+|\/+$/g,"")).filter(Boolean).join("/");return(n===""?`/${a}`:`${n}/${a}`).replace(/\/{2,}/g,"/")}function H(e,...t){let a=[e?.replace(/^\/+|\/+$/g,"")??"",...t].filter(Boolean);return Qe("/admin",...a)}import{jsx as p,jsxs as ve}from"react/jsx-runtime";function Ze(e){if(!Array.isArray(e))return[];let t=[];for(let n of e){if(!n||typeof n!="object")continue;let a=n,o=a.id,r=a.name;typeof o=="string"&&typeof r=="string"&&t.push({id:o,name:r})}return t}var et=({field:e,path:t,readOnly:n})=>{let{requestJson:a}=h(),[o,r]=Z.useState([]),[i,s]=Z.useState(null);return Z.useEffect(()=>{let l=!1;return(async()=>{try{let u=await a("/marketing/audiences");l||(r(Ze(u)),s(null))}catch(u){l||s(u instanceof Error?u.message:"Failed to load audiences")}})(),()=>{l=!0}},[a]),ve("div",{className:"field-type relative",children:[i?p("p",{className:"text-red-500",role:"alert",children:i}):null,p(Xe,{field:{label:typeof e.label=="string"?e.label:"Audience",name:e.name,options:o.map(l=>({label:l.name,value:l.id})),required:e.required===!0,type:"select"},path:t,readOnly:n})]})};function tt({basePath:e=""}){return ve(Ke,{isOpen:!0,label:"Marketing",children:[p(ke,{className:"nav__link",href:H(e,"audience"),children:"Audience"}),p(ke,{className:"nav__link",href:H(e,"broadcast"),children:"Broadcast"})]})}function at({audiences:e}){return p("table",{children:p("tbody",{children:e.map(t=>p("tr",{children:p("td",{children:t.name})},t.id))})})}function nt({contacts:e}){return p("table",{children:p("tbody",{children:e.map(t=>p("tr",{children:p("td",{children:t.email})},t.id))})})}function ot({broadcasts:e}){return p("table",{children:p("tbody",{children:e.map(t=>p("tr",{children:p("td",{children:t.name})},t.id))})})}import{Suspense as Mt}from"react";import{notFound as wt}from"next/navigation";import{Gutter as kt,Link as vt}from"@payloadcms/ui";import ee from"react";import{CheckboxField as dt,Form as ct,Pagination as ut,Table as mt,TextField as te,toast as J,useModal as ae,useTranslation as ne,Button as oe}from"@payloadcms/ui";import{useRouter as Ce}from"next/navigation";import pt from"react";import{useTransition as ft}from"react";function $(e){if(!e)return"\u2014";let t=new Date(e);return Number.isNaN(t.valueOf())?String(e):new Intl.DateTimeFormat(void 0,{dateStyle:"medium"}).format(t)}import U from"react";import{Button as rt,Modal as it,useModal as st,useTranslation as lt}from"@payloadcms/ui";import{jsx as R}from"react/jsx-runtime";var Se=U.createContext({modalSlug:""});function C({children:e,className:t,slug:n,...a}){let[o,r]=U.useState(!1);return U.useEffect(()=>{r(!0)},[]),R(Se.Provider,{value:{modalSlug:n},children:o&&R(it,{slug:n,...a,children:e})})}function x({children:e,...t}){return R("div",{"data-slot":"payload-modal-content",...t,children:e})}function A({children:e,...t}){return R("div",{"data-slot":"payload-modal-body",...t,children:e})}function L({children:e,...t}){return R("h1",{"data-slot":"payload-modal-title",...t,children:e})}function B({children:e,...t}){return R("div",{"data-slot":"payload-modal-footer",...t,children:e})}function N({children:e,className:t,...n}){let{t:a}=lt(),{modalSlug:o}=U.useContext(Se),r=st();return R(rt,{buttonStyle:"secondary","data-slot":"payload-modal-close",size:"large",...n,onClick:i=>{r.closeModal(o),n.onClick?.(i)},children:e??a("general:cancel")})}import{Fragment as ie,jsx as c,jsxs as k}from"react/jsx-runtime";function xe({audienceId:e,contacts:t}){let[n,a]=ee.useState(1),[o]=ee.useState(100),r=ee.useMemo(()=>t.slice((n-1)*o,n*o),[t,o,n]);return k(ie,{children:[c(mt,{columns:[{Heading:"First name",accessor:"firstName",active:!0,field:{name:"firstName",type:"text"},renderedCells:r.map(i=>c("div",{children:i.firstName??"\u2014"},i.id))},{Heading:"Last name",accessor:"lastName",active:!0,field:{name:"lastName",type:"text"},renderedCells:r.map(i=>c("div",{children:i.lastName??"\u2014"},i.id))},{Heading:"Email",accessor:"email",active:!0,field:{name:"email",type:"text"},renderedCells:r.map(i=>c("div",{children:i.email},i.id))},{Heading:"Created",accessor:"createdAt",active:!0,field:{name:"createdAt",type:"text"},renderedCells:r.map(i=>c("div",{children:$(i.createdAt)},i.id))},{Heading:"Status",accessor:"subscribed",active:!0,field:{name:"subscribed",type:"text"},renderedCells:r.map(i=>k("div",{className:"flex items-center gap-4 flex-wrap",children:[c("span",{children:i.subscribed!==!1?"\u2705 subscribed":"\u274C unsubscribed"}),c(re,{audienceId:e,contact:i}),c(gt,{audienceId:e,contactEmail:i.email,contactId:i.id})]},i.id))}],data:r}),c(ut,{hasNextPage:n*o<t.length,hasPrevPage:n>1,limit:o,onChange:i=>{a(i)},page:n,totalPages:Math.ceil(t.length/o)})]})}function gt({audienceId:e,contactId:t,contactEmail:n}){let a=ae(),{t:o}=ne(),r=Ce(),{requestJson:i}=h(),s=`delete-contact_${t}`;async function l(){await i(`/marketing/audiences/${encodeURIComponent(e)}/contacts/${encodeURIComponent(t)}`,{method:"DELETE"}),J.success(o("general:deletedSuccessfully")),a.closeModal(s),r.refresh()}return k(ie,{children:[c(C,{slug:s,children:k(x,{children:[k(A,{children:[c("h1",{children:o("general:confirmDeletion")}),c("p",{children:`Remove contact ${n}?`})]}),k(B,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[c(N,{}),c(oe,{buttonStyle:"error",onClick:()=>{l().catch(u=>J.error(u instanceof Error?u.message:"Delete failed"))},children:o("general:confirm")})]})]})}),c("button",{onClick:()=>a.openModal(s),type:"button",children:o("general:delete")})]})}function re({audienceId:e,contact:t}){let n=ae(),{t:a}=ne(),o=pt.useId(),r=t?`edit-contact_${t.id}`:`create-contact_${e}_${o}`;return k(ie,{children:[c(yt,{audienceId:e,contact:t,modalSlug:r}),c(t?"button":oe,{...t?{}:{size:"large"},onClick:()=>n.openModal(r),type:"button",children:a(t?"general:edit":"general:createNew")})]})}function yt({audienceId:e,contact:t,modalSlug:n}){let a=ae(),{t:o}=ne(),r=Ce(),{requestJson:i}=h(),[,s]=ft(),l=(u,g)=>{let M=g.email,m=String(g.firstName??""),T=String(g.lastName??""),_=!!g.subscribed;s(()=>{(async()=>{try{await i("/marketing/contacts",{body:JSON.stringify({audienceId:e,email:M,firstName:m,id:t?.id,lastName:T,subscribed:_}),method:"POST"}),J.success(t?"Contact updated.":"Contact created."),a.closeModal(n),r.refresh()}catch(V){J.error(V instanceof Error?V.message:"Save failed")}})()})};return c(C,{slug:n,children:c(x,{style:{width:"100%",maxWidth:"32rem"},children:k(A,{children:[c("h1",{children:o(t?"general:edit":"general:createNew")}),k(ct,{className:"flex w-full flex-col gap-6",initialState:{email:{value:t?.email??""},firstName:{value:t?.firstName??""},lastName:{value:t?.lastName??""},subscribed:{value:t?.subscribed!==!1}},onSubmit:l,waitForAutocomplete:!0,children:[c(te,{field:{label:o("general:email"),name:"email",required:!0,type:"text"},path:"email",validate:u=>typeof u=="string"&&u.includes("@")?!0:"Valid email required"}),c(te,{field:{label:"First name",name:"firstName",type:"text"},path:"firstName"}),c(te,{field:{label:"Last name",name:"lastName",type:"text"},path:"lastName"}),c(dt,{field:{label:"Subscribed",name:"subscribed"},path:"subscribed"}),k(B,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[c(N,{}),c(oe,{size:"large",type:"submit",children:o(t?"general:save":"general:create")})]})]})]})})})}import{DefaultTemplate as bt}from"@payloadcms/next/templates";import{jsx as ht}from"react/jsx-runtime";function q({children:e,initPageResult:t,params:n,searchParams:a}){return ht(bt,{i18n:t.req.i18n,locale:t.locale,params:n,payload:t.req.payload,permissions:t.permissions,searchParams:a,user:t.req.user??void 0,visibleEntities:t.visibleEntities,children:e})}function Pt(e){if(typeof e=="string"&&e.trim())return e.trim();if(Array.isArray(e)&&typeof e[0]=="string"&&e[0].trim())return e[0].trim()}function Ae(e){if(!e)return;let t=Pt(e.id);if(t)return t;let n=e.segments,a=Array.isArray(n)?n.filter(i=>typeof i=="string"&&i.length>0):typeof n=="string"?n.split("/").filter(Boolean):[];if(a.length===0)return;let o=a.lastIndexOf("audience");if(o>=0&&a[o+1])return a[o+1];let r=a[a.length-1];if(r!=="audience")return r}import{Fragment as xt,jsx as P,jsxs as G}from"react/jsx-runtime";function se({initPageResult:e,params:t,searchParams:n}){let a=Ae(t);if(!a)throw new Error("No audience id in route params");return P(q,{initPageResult:e,params:t,searchParams:n,children:P(kt,{children:P(St,{audienceId:a,initPageResult:e})})})}async function St({audienceId:e,initPageResult:t}){let n=I(t.req.payload);if(!n)return P("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let a=F(n.permissions);if(!a.audiences.read)return P("p",{role:"alert",children:"You do not have permission to view this audience."});let{adapter:o}=S(t.req.payload),r=await o.audiences.get(e);r||wt();let i=o.urls?.audience?.(e);return G(xt,{children:[G("header",{className:"flex flex-col gap-4",children:[P("h1",{children:r.name}),i?G(vt,{href:i,rel:"noreferrer noopener",target:"_blank",children:["Open this audience in ",o.label]}):null]}),G("div",{className:"mt-12 flex flex-col gap-6",children:[a.contacts.write?P("div",{children:P(re,{audienceId:e,contact:null})}):null,a.contacts.read?P(Mt,{fallback:P("div",{"aria-busy":!0,style:{minHeight:"12rem"}}),children:P(Ct,{audienceId:e,initPageResult:t})}):P("p",{role:"alert",children:"You do not have permission to list contacts."})]})]})}async function Ct({audienceId:e,initPageResult:t}){let{adapter:n}=S(t.req.payload),a=await n.contacts.list({audienceId:e});return P(xe,{audienceId:e,contacts:a})}import{Suspense as Dt}from"react";import{Gutter as Ft,Link as Fe,Table as It}from"@payloadcms/ui";import{useTransition as At}from"react";import{Button as Be,Form as Bt,TextField as Nt,toast as z,useModal as de,useTranslation as ce,Button as Tt}from"@payloadcms/ui";import{useRouter as Ne}from"next/navigation";import{Fragment as De,jsx as y,jsxs as D}from"react/jsx-runtime";var le="create-audience";function Te(){let e=de(),{t}=ce();return D(De,{children:[y(Rt,{}),y(Be,{onClick:()=>e.openModal(le),size:"large",type:"button",children:t("general:createNew")})]})}function Rt(){let e=de(),{t}=ce(),n=Ne(),{requestJson:a}=h(),[o,r]=At();return y(C,{closeOnBlur:!0,slug:le,children:y(x,{style:{width:"100%",maxWidth:"24rem"},children:y(Bt,{initialState:{},onSubmit:(s,l)=>{let g=l.audienceName,M=typeof g=="string"?g.trim():"";r(()=>{(async()=>{try{if(!M)throw new Error("Name is required.");await a("/marketing/audiences",{body:JSON.stringify({name:M}),method:"POST"}),e.closeModal(le),z.success(t("general:successfullyCreated")),n.refresh()}catch(m){z.error(m instanceof Error?m.message:"Create failed")}})()})},waitForAutocomplete:!0,children:D(A,{children:[y(L,{children:t("general:createNew")}),y(Nt,{field:{name:"audienceName",required:!0,type:"text"},path:"audienceName",validate:s=>typeof s=="string"&&s.trim().length>0?!0:"Name is required"}),D(B,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[y(N,{}),y(Be,{disabled:o,size:"large",type:"submit",children:t("general:confirm")})]})]})})})})}function Re({audienceId:e,audienceName:t}){let n=de(),{t:a}=ce(),o=Ne(),{requestJson:r}=h(),i=`delete-audience_${e}`;async function s(){await r(`/marketing/audiences/${encodeURIComponent(e)}`,{method:"DELETE"}),z.success(a("general:deletedSuccessfully")),n.closeModal(i),o.refresh()}return D(De,{children:[y(C,{slug:i,children:D(x,{children:[D(A,{children:[y(L,{children:a("general:confirmDeletion")}),y("p",{children:`Remove audience "${t}"?`})]}),D(B,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[y(N,{}),y(Tt,{buttonStyle:"error",onClick:()=>{s().catch(l=>z.error(l instanceof Error?l.message:"Delete failed"))},children:a("general:confirm")})]})]})}),y("button",{onClick:()=>n.openModal(i),type:"button",children:a("general:delete")})]})}import{Fragment as Et,jsx as f,jsxs as j}from"react/jsx-runtime";function ue({basePath:e="",initPageResult:t,params:n,searchParams:a}){return f(q,{initPageResult:t,params:n,searchParams:a,children:f(Ft,{children:f(Lt,{basePath:e,initPageResult:t})})})}function Lt({basePath:e,initPageResult:t}){let n=I(t.req.payload);if(!n)return f("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let a=F(n.permissions);if(!a.audiences.read)return f("p",{role:"alert",children:"You do not have permission to view audiences."});let o=n.adapter.urls?.audiences;return j(Et,{children:[j("header",{className:"flex flex-col gap-4",children:[f("h1",{children:"Audiences"}),o?j(Fe,{href:o,rel:"noreferrer noopener",target:"_blank",children:["View audiences in ",n.adapter.label]}):null]}),j("div",{className:"mt-4 flex flex-col gap-8",children:[a.audiences.write?f("div",{children:f(Te,{})}):null,f(Dt,{fallback:f("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:f(qt,{audiencesWrite:a.audiences.write,basePath:e,initPageResult:t})})]})]})}async function qt({audiencesWrite:e,basePath:t,initPageResult:n}){let{adapter:a}=S(n.req.payload),o=await a.audiences.list(),r={Heading:"Name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:o.map(s=>f("div",{children:f(Fe,{href:H(t,"audience",s.id),children:s.name})},s.id))},i={Heading:"",accessor:"",active:!0,field:{name:"_delete",type:"text"},renderedCells:o.map(s=>f("div",{children:f(Re,{audienceId:s.id,audienceName:s.name})},s.id))};return f(It,{columns:e?[r,i]:[r],data:o})}import{Suspense as Ge}from"react";import{Gutter as ea,Link as ta}from"@payloadcms/ui";import me from"react";import{Button as Ie,DateTimeField as Vt,Form as Ht,Pagination as $t,Pill as E,Table as _t,toast as W,useModal as Le,useTranslation as qe}from"@payloadcms/ui";import Ot from"next/link";import{useRouter as Ee}from"next/navigation";import{Fragment as Y,jsx as d,jsxs as w}from"react/jsx-runtime";function Ve({broadcasts:e}){let[t,n]=me.useState(1),[a]=me.useState(100),o=me.useMemo(()=>e.slice((t-1)*a,t*a),[e,a,t]);return w(Y,{children:[d(_t,{columns:[{Heading:"Campaign name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:o.map(r=>d("div",{children:r.name},r.id))},{Heading:"Schedule date",accessor:"scheduledAt",active:!0,field:{name:"scheduledAt",type:"text"},renderedCells:o.map(r=>d("div",{children:$(r.scheduledAt)},r.id))},{Heading:"Sent date",accessor:"sentAt",active:!0,field:{name:"sentAt",type:"text"},renderedCells:o.map(r=>d("div",{children:$(r.sentAt)},r.id))},{Heading:"Status",accessor:"status",active:!0,field:{name:"status",type:"text"},renderedCells:o.map(r=>d("div",{children:d(Ut,{status:r.status})},r.id))},{Heading:"",accessor:"",active:!0,field:{name:"_",type:"text"},renderedCells:o.map(r=>w("div",{className:"flex items-center gap-4 flex-wrap",children:[r.externalDashboardUrl?d(Ot,{href:r.externalDashboardUrl,rel:"noreferrer noopener",target:"_blank",children:d(E,{children:"dashboard \u2197"})}):null,r.status==="draft"||r.status==="save"?w(Y,{children:[d(Jt,{broadcastId:r.id,broadcastName:r.name}),d(Gt,{broadcastId:r.id,broadcastName:r.name})]}):null]},r.id))}],data:o}),d($t,{hasNextPage:t*a<e.length,hasPrevPage:t>1,limit:a,onChange:r=>n(r),page:t,totalPages:Math.ceil(e.length/a)})]})}function Ut({status:e}){switch(e){case"draft":case"save":return d(E,{pillStyle:"light-gray",children:"Draft"});case"queued":return d(E,{pillStyle:"white",children:"Queued"});case"sent":return d(E,{pillStyle:"success",children:"Sent"});default:return d(E,{children:e})}}function Jt({broadcastId:e,broadcastName:t}){let n=Le(),{t:a}=qe(),o=Ee(),{requestJson:r}=h(),i=`delete-broadcast_${e}`;async function s(){await r(`/marketing/broadcasts/${encodeURIComponent(e)}`,{method:"DELETE"}),W.success(a("general:deletedSuccessfully")),n.closeModal(i),o.refresh()}return w(Y,{children:[d(C,{slug:i,children:w(x,{children:[w(A,{children:[d(L,{children:a("general:confirmDeletion")}),d("p",{children:`Delete draft broadcast "${t}"?`})]}),w(B,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[d(N,{}),d(Ie,{buttonStyle:"error",onClick:()=>{s().catch(l=>W.error(l instanceof Error?l.message:"Delete failed"))},children:a("general:confirm")})]})]})}),d("button",{onClick:()=>n.openModal(i),type:"button",children:a("general:delete")})]})}function Gt({broadcastId:e,broadcastName:t}){let n=Le(),{t:a}=qe(),o=Ee(),{requestJson:r}=h(),i=`send-broadcast_${e}`,s=(l,u)=>{let M=u.scheduledAt,m="";typeof M=="string"?m=M:M instanceof Date&&(m=M.toISOString()),(async()=>{try{await r(`/marketing/broadcasts/${encodeURIComponent(e)}/send`,{body:JSON.stringify({...m&&m.trim()!==""?{scheduledAt:m.trim()}:{}}),method:"POST"}),n.closeModal(i),W.success(a("general:success")),o.refresh()}catch(T){W.error(T instanceof Error?T.message:"Send failed")}})()};return w(Y,{children:[d(C,{slug:i,children:d(x,{style:{width:"100%",maxWidth:"24rem"},children:w(A,{children:[d(L,{children:`Send \u201C${t}\u201D`}),w(Ht,{initialState:{},onSubmit:s,waitForAutocomplete:!0,children:[d(Vt,{field:{label:"Schedule at (optional)",name:"scheduledAt",required:!1},path:"scheduledAt"}),w(B,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[d(N,{}),d(Ie,{size:"large",type:"submit",children:"Send"})]})]})]})})}),d(E,{pillStyle:"dark",onClick:()=>n.openModal(i),size:"small",children:"Send"})]})}import zt from"react";import{Button as $e,Drawer as jt,Form as Wt,SelectField as Yt,TextareaField as Qt,TextField as Q,toast as He,useModal as _e,useTranslation as Oe}from"@payloadcms/ui";import{useRouter as Kt}from"next/navigation";import{Fragment as Zt,jsx as v,jsxs as Je}from"react/jsx-runtime";var pe="create-marketing-broadcast";function Ue({audiences:e,provider:t}){let n=_e(),{t:a}=Oe();return Je(Zt,{children:[v(Xt,{audiences:e,provider:t}),v($e,{onClick:()=>n.openModal(pe),size:"large",type:"button",children:a("general:createNew")})]})}function Xt({audiences:e,provider:t}){let n=Kt(),a=_e(),{t:o}=Oe(),{requestJson:r}=h(),[i,s]=zt.useState(!1),l=t==="mailchimp",u=(g,M)=>{let m=M,T=m.audienceId,_=m.name,V=m.subject,ge=m.htmlBody,ye=m.templateId,be=m.replyTo,he=typeof T=="string"?T:"",Pe=typeof _=="string"?_.trim():"",Me=typeof V=="string"?V.trim():"",O=typeof ge=="string"?ge.trim():"",X=typeof ye=="string"?ye.trim():"",ze=typeof be=="string"?be.trim():"";s(!0),(async()=>{try{if(!he||!Pe||!Me)throw new Error("Audience, name, and subject are required.");if(l){if(!X&&!O)throw new Error("Provide an HTML body or Mailchimp template id.");if(X&&O)throw new Error("Use either HTML body or Mailchimp template id, not both.")}else if(!O)throw new Error("HTML body is required for this provider.");await r("/marketing/broadcasts",{body:JSON.stringify({audienceId:he,html:O,name:Pe,replyTo:ze,subject:Me,templateId:X||void 0}),method:"POST"}),a.closeModal(pe),He.success(o("general:successfullyCreated",{label:"Broadcast"})),n.refresh()}catch(we){He.error(we instanceof Error?we.message:"Create failed")}finally{s(!1)}})()};return v(jt,{slug:pe,title:o("general:createNew"),children:Je(Wt,{className:"flex w-full flex-col gap-8",initialState:{},onSubmit:u,waitForAutocomplete:!0,children:[v(Yt,{field:{label:"Audience",name:"audienceId",options:e.map(g=>({label:g.name,value:g.id})),required:!0},path:"audienceId"}),v(Q,{field:{label:"Campaign name",name:"name",required:!0,type:"text"},path:"name"}),v(Q,{field:{label:"Subject",name:"subject",required:!0,type:"text"},path:"subject"}),v(Q,{field:{label:"Reply-to (optional)",name:"replyTo",type:"text"},path:"replyTo"}),l?v(Q,{field:{admin:{description:"Optional Mailchimp saved-template id (numeric string). Leave HTML empty when using templates."},label:"Template id",name:"templateId",required:!1,type:"text"},path:"templateId"}):null,v(Qt,{field:{admin:{description:l?"Optional plain HTML alternative to a Mailchimp template.":"HTML broadcast body."},label:l?"HTML body (optional with Mailchimp)":"HTML body",name:"htmlBody",required:!l},path:"htmlBody"}),v($e,{className:"w-full",disabled:i,type:"submit",children:o("general:create")})]})})}import{Fragment as ra,jsx as b,jsxs as K}from"react/jsx-runtime";function fe({initPageResult:e,params:t,searchParams:n}){return b(q,{initPageResult:e,params:t,searchParams:n,children:b(ea,{children:b(aa,{initPageResult:e})})})}function aa({initPageResult:e}){let t=I(e.req.payload);if(!t)return b("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=F(t.permissions);if(!n.broadcasts.read)return b("p",{role:"alert",children:"You do not have permission to view broadcasts."});let{adapter:a}=S(e.req.payload),o=a.urls?.broadcasts;return K(ra,{children:[K("header",{className:"flex flex-col gap-4",children:[b("h1",{children:"Campaigns"}),o?K(ta,{href:o,rel:"noreferrer noopener",target:"_blank",children:["View campaigns in ",a.label]}):null]}),K("div",{className:"mt-4 flex flex-col gap-8",children:[n.broadcasts.write?b("div",{children:b(Ge,{fallback:b("div",{"aria-busy":!0,style:{minHeight:"2.5rem"}}),children:b(na,{initPageResult:e})})}):null,b(Ge,{fallback:b("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:b(oa,{initPageResult:e})})]})]})}async function na({initPageResult:e}){let{adapter:t}=S(e.req.payload),n=await t.audiences.list();return b(Ue,{audiences:n,provider:t.provider})}async function oa({initPageResult:e}){let{adapter:t}=S(e.req.payload),a=(await t.broadcasts.list()).map(o=>({...o,externalDashboardUrl:t.urls?.broadcast?.(o.id)}));return b(Ve,{broadcasts:a})}var Fn="payload-plugin-marketing/admin";export{se as AudienceDetail,ue as AudienceList,et as AudienceSelect,at as AudienceTable,fe as BroadcastList,ot as BroadcastsTable,nt as ContactsTable,tt as MarketingMenu,Fn as defaultAdminComponentPath};
|
|
1
|
+
export*from"./constants";export*from"./server";export*from"./client";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/admin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/components/marketing-components.tsx","../../src/admin/use-marketing-api.ts","../../src/admin/paths.ts","../../src/admin/components/audience-detail.tsx","../../src/admin/components/contacts-table.tsx","../../src/admin/date-format.ts","../../src/admin/components/payload-modal.tsx","../../src/admin/components/marketing-view-shell.tsx","../../src/admin/components/view-params.ts","../../src/admin/components/audience-list.tsx","../../src/admin/components/audience-buttons.tsx","../../src/admin/components/broadcast-list.tsx","../../src/admin/components/broadcasts-table.tsx","../../src/admin/components/create-broadcast-button.tsx","../../src/admin/index.ts"],"sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { Link, NavGroup, SelectField } from \"@payloadcms/ui\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingAudience } from \"../../types\"\nimport type { TextFieldClientComponent } from \"payload\"\nimport { marketingAdminHref } from \"../paths\"\n\nfunction parseAudiences(payload: unknown): MarketingAudience[] {\n if (!Array.isArray(payload)) return []\n const out: MarketingAudience[] = []\n for (const item of payload) {\n if (!item || typeof item !== \"object\") continue\n const rec = item as Record<string, unknown>\n const id = rec.id\n const name = rec.name\n if (typeof id === \"string\" && typeof name === \"string\") {\n out.push({ id, name })\n }\n }\n return out\n}\n\nexport const AudienceSelect: TextFieldClientComponent = ({ field, path, readOnly }) => {\n const { requestJson } = useMarketingApi()\n const [audiences, setAudiences] = React.useState<MarketingAudience[]>([])\n const [loadError, setLoadError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n let cancelled = false\n void (async () => {\n try {\n const data = await requestJson(\"/marketing/audiences\")\n if (!cancelled) {\n setAudiences(parseAudiences(data))\n setLoadError(null)\n }\n } catch (err) {\n if (!cancelled) {\n setLoadError(err instanceof Error ? err.message : \"Failed to load audiences\")\n }\n }\n })()\n return () => {\n cancelled = true\n }\n }, [requestJson])\n\n return (\n <div className=\"field-type relative\">\n {loadError ? (\n <p className=\"text-red-500\" role=\"alert\">\n {loadError}\n </p>\n ) : null}\n <SelectField\n field={{\n label: typeof field.label === \"string\" ? field.label : \"Audience\",\n name: field.name,\n options: audiences.map((a) => ({ label: a.name, value: a.id })),\n required: field.required === true,\n type: \"select\",\n }}\n path={path}\n readOnly={readOnly}\n />\n </div>\n )\n}\n\nexport function MarketingMenu({ basePath = \"\" }: { basePath?: string }) {\n return (\n <NavGroup isOpen label=\"Marketing\">\n <Link className=\"nav__link\" href={marketingAdminHref(basePath, \"audience\")}>\n Audience\n </Link>\n <Link className=\"nav__link\" href={marketingAdminHref(basePath, \"broadcast\")}>\n Broadcast\n </Link>\n </NavGroup>\n )\n}\n\nexport function AudienceTable({ audiences }: { audiences: Array<{ id: string; name: string }> }) {\n return (\n <table>\n <tbody>\n {audiences.map((audience) => (\n <tr key={audience.id}>\n <td>{audience.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function ContactsTable({ contacts }: { contacts: Array<{ email: string; id: string }> }) {\n return (\n <table>\n <tbody>\n {contacts.map((contact) => (\n <tr key={contact.id}>\n <td>{contact.email}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function BroadcastsTable({\n broadcasts,\n}: {\n broadcasts: Array<{ id: string; name: string }>\n}) {\n return (\n <table>\n <tbody>\n {broadcasts.map((broadcast) => (\n <tr key={broadcast.id}>\n <td>{broadcast.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n","\"use client\"\n\nimport { useConfig } from \"@payloadcms/ui\"\nimport { useCallback, useMemo } from \"react\"\n\nexport function useMarketingApi() {\n const context = useConfig() as unknown as {\n routes?: { api?: string }\n serverURL?: string\n }\n\n const base = useMemo(() => `${context.serverURL ?? \"\"}${context.routes?.api ?? \"/api\"}`, [\n context.routes?.api,\n context.serverURL,\n ])\n\n const requestJson = useCallback(\n async (pathSegment: string, init?: RequestInit): Promise<unknown> => {\n const { headers: _headersIgnored, ...restInit } = init ?? {}\n const headers = new Headers(init?.headers)\n if (\n restInit.body !== undefined &&\n restInit.body !== \"\" &&\n restInit.body !== null\n ) {\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\")\n }\n }\n\n const res = await fetch(`${base}${pathSegment}`, {\n ...restInit,\n credentials: \"include\",\n headers,\n })\n\n if (!res.ok) {\n let detail = `${res.status} ${res.statusText}`\n try {\n const parsed = (await res.json()) as { message?: string }\n if (typeof parsed.message === \"string\") detail = parsed.message\n } catch {\n //\n }\n throw new Error(detail)\n }\n\n if (res.status === 204) {\n return undefined\n }\n\n try {\n return await res.json()\n } catch {\n return undefined\n }\n },\n [base],\n )\n\n return { base, requestJson }\n}\n","export function joinAdminSegments(adminRoute: string, ...segments: string[]): string {\n const trimmedAdmin = adminRoute.replace(/\\/+$/, \"\") || \"\"\n const body = segments\n .flatMap((s) => String(s).split(\"/\"))\n .map((segment) => segment.replace(/^\\/+|\\/+$/g, \"\"))\n .filter(Boolean)\n .join(\"/\")\n const combined = trimmedAdmin === \"\" ? `/${body}` : `${trimmedAdmin}/${body}`\n return combined.replace(/\\/{2,}/g, \"/\")\n}\n\n/** Absolute admin hrefs for marketing custom views (`/admin`, optional plugin `basePath`, then path segments). */\nexport function marketingAdminHref(basePath: string | undefined, ...segments: string[]): string {\n const normalized = basePath?.replace(/^\\/+|\\/+$/g, \"\") ?? \"\"\n const parts = [normalized, ...segments].filter(Boolean)\n return joinAdminSegments(\"/admin\", ...parts)\n}\n","import { Suspense } from \"react\"\nimport { notFound } from \"next/navigation\"\nimport { Gutter, Link } from \"@payloadcms/ui\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { ContactsTable, EditContactButton } from \"./contacts-table\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\nimport { marketingAudienceIdFromParams } from \"./view-params\"\n\nimport type { AdminViewServerProps } from \"payload\"\n\nexport type AudienceDetailViewProps = AdminViewServerProps & {\n basePath?: string\n}\n\nexport default function AudienceDetail({\n initPageResult,\n params,\n searchParams,\n}: AudienceDetailViewProps) {\n const audienceId = marketingAudienceIdFromParams(params)\n\n if (!audienceId) {\n throw new Error(\"No audience id in route params\")\n }\n\n return (\n <MarketingViewShell initPageResult={initPageResult} params={params} searchParams={searchParams}>\n <Gutter>\n <AudienceDetailBody audienceId={audienceId} initPageResult={initPageResult} />\n </Gutter>\n </MarketingViewShell>\n )\n}\n\nasync function AudienceDetailBody({\n audienceId,\n initPageResult,\n}: {\n audienceId: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const integration = tryGetMarketingIntegration(initPageResult.req.payload)\n if (!integration) {\n return (\n <p role=\"alert\">\n Marketing plugin is not configured (missing adapter on Payload config).\n </p>\n )\n }\n\n const effective = resolveMarketingPermissions(integration.permissions)\n if (!effective.audiences.read) {\n return <p role=\"alert\">You do not have permission to view this audience.</p>\n }\n\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const audience = await adapter.audiences.get(audienceId)\n if (!audience) {\n notFound()\n }\n\n const audienceDashboardUrl = adapter.urls?.audience?.(audienceId)\n\n return (\n <>\n <header className=\"flex flex-col gap-4\">\n <h1>{audience.name}</h1>\n {audienceDashboardUrl ? (\n <Link href={audienceDashboardUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n Open this audience in {adapter.label}\n </Link>\n ) : null}\n </header>\n\n <div className=\"mt-12 flex flex-col gap-6\">\n {effective.contacts.write ? (\n <div>\n <EditContactButton audienceId={audienceId} contact={null} />\n </div>\n ) : null}\n {effective.contacts.read ? (\n <Suspense fallback={<div aria-busy style={{ minHeight: \"12rem\" }} />}>\n <DetailContacts audienceId={audienceId} initPageResult={initPageResult} />\n </Suspense>\n ) : (\n <p role=\"alert\">You do not have permission to list contacts.</p>\n )}\n </div>\n </>\n )\n}\n\nasync function DetailContacts({\n audienceId,\n initPageResult,\n}: {\n audienceId: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const contacts = await adapter.contacts.list({ audienceId })\n return <ContactsTable audienceId={audienceId} contacts={contacts} />\n}\n","\"use client\"\n\nimport React from \"react\"\nimport {\n CheckboxField,\n Form,\n Pagination,\n Table,\n TextField,\n toast,\n useModal,\n useTranslation,\n Button as PayloadButton,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\nimport ReactRaw from \"react\"\nimport { useTransition } from \"react\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n} from \"./payload-modal\"\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingContact } from \"../../types\"\n\nimport type { Data, FormState } from \"payload\"\n\ninterface ContactsTableProps {\n audienceId: string\n contacts: MarketingContact[]\n}\n\nexport function ContactsTable({ audienceId, contacts }: ContactsTableProps) {\n const [page, setPage] = React.useState(1)\n const [limit] = React.useState(100)\n const currentPage = React.useMemo(\n () => contacts.slice((page - 1) * limit, page * limit),\n [contacts, limit, page],\n )\n\n return (\n <>\n <Table\n columns={[\n {\n Heading: \"First name\",\n accessor: \"firstName\",\n active: true,\n field: { name: \"firstName\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{contact.firstName ?? \"—\"}</div>\n )),\n },\n {\n Heading: \"Last name\",\n accessor: \"lastName\",\n active: true,\n field: { name: \"lastName\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{contact.lastName ?? \"—\"}</div>\n )),\n },\n {\n Heading: \"Email\",\n accessor: \"email\",\n active: true,\n field: { name: \"email\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{contact.email}</div>\n )),\n },\n {\n Heading: \"Created\",\n accessor: \"createdAt\",\n active: true,\n field: { name: \"createdAt\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id}>{formatMarketingDate(contact.createdAt)}</div>\n )),\n },\n {\n Heading: \"Status\",\n accessor: \"subscribed\",\n active: true,\n field: { name: \"subscribed\", type: \"text\" },\n renderedCells: currentPage.map((contact) => (\n <div key={contact.id} className=\"flex items-center gap-4 flex-wrap\">\n <span>{contact.subscribed !== false ? \"✅ subscribed\" : \"❌ unsubscribed\"}</span>\n <EditContactButton audienceId={audienceId} contact={contact} />\n <DeleteContactButton\n audienceId={audienceId}\n contactEmail={contact.email}\n contactId={contact.id}\n />\n </div>\n )),\n },\n ]}\n data={currentPage as unknown as Record<string, unknown>[]}\n />\n <Pagination\n hasNextPage={page * limit < contacts.length}\n hasPrevPage={page > 1}\n limit={limit}\n onChange={(p) => {\n setPage(p)\n }}\n page={page}\n totalPages={Math.ceil(contacts.length / limit)}\n />\n </>\n )\n}\n\nfunction DeleteContactButton({\n audienceId,\n contactId,\n contactEmail,\n}: {\n audienceId: string\n contactEmail: string\n contactId: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `delete-contact_${contactId}`\n\n async function confirmDelete(): Promise<void> {\n await requestJson(`/marketing/audiences/${encodeURIComponent(audienceId)}/contacts/${encodeURIComponent(contactId)}`, {\n method: \"DELETE\",\n })\n toast.success(t(\"general:deletedSuccessfully\"))\n modal.closeModal(modalSlug)\n router.refresh()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent>\n <PayloadModalBody>\n <h1>{t(\"general:confirmDeletion\")}</h1>\n <p>{`Remove contact ${contactEmail}?`}</p>\n </PayloadModalBody>\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton\n buttonStyle=\"error\"\n onClick={() => {\n void confirmDelete().catch((err: unknown) =>\n toast.error(err instanceof Error ? err.message : \"Delete failed\"),\n )\n }}\n >\n {t(\"general:confirm\")}\n </PayloadButton>\n </PayloadModalFooter>\n </PayloadModalContent>\n </PayloadModal>\n <button onClick={() => modal.openModal(modalSlug)} type=\"button\">\n {t(\"general:delete\")}\n </button>\n </>\n )\n}\n\nexport function EditContactButton({\n audienceId,\n contact,\n}: {\n audienceId: string\n contact: MarketingContact | null\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const id = ReactRaw.useId()\n const slug = contact ? `edit-contact_${contact.id}` : `create-contact_${audienceId}_${id}`\n\n const ButtonComp = contact ? \"button\" : PayloadButton\n\n return (\n <>\n <EditContactModalWrapper audienceId={audienceId} contact={contact} modalSlug={slug} />\n <ButtonComp {...(contact ? {} : { size: \"large\" })} onClick={() => modal.openModal(slug)} type=\"button\">\n {contact ? t(\"general:edit\") : t(\"general:createNew\")}\n </ButtonComp>\n </>\n )\n}\n\nfunction EditContactModalWrapper({\n audienceId,\n contact,\n modalSlug,\n}: {\n audienceId: string\n contact: MarketingContact | null\n modalSlug: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const [, startTransition] = useTransition()\n\n const submit = (fields: FormState, data: Data) => {\n const email = data.email as string\n const firstName = String(data.firstName ?? \"\")\n const lastName = String(data.lastName ?? \"\")\n const subscribed = Boolean(data.subscribed)\n\n startTransition(() => {\n void (async () => {\n try {\n await requestJson(\"/marketing/contacts\", {\n body: JSON.stringify({\n audienceId,\n email,\n firstName,\n id: contact?.id,\n lastName,\n subscribed,\n }),\n method: \"POST\",\n })\n toast.success(contact ? \"Contact updated.\" : \"Contact created.\")\n modal.closeModal(modalSlug)\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Save failed\")\n }\n })()\n })\n }\n\n return (\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent style={{ width: \"100%\", maxWidth: \"32rem\" }}>\n <PayloadModalBody>\n <h1>{contact ? t(\"general:edit\") : t(\"general:createNew\")}</h1>\n <Form\n className=\"flex w-full flex-col gap-6\"\n initialState={{\n email: {\n value: contact?.email ?? \"\",\n },\n firstName: {\n value: contact?.firstName ?? \"\",\n },\n lastName: {\n value: contact?.lastName ?? \"\",\n },\n subscribed: {\n value: contact?.subscribed !== false,\n },\n }}\n onSubmit={submit}\n waitForAutocomplete\n >\n <TextField\n field={{\n label: t(\"general:email\"),\n name: \"email\",\n required: true,\n type: \"text\",\n }}\n path=\"email\"\n validate={(v) => (typeof v === \"string\" && v.includes(\"@\") ? true : \"Valid email required\")}\n />\n <TextField\n field={{\n label: \"First name\",\n name: \"firstName\",\n type: \"text\",\n }}\n path=\"firstName\"\n />\n <TextField\n field={{\n label: \"Last name\",\n name: \"lastName\",\n type: \"text\",\n }}\n path=\"lastName\"\n />\n <CheckboxField\n field={{\n label: \"Subscribed\",\n name: \"subscribed\",\n }}\n path=\"subscribed\"\n />\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton size=\"large\" type=\"submit\">\n {contact ? t(\"general:save\") : t(\"general:create\")}\n </PayloadButton>\n </PayloadModalFooter>\n </Form>\n </PayloadModalBody>\n </PayloadModalContent>\n </PayloadModal>\n )\n}\n","export function formatMarketingDate(iso?: string | null): string {\n if (!iso) return \"—\"\n const d = new Date(iso)\n return Number.isNaN(d.valueOf())\n ? String(iso)\n : new Intl.DateTimeFormat(undefined, { dateStyle: \"medium\" }).format(d)\n}\n","\"use client\"\n\nimport React from \"react\"\nimport { Button, Modal, useModal, useTranslation } from \"@payloadcms/ui\"\n\nconst PayloadModalContext = React.createContext({ modalSlug: \"\" })\n\ninterface PayloadModalProps extends React.ComponentProps<typeof Modal> {\n children: React.ReactNode\n}\n\nfunction PayloadModal({ children, className: _className, slug: modalSlug, ...props }: PayloadModalProps) {\n const [loaded, setLoaded] = React.useState(false)\n\n React.useEffect(() => {\n setLoaded(true)\n }, [])\n\n return (\n <PayloadModalContext.Provider value={{ modalSlug }}>\n {loaded && (\n <Modal slug={modalSlug} {...props}>\n {children}\n </Modal>\n )}\n </PayloadModalContext.Provider>\n )\n}\n\nfunction PayloadModalContent({ children, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"payload-modal-content\" {...props}>\n {children}\n </div>\n )\n}\n\nfunction PayloadModalBody({ children, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"payload-modal-body\" {...props}>\n {children}\n </div>\n )\n}\n\nfunction PayloadModalTitle({ children, ...props }: React.ComponentProps<\"h1\">) {\n return (\n <h1 data-slot=\"payload-modal-title\" {...props}>\n {children}\n </h1>\n )\n}\n\nfunction PayloadModalFooter({ children, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div data-slot=\"payload-modal-footer\" {...props}>\n {children}\n </div>\n )\n}\n\nfunction PayloadModalClose({ children, className: _className, ...props }: React.ComponentProps<typeof Button>) {\n const { t } = useTranslation()\n const { modalSlug } = React.useContext(PayloadModalContext)\n const modal = useModal()\n\n return (\n <Button\n buttonStyle=\"secondary\"\n data-slot=\"payload-modal-close\"\n size=\"large\"\n {...props}\n onClick={(e) => {\n modal.closeModal(modalSlug)\n props.onClick?.(e)\n }}\n >\n {children ?? t(\"general:cancel\")}\n </Button>\n )\n}\n\nexport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n}\n","import { DefaultTemplate } from \"@payloadcms/next/templates\"\nimport type { AdminViewServerProps } from \"payload\"\nimport type { ReactNode } from \"react\"\n\ntype ShellProps = Pick<AdminViewServerProps, \"initPageResult\" | \"params\" | \"searchParams\"> & {\n children: ReactNode\n}\n\nexport function MarketingViewShell({ children, initPageResult, params, searchParams }: ShellProps) {\n return (\n <DefaultTemplate\n i18n={initPageResult.req.i18n}\n locale={initPageResult.locale}\n params={params}\n payload={initPageResult.req.payload}\n permissions={initPageResult.permissions}\n searchParams={searchParams}\n user={initPageResult.req.user ?? undefined}\n visibleEntities={initPageResult.visibleEntities}\n >\n {children}\n </DefaultTemplate>\n )\n}\n","import type { AdminViewServerProps } from \"payload\"\n\nfunction firstString(value: string | string[] | undefined): string | undefined {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim()\n }\n if (Array.isArray(value) && typeof value[0] === \"string\" && value[0].trim()) {\n return value[0].trim()\n }\n return undefined\n}\n\n/** Resolve audience id from custom admin view params (`:id` or URL segments). */\nexport function marketingAudienceIdFromParams(\n params: AdminViewServerProps[\"params\"] | undefined,\n): string | undefined {\n if (!params) {\n return undefined\n }\n\n const fromId = firstString(params.id)\n if (fromId) {\n return fromId\n }\n\n const segmentsRaw = params.segments\n const segmentList: string[] = Array.isArray(segmentsRaw)\n ? segmentsRaw.filter((s): s is string => typeof s === \"string\" && s.length > 0)\n : typeof segmentsRaw === \"string\"\n ? segmentsRaw.split(\"/\").filter(Boolean)\n : []\n\n if (segmentList.length === 0) {\n return undefined\n }\n\n const audienceIdx = segmentList.lastIndexOf(\"audience\")\n if (audienceIdx >= 0 && segmentList[audienceIdx + 1]) {\n return segmentList[audienceIdx + 1]\n }\n\n const last = segmentList[segmentList.length - 1]\n if (last === \"audience\") {\n return undefined\n }\n return last\n}\n","import { Suspense } from \"react\"\nimport { Gutter, Link, Table } from \"@payloadcms/ui\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { marketingAdminHref } from \"../paths\"\nimport { CreateAudienceButton, DeleteAudienceButton } from \"./audience-buttons\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\n\nexport type AudienceListViewProps = AdminViewServerProps & {\n basePath?: string\n}\n\nexport default function AudienceList({\n basePath = \"\",\n initPageResult,\n params,\n searchParams,\n}: AudienceListViewProps) {\n return (\n <MarketingViewShell initPageResult={initPageResult} params={params} searchParams={searchParams}>\n <Gutter>\n <AudienceListBody basePath={basePath} initPageResult={initPageResult} />\n </Gutter>\n </MarketingViewShell>\n )\n}\n\nfunction AudienceListBody({\n basePath,\n initPageResult,\n}: {\n basePath: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const integration = tryGetMarketingIntegration(initPageResult.req.payload)\n if (!integration) {\n return (\n <p role=\"alert\">\n Marketing plugin is not configured (missing adapter on Payload config).\n </p>\n )\n }\n\n const effective = resolveMarketingPermissions(integration.permissions)\n if (!effective.audiences.read) {\n return <p role=\"alert\">You do not have permission to view audiences.</p>\n }\n\n const audiencesUrl = integration.adapter.urls?.audiences\n\n return (\n <>\n <header className=\"flex flex-col gap-4\">\n <h1>Audiences</h1>\n {audiencesUrl ? (\n <Link href={audiencesUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n View audiences in {integration.adapter.label}\n </Link>\n ) : null}\n </header>\n\n <div className=\"mt-4 flex flex-col gap-8\">\n {effective.audiences.write ? (\n <div>\n <CreateAudienceButton />\n </div>\n ) : null}\n <Suspense fallback={<div aria-busy style={{ minHeight: \"4rem\" }} />}>\n <AudienceTableRows\n audiencesWrite={effective.audiences.write}\n basePath={basePath}\n initPageResult={initPageResult}\n />\n </Suspense>\n </div>\n </>\n )\n}\n\nasync function AudienceTableRows({\n audiencesWrite,\n basePath,\n initPageResult,\n}: {\n audiencesWrite: boolean\n basePath: string\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const audiences = await adapter.audiences.list()\n\n const nameColumn = {\n Heading: \"Name\",\n accessor: \"name\",\n active: true,\n field: { name: \"name\", type: \"text\" as const },\n renderedCells: audiences.map((audience) => (\n <div key={audience.id}>\n <Link href={marketingAdminHref(basePath, \"audience\", audience.id)}>{audience.name}</Link>\n </div>\n )),\n }\n\n const deleteColumn = {\n Heading: \"\",\n accessor: \"\",\n active: true,\n field: { name: \"_delete\", type: \"text\" as const },\n renderedCells: audiences.map((audience) => (\n <div key={audience.id}>\n <DeleteAudienceButton audienceId={audience.id} audienceName={audience.name} />\n </div>\n )),\n }\n\n return (\n <Table\n columns={audiencesWrite ? [nameColumn, deleteColumn] : [nameColumn]}\n data={audiences as unknown as Record<string, unknown>[]}\n />\n )\n}\n","\"use client\"\n\nimport { useTransition } from \"react\"\nimport {\n Button,\n Form,\n TextField,\n toast,\n useModal,\n useTranslation,\n Button as PayloadButton,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\n\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { Data, FormState } from \"payload\"\n\nconst createAudienceSlug = \"create-audience\"\n\nexport function CreateAudienceButton() {\n const modal = useModal()\n const { t } = useTranslation()\n\n return (\n <>\n <CreateAudienceModal />\n <Button onClick={() => modal.openModal(createAudienceSlug)} size=\"large\" type=\"button\">\n {t(\"general:createNew\")}\n </Button>\n </>\n )\n}\n\nfunction CreateAudienceModal() {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const [isPending, startTransition] = useTransition()\n\n const submit = (fields: FormState, data: Data) => {\n const row = data as Record<string, unknown>\n const nameRaw: unknown = row.audienceName\n const name = typeof nameRaw === \"string\" ? nameRaw.trim() : \"\"\n startTransition(() => {\n void (async () => {\n try {\n if (!name) {\n throw new Error(\"Name is required.\")\n }\n await requestJson(\"/marketing/audiences\", {\n body: JSON.stringify({ name }),\n method: \"POST\",\n })\n modal.closeModal(createAudienceSlug)\n toast.success(t(\"general:successfullyCreated\"))\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Create failed\")\n }\n })()\n })\n }\n\n return (\n <PayloadModal closeOnBlur slug={createAudienceSlug}>\n <PayloadModalContent style={{ width: \"100%\", maxWidth: \"24rem\" }}>\n <Form initialState={{}} onSubmit={submit} waitForAutocomplete>\n <PayloadModalBody>\n <PayloadModalTitle>{t(\"general:createNew\")}</PayloadModalTitle>\n <TextField\n field={{\n name: \"audienceName\",\n required: true,\n type: \"text\",\n }}\n path=\"audienceName\"\n validate={(v) => (typeof v === \"string\" && v.trim().length > 0 ? true : \"Name is required\")}\n />\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <Button disabled={isPending} size=\"large\" type=\"submit\">\n {t(\"general:confirm\")}\n </Button>\n </PayloadModalFooter>\n </PayloadModalBody>\n </Form>\n </PayloadModalContent>\n </PayloadModal>\n )\n}\n\nexport function DeleteAudienceButton({\n audienceId,\n audienceName,\n}: {\n audienceId: string\n audienceName: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `delete-audience_${audienceId}`\n\n async function confirmDelete(): Promise<void> {\n await requestJson(`/marketing/audiences/${encodeURIComponent(audienceId)}`, {\n method: \"DELETE\",\n })\n toast.success(t(\"general:deletedSuccessfully\"))\n modal.closeModal(modalSlug)\n router.refresh()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent>\n <PayloadModalBody>\n <PayloadModalTitle>{t(\"general:confirmDeletion\")}</PayloadModalTitle>\n <p>{`Remove audience \"${audienceName}\"?`}</p>\n </PayloadModalBody>\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton\n buttonStyle=\"error\"\n onClick={() => {\n void confirmDelete().catch((err: unknown) =>\n toast.error(err instanceof Error ? err.message : \"Delete failed\"),\n )\n }}\n >\n {t(\"general:confirm\")}\n </PayloadButton>\n </PayloadModalFooter>\n </PayloadModalContent>\n </PayloadModal>\n <button onClick={() => modal.openModal(modalSlug)} type=\"button\">\n {t(\"general:delete\")}\n </button>\n </>\n )\n}\n","import { Suspense } from \"react\"\nimport { Gutter, Link } from \"@payloadcms/ui\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { BroadcastsTable } from \"./broadcasts-table\"\nimport { CreateBroadcastButton } from \"./create-broadcast-button\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\nimport type { MarketingBroadcastRow } from \"./broadcasts-table\"\n\nexport type BroadcastListViewProps = AdminViewServerProps & {\n basePath?: string\n}\n\nexport default function BroadcastList({\n initPageResult,\n params,\n searchParams,\n}: BroadcastListViewProps) {\n return (\n <MarketingViewShell initPageResult={initPageResult} params={params} searchParams={searchParams}>\n <Gutter>\n <BroadcastListBody initPageResult={initPageResult} />\n </Gutter>\n </MarketingViewShell>\n )\n}\n\nfunction BroadcastListBody({\n initPageResult,\n}: {\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const integration = tryGetMarketingIntegration(initPageResult.req.payload)\n if (!integration) {\n return (\n <p role=\"alert\">\n Marketing plugin is not configured (missing adapter on Payload config).\n </p>\n )\n }\n\n const effective = resolveMarketingPermissions(integration.permissions)\n if (!effective.broadcasts.read) {\n return <p role=\"alert\">You do not have permission to view broadcasts.</p>\n }\n\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const broadcastsUrl = adapter.urls?.broadcasts\n\n return (\n <>\n <header className=\"flex flex-col gap-4\">\n <h1>Campaigns</h1>\n {broadcastsUrl ? (\n <Link href={broadcastsUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n View campaigns in {adapter.label}\n </Link>\n ) : null}\n </header>\n\n <div className=\"mt-4 flex flex-col gap-8\">\n {effective.broadcasts.write ? (\n <div>\n <Suspense fallback={<div aria-busy style={{ minHeight: \"2.5rem\" }} />}>\n <CreateBroadcastRegion initPageResult={initPageResult} />\n </Suspense>\n </div>\n ) : null}\n <Suspense fallback={<div aria-busy style={{ minHeight: \"4rem\" }} />}>\n <BroadcastTableRegion initPageResult={initPageResult} />\n </Suspense>\n </div>\n </>\n )\n}\n\nasync function CreateBroadcastRegion({\n initPageResult,\n}: {\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const audiences = await adapter.audiences.list()\n return <CreateBroadcastButton audiences={audiences} provider={adapter.provider} />\n}\n\nasync function BroadcastTableRegion({\n initPageResult,\n}: {\n initPageResult: AdminViewServerProps[\"initPageResult\"]\n}) {\n const { adapter } = getMarketingIntegration(initPageResult.req.payload)\n const rows = await adapter.broadcasts.list()\n const broadcasts: MarketingBroadcastRow[] = rows.map((b) => ({\n ...b,\n externalDashboardUrl: adapter.urls?.broadcast?.(b.id),\n }))\n\n return <BroadcastsTable broadcasts={broadcasts} />\n}\n","\"use client\"\n\nimport React from \"react\"\nimport {\n Button as PayloadButton,\n DateTimeField,\n Form,\n Pagination,\n Pill,\n Table,\n toast,\n useModal,\n useTranslation,\n} from \"@payloadcms/ui\"\nimport Link from \"next/link\"\nimport { useRouter } from \"next/navigation\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingBroadcast } from \"../../types\"\nimport type { Data, FormState } from \"payload\"\n\nexport interface MarketingBroadcastRow extends MarketingBroadcast {\n externalDashboardUrl?: string\n}\n\ninterface BroadcastsTableProps {\n broadcasts: MarketingBroadcastRow[]\n}\n\nexport function BroadcastsTable({ broadcasts }: BroadcastsTableProps) {\n const [page, setPage] = React.useState(1)\n const [limit] = React.useState(100)\n const currentPage = React.useMemo(\n () => broadcasts.slice((page - 1) * limit, page * limit),\n [broadcasts, limit, page],\n )\n\n return (\n <>\n <Table\n columns={[\n {\n Heading: \"Campaign name\",\n accessor: \"name\",\n active: true,\n field: { name: \"name\", type: \"text\" },\n renderedCells: currentPage.map((b) => <div key={b.id}>{b.name}</div>),\n },\n {\n Heading: \"Schedule date\",\n accessor: \"scheduledAt\",\n active: true,\n field: { name: \"scheduledAt\", type: \"text\" },\n renderedCells: currentPage.map((b) => (\n <div key={b.id}>{formatMarketingDate(b.scheduledAt)}</div>\n )),\n },\n {\n Heading: \"Sent date\",\n accessor: \"sentAt\",\n active: true,\n field: { name: \"sentAt\", type: \"text\" },\n renderedCells: currentPage.map((b) => <div key={b.id}>{formatMarketingDate(b.sentAt)}</div>),\n },\n {\n Heading: \"Status\",\n accessor: \"status\",\n active: true,\n field: { name: \"status\", type: \"text\" },\n renderedCells: currentPage.map((broadcast) => (\n <div key={broadcast.id}>\n <BroadcastStatusPill status={broadcast.status} />\n </div>\n )),\n },\n {\n Heading: \"\",\n accessor: \"\",\n active: true,\n field: { name: \"_\", type: \"text\" },\n renderedCells: currentPage.map((broadcast) => (\n <div key={broadcast.id} className=\"flex items-center gap-4 flex-wrap\">\n {broadcast.externalDashboardUrl ? (\n <Link href={broadcast.externalDashboardUrl} rel=\"noreferrer noopener\" target=\"_blank\">\n <Pill>dashboard ↗</Pill>\n </Link>\n ) : null}\n {broadcast.status === \"draft\" || broadcast.status === \"save\" ? (\n <>\n <DeleteBroadcastButton broadcastId={broadcast.id} broadcastName={broadcast.name} />\n <SendBroadcastButton broadcastId={broadcast.id} broadcastName={broadcast.name} />\n </>\n ) : null}\n </div>\n )),\n },\n ]}\n data={currentPage as unknown as Record<string, unknown>[]}\n />\n <Pagination\n hasNextPage={page * limit < broadcasts.length}\n hasPrevPage={page > 1}\n limit={limit}\n onChange={(p) => setPage(p)}\n page={page}\n totalPages={Math.ceil(broadcasts.length / limit)}\n />\n </>\n )\n}\n\nfunction BroadcastStatusPill({ status }: { status: string }) {\n switch (status) {\n case \"draft\":\n case \"save\": {\n return <Pill pillStyle=\"light-gray\">Draft</Pill>\n }\n case \"queued\": {\n return <Pill pillStyle=\"white\">Queued</Pill>\n }\n case \"sent\": {\n return <Pill pillStyle=\"success\">Sent</Pill>\n }\n default: {\n return <Pill>{status}</Pill>\n }\n }\n}\n\nfunction DeleteBroadcastButton({\n broadcastId,\n broadcastName,\n}: {\n broadcastId: string\n broadcastName: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `delete-broadcast_${broadcastId}`\n\n async function confirmDelete(): Promise<void> {\n await requestJson(`/marketing/broadcasts/${encodeURIComponent(broadcastId)}`, { method: \"DELETE\" })\n toast.success(t(\"general:deletedSuccessfully\"))\n modal.closeModal(modalSlug)\n router.refresh()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent>\n <PayloadModalBody>\n <PayloadModalTitle>{t(\"general:confirmDeletion\")}</PayloadModalTitle>\n <p>{`Delete draft broadcast \"${broadcastName}\"?`}</p>\n </PayloadModalBody>\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton\n buttonStyle=\"error\"\n onClick={() => {\n void confirmDelete().catch((err: unknown) =>\n toast.error(err instanceof Error ? err.message : \"Delete failed\"),\n )\n }}\n >\n {t(\"general:confirm\")}\n </PayloadButton>\n </PayloadModalFooter>\n </PayloadModalContent>\n </PayloadModal>\n <button onClick={() => modal.openModal(modalSlug)} type=\"button\">\n {t(\"general:delete\")}\n </button>\n </>\n )\n}\n\nexport function SendBroadcastButton({\n broadcastId,\n broadcastName,\n}: {\n broadcastId: string\n broadcastName: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n const router = useRouter()\n const { requestJson } = useMarketingApi()\n const modalSlug = `send-broadcast_${broadcastId}`\n\n const submit = (fields: FormState, data: Data) => {\n const row = data as Record<string, unknown>\n const scheduledRaw: unknown = row.scheduledAt\n let scheduledAt = \"\"\n if (typeof scheduledRaw === \"string\") {\n scheduledAt = scheduledRaw\n } else if (scheduledRaw instanceof Date) {\n scheduledAt = scheduledRaw.toISOString()\n }\n\n void (async () => {\n try {\n await requestJson(`/marketing/broadcasts/${encodeURIComponent(broadcastId)}/send`, {\n body: JSON.stringify({\n ...(scheduledAt && scheduledAt.trim() !== \"\"\n ? { scheduledAt: scheduledAt.trim() }\n : {}),\n }),\n method: \"POST\",\n })\n modal.closeModal(modalSlug)\n toast.success(t(\"general:success\"))\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Send failed\")\n }\n })()\n }\n\n return (\n <>\n <PayloadModal slug={modalSlug}>\n <PayloadModalContent style={{ width: \"100%\", maxWidth: \"24rem\" }}>\n <PayloadModalBody>\n <PayloadModalTitle>{`Send “${broadcastName}”`}</PayloadModalTitle>\n <Form initialState={{}} onSubmit={submit} waitForAutocomplete>\n <DateTimeField\n field={{\n label: \"Schedule at (optional)\",\n name: \"scheduledAt\",\n required: false,\n }}\n path=\"scheduledAt\"\n />\n <PayloadModalFooter style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}>\n <PayloadModalClose />\n <PayloadButton size=\"large\" type=\"submit\">\n Send\n </PayloadButton>\n </PayloadModalFooter>\n </Form>\n </PayloadModalBody>\n </PayloadModalContent>\n </PayloadModal>\n <Pill pillStyle=\"dark\" onClick={() => modal.openModal(modalSlug)} size=\"small\">\n Send\n </Pill>\n </>\n )\n}\n","\"use client\"\n\nimport React from \"react\"\nimport {\n Button,\n Drawer,\n Form,\n SelectField,\n TextareaField,\n TextField,\n toast,\n useModal,\n useTranslation,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingAudience } from \"../../types\"\n\nimport type { Data, FormState } from \"payload\"\n\nconst modalSlug = \"create-marketing-broadcast\"\n\nexport function CreateBroadcastButton({\n audiences,\n provider,\n}: {\n audiences: MarketingAudience[]\n provider: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n\n return (\n <>\n <CreateBroadcastModal audiences={audiences} provider={provider} />\n <Button onClick={() => modal.openModal(modalSlug)} size=\"large\" type=\"button\">\n {t(\"general:createNew\")}\n </Button>\n </>\n )\n}\n\nfunction CreateBroadcastModal({\n audiences,\n provider,\n}: {\n audiences: MarketingAudience[]\n provider: string\n}) {\n const router = useRouter()\n const modal = useModal()\n const { t } = useTranslation()\n const { requestJson } = useMarketingApi()\n const [isPending, setIsPending] = React.useState(false)\n\n const showTemplateField = provider === \"mailchimp\"\n\n const submit = (fields: FormState, data: Data) => {\n const row = data as Record<string, unknown>\n const audienceIdRaw: unknown = row.audienceId\n const nameRaw: unknown = row.name\n const subjectRaw: unknown = row.subject\n const htmlRaw: unknown = row.htmlBody\n const templateIdRaw: unknown = row.templateId\n const replyToRaw: unknown = row.replyTo\n\n const audienceId = typeof audienceIdRaw === \"string\" ? audienceIdRaw : \"\"\n const name = typeof nameRaw === \"string\" ? nameRaw.trim() : \"\"\n const subject = typeof subjectRaw === \"string\" ? subjectRaw.trim() : \"\"\n const htmlBody = typeof htmlRaw === \"string\" ? htmlRaw.trim() : \"\"\n const templateId = typeof templateIdRaw === \"string\" ? templateIdRaw.trim() : \"\"\n const replyTo = typeof replyToRaw === \"string\" ? replyToRaw.trim() : \"\"\n\n setIsPending(true)\n void (async () => {\n try {\n if (!audienceId || !name || !subject) {\n throw new Error(\"Audience, name, and subject are required.\")\n }\n if (showTemplateField) {\n if (!templateId && !htmlBody) {\n throw new Error(\"Provide an HTML body or Mailchimp template id.\")\n }\n if (templateId && htmlBody) {\n throw new Error(\"Use either HTML body or Mailchimp template id, not both.\")\n }\n } else if (!htmlBody) {\n throw new Error(\"HTML body is required for this provider.\")\n }\n\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n html: htmlBody,\n name,\n replyTo,\n subject,\n templateId: templateId || undefined,\n }),\n method: \"POST\",\n })\n\n modal.closeModal(modalSlug)\n toast.success(t(\"general:successfullyCreated\", { label: \"Broadcast\" }))\n router.refresh()\n } catch (err) {\n toast.error(err instanceof Error ? err.message : \"Create failed\")\n } finally {\n setIsPending(false)\n }\n })()\n }\n\n return (\n <Drawer slug={modalSlug} title={t(\"general:createNew\")}>\n <Form\n className=\"flex w-full flex-col gap-8\"\n initialState={{}}\n onSubmit={submit}\n waitForAutocomplete\n >\n <SelectField\n field={{\n label: \"Audience\",\n name: \"audienceId\",\n options: audiences.map((a) => ({ label: a.name, value: a.id })),\n required: true,\n }}\n path=\"audienceId\"\n />\n <TextField\n field={{\n label: \"Campaign name\",\n name: \"name\",\n required: true,\n type: \"text\",\n }}\n path=\"name\"\n />\n <TextField\n field={{\n label: \"Subject\",\n name: \"subject\",\n required: true,\n type: \"text\",\n }}\n path=\"subject\"\n />\n <TextField\n field={{\n label: \"Reply-to (optional)\",\n name: \"replyTo\",\n type: \"text\",\n }}\n path=\"replyTo\"\n />\n\n {showTemplateField ? (\n <TextField\n field={{\n admin: {\n description:\n \"Optional Mailchimp saved-template id (numeric string). Leave HTML empty when using templates.\",\n },\n label: \"Template id\",\n name: \"templateId\",\n required: false,\n type: \"text\",\n }}\n path=\"templateId\"\n />\n ) : null}\n\n <TextareaField\n field={{\n admin: {\n description: showTemplateField\n ? \"Optional plain HTML alternative to a Mailchimp template.\"\n : \"HTML broadcast body.\",\n },\n label: showTemplateField ? \"HTML body (optional with Mailchimp)\" : \"HTML body\",\n name: \"htmlBody\",\n required: !showTemplateField,\n }}\n path=\"htmlBody\"\n />\n\n <Button className=\"w-full\" disabled={isPending} type=\"submit\">\n {t(\"general:create\")}\n </Button>\n </Form>\n </Drawer>\n )\n}\n","export const defaultAdminComponentPath = \"payload-plugin-marketing/admin\"\n\nexport {\n AudienceSelect,\n AudienceTable,\n BroadcastsTable,\n ContactsTable,\n MarketingMenu,\n} from \"./components/marketing-components\"\nexport { AudienceDetail, AudienceList, BroadcastList } from \"./components/views\"\n"],"mappings":"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","names":["React","Link","NavGroup","SelectField","useConfig","useCallback","useMemo","useMarketingApi","context","base","requestJson","pathSegment","init","_headersIgnored","restInit","headers","res","detail","parsed","joinAdminSegments","adminRoute","segments","trimmedAdmin","body","s","segment","marketingAdminHref","basePath","parts","jsx","jsxs","parseAudiences","payload","out","item","rec","id","name","AudienceSelect","field","path","readOnly","requestJson","useMarketingApi","audiences","setAudiences","React","loadError","setLoadError","cancelled","data","err","SelectField","a","MarketingMenu","basePath","NavGroup","Link","marketingAdminHref","AudienceTable","audience","ContactsTable","contacts","contact","BroadcastsTable","broadcasts","broadcast","Suspense","notFound","Gutter","Link","React","CheckboxField","Form","Pagination","Table","TextField","toast","useModal","useTranslation","PayloadButton","useRouter","ReactRaw","useTransition","formatMarketingDate","iso","d","React","Button","Modal","useModal","useTranslation","jsx","PayloadModalContext","PayloadModal","children","_className","modalSlug","props","loaded","setLoaded","PayloadModalContent","PayloadModalBody","PayloadModalTitle","PayloadModalFooter","PayloadModalClose","t","modal","e","Fragment","jsx","jsxs","ContactsTable","audienceId","contacts","page","setPage","React","limit","currentPage","Table","contact","formatMarketingDate","EditContactButton","DeleteContactButton","Pagination","p","contactId","contactEmail","modal","useModal","t","useTranslation","router","useRouter","requestJson","useMarketingApi","modalSlug","confirmDelete","toast","PayloadModal","PayloadModalContent","PayloadModalBody","PayloadModalFooter","PayloadModalClose","PayloadButton","err","id","ReactRaw","slug","EditContactModalWrapper","startTransition","useTransition","submit","fields","data","email","firstName","lastName","subscribed","Form","TextField","v","CheckboxField","DefaultTemplate","jsx","MarketingViewShell","children","initPageResult","params","searchParams","firstString","value","marketingAudienceIdFromParams","params","fromId","segmentsRaw","segmentList","s","audienceIdx","last","Fragment","jsx","jsxs","AudienceDetail","initPageResult","params","searchParams","audienceId","marketingAudienceIdFromParams","MarketingViewShell","Gutter","AudienceDetailBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","audience","notFound","audienceDashboardUrl","Link","EditContactButton","Suspense","DetailContacts","contacts","ContactsTable","Suspense","Gutter","Link","Table","useTransition","Button","Form","TextField","toast","useModal","useTranslation","PayloadButton","useRouter","Fragment","jsx","jsxs","createAudienceSlug","CreateAudienceButton","modal","useModal","useTranslation","CreateAudienceModal","Button","router","useRouter","requestJson","useMarketingApi","isPending","startTransition","useTransition","PayloadModal","PayloadModalContent","Form","fields","data","nameRaw","name","toast","err","PayloadModalBody","PayloadModalTitle","TextField","v","PayloadModalFooter","PayloadModalClose","DeleteAudienceButton","audienceId","audienceName","t","modalSlug","confirmDelete","PayloadButton","Fragment","jsx","jsxs","AudienceList","basePath","initPageResult","params","searchParams","MarketingViewShell","Gutter","AudienceListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","audiencesUrl","Link","CreateAudienceButton","Suspense","AudienceTableRows","audiencesWrite","adapter","getMarketingIntegration","audiences","nameColumn","audience","marketingAdminHref","deleteColumn","DeleteAudienceButton","Table","Suspense","Gutter","Link","React","PayloadButton","DateTimeField","Form","Pagination","Pill","Table","toast","useModal","useTranslation","Link","useRouter","Fragment","jsx","jsxs","BroadcastsTable","broadcasts","page","setPage","React","limit","currentPage","Table","b","formatMarketingDate","broadcast","BroadcastStatusPill","Link","Pill","DeleteBroadcastButton","SendBroadcastButton","Pagination","p","status","broadcastId","broadcastName","modal","useModal","t","useTranslation","router","useRouter","requestJson","useMarketingApi","modalSlug","confirmDelete","toast","PayloadModal","PayloadModalContent","PayloadModalBody","PayloadModalTitle","PayloadModalFooter","PayloadModalClose","PayloadButton","err","submit","fields","data","scheduledRaw","scheduledAt","Form","DateTimeField","React","Button","Drawer","Form","SelectField","TextareaField","TextField","toast","useModal","useTranslation","useRouter","Fragment","jsx","jsxs","modalSlug","CreateBroadcastButton","audiences","provider","modal","useModal","t","useTranslation","CreateBroadcastModal","Button","router","useRouter","requestJson","useMarketingApi","isPending","setIsPending","React","showTemplateField","submit","fields","data","row","audienceIdRaw","nameRaw","subjectRaw","htmlRaw","templateIdRaw","replyToRaw","audienceId","name","subject","htmlBody","templateId","replyTo","toast","err","Drawer","Form","SelectField","a","TextField","TextareaField","Fragment","jsx","jsxs","BroadcastList","initPageResult","params","searchParams","MarketingViewShell","Gutter","BroadcastListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","broadcastsUrl","Link","Suspense","CreateBroadcastRegion","BroadcastTableRegion","audiences","CreateBroadcastButton","broadcasts","b","BroadcastsTable","defaultAdminComponentPath"]}
|
|
1
|
+
{"version":3,"sources":["../../src/admin/index.ts"],"sourcesContent":["export * from \"./constants\"\nexport * from \"./server\"\nexport * from \"./client\"\n"],"mappings":"AAAA,WAAc,cACd,WAAc,WACd,WAAc","names":[]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SanitizedConfig } from "payload";
|
|
2
|
+
/** Options for admin selects; values are locale codes from `config.localization.locales`. */
|
|
3
|
+
export declare function getLocaleSelectOptionsFromConfig(config: SanitizedConfig): {
|
|
4
|
+
label: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}[];
|
|
7
|
+
//# sourceMappingURL=locale-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locale-options.d.ts","sourceRoot":"","sources":["../../src/admin/locale-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,eAAe,EAAE,MAAM,SAAS,CAAA;AAiBtD,6FAA6F;AAC7F,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,eAAe,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAapC"}
|