payload-plugin-marketing 0.9.4 → 0.9.5
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/dist/admin/server.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var Qe=Object.create;var X=Object.defineProperty;var Xe=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var et=Object.getPrototypeOf,tt=Object.prototype.hasOwnProperty;var at=(e,t)=>{for(var a in t)X(e,a,{get:t[a],enumerable:!0})},Re=(e,t,a,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Ze(t))!tt.call(e,o)&&o!==a&&X(e,o,{get:()=>t[o],enumerable:!(n=Xe(t,o))||n.enumerable});return e};var L=(e,t,a)=>(a=e!=null?Qe(et(e)):{},Re(t||!e||!e.__esModule?X(a,"default",{value:e,enumerable:!0}):a,e)),nt=e=>Re(X({},"__esModule",{value:!0}),e);var kt={};at(kt,{AudienceDetail:()=>oe,AudienceList:()=>re,BroadcastList:()=>se});module.exports=nt(kt);var ne=require("@payloadcms/ui"),je=require("next/navigation");function ot(e,...t){let a=e.replace(/\/+$/,"")||"",n=t.flatMap(r=>String(r).split("/")).map(r=>r.replace(/^\/+|\/+$/g,"")).filter(Boolean).join("/");return(a===""?`/${n}`:`${a}/${n}`).replace(/\/{2,}/g,"/")}function Ne(e,...t){let n=[e?.replace(/^\/+|\/+$/g,"")??"",...t].filter(Boolean);return ot("/admin",...n)}var Fe=require("@payloadcms/ui"),Z=require("react");function S(){let e=(0,Fe.useConfig)(),t=(0,Z.useMemo)(()=>`${e.serverURL??""}${e.routes?.api??"/api"}`,[e.routes?.api,e.serverURL]),a=(0,Z.useCallback)(async(n,o)=>{let{headers:r,...i}=o??{},d=new Headers(o?.headers);i.body!==void 0&&i.body!==""&&i.body!==null&&(d.has("Content-Type")||d.set("Content-Type","application/json"));let b=await fetch(`${t}${n}`,{...i,credentials:"include",headers:d});if(!b.ok){let w=`${b.status} ${b.statusText}`;try{let k=await b.json();typeof k.message=="string"&&(w=k.message)}catch{}throw new Error(w)}if(b.status!==204)try{return await b.json()}catch{return}},[t]);return{base:t,requestJson:a}}var u=require("@payloadcms/ui"),De=L(require("next/link"),1),de=require("next/navigation"),ee=L(require("react"),1);function G(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)}var I=require("@payloadcms/ui"),W=L(require("react"),1),F=require("react/jsx-runtime");function O(...e){return e.filter(Boolean).join(" ")}var Ie=W.default.createContext({modalSlug:""});function C({children:e,className:t,slug:a,...n}){let[o,r]=W.default.useState(!1);return W.default.useEffect(()=>{r(!0)},[]),(0,F.jsx)(Ie.Provider,{value:{modalSlug:a},children:o&&(0,F.jsx)(I.Modal,{slug:a,className:O("confirmation-modal",t),...n,children:e})})}function x({children:e,className:t,...a}){return(0,F.jsx)("div",{className:O("confirmation-modal__wrapper",t),"data-slot":"payload-modal-content",...a,children:e})}function B({children:e,className:t,...a}){return(0,F.jsx)("div",{className:O("confirmation-modal__content",t),"data-slot":"payload-modal-body",...a,children:e})}function V({children:e,className:t,...a}){return(0,F.jsx)("h1",{className:O("",t),"data-slot":"payload-modal-title",...a,children:e})}function A({children:e,className:t,...a}){return(0,F.jsx)("div",{className:O("confirmation-modal__controls",t),"data-slot":"payload-modal-footer",...a,children:e})}function T({children:e,className:t,...a}){let{t:n}=(0,I.useTranslation)(),{modalSlug:o}=W.default.useContext(Ie),r=(0,I.useModal)();return(0,F.jsx)(I.Button,{className:O("",t),buttonStyle:"secondary",size:"large","data-slot":"payload-modal-close",...a,onClick:()=>r.closeModal(o),children:e??n("general:cancel")})}var s=require("react/jsx-runtime");function ce({broadcasts:e}){let[t,a]=ee.default.useState(1),[n]=ee.default.useState(100),o=ee.default.useMemo(()=>e.slice((t-1)*n,t*n),[e,n,t]);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(u.Table,{columns:[{Heading:"Campaign name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:o.map(r=>(0,s.jsx)("div",{children:r.name},r.id))},{Heading:"Schedule date",accessor:"scheduledAt",active:!0,field:{name:"scheduledAt",type:"text"},renderedCells:o.map(r=>(0,s.jsx)("div",{children:G(r.scheduledAt)},r.id))},{Heading:"Sent date",accessor:"sentAt",active:!0,field:{name:"sentAt",type:"text"},renderedCells:o.map(r=>(0,s.jsx)("div",{children:G(r.sentAt)},r.id))},{Heading:"Status",accessor:"status",active:!0,field:{name:"status",type:"text"},renderedCells:o.map(r=>(0,s.jsx)("div",{children:(0,s.jsx)(rt,{status:r.status})},r.id))},{Heading:"",accessor:"",active:!0,field:{name:"_",type:"text"},renderedCells:o.map(r=>(0,s.jsxs)("div",{className:"flex items-center gap-4 flex-wrap",children:[r.externalDashboardUrl?(0,s.jsx)(De.default,{href:r.externalDashboardUrl,rel:"noreferrer noopener",target:"_blank",children:(0,s.jsx)(u.Pill,{children:"dashboard \u2197"})}):null,r.status==="draft"||r.status==="save"?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(it,{broadcastId:r.id,broadcastName:r.name}),(0,s.jsx)(st,{broadcastId:r.id,broadcastName:r.name})]}):null]},r.id))}],data:o}),(0,s.jsx)(u.Pagination,{hasNextPage:t*n<e.length,hasPrevPage:t>1,limit:n,onChange:r=>a(r),page:t,totalPages:Math.ceil(e.length/n)})]})}function rt({status:e}){switch(e){case"draft":case"save":return(0,s.jsx)(u.Pill,{pillStyle:"light-gray",children:"Draft"});case"queued":return(0,s.jsx)(u.Pill,{pillStyle:"white",children:"Queued"});case"sent":return(0,s.jsx)(u.Pill,{pillStyle:"success",children:"Sent"});default:return(0,s.jsx)(u.Pill,{children:e})}}function it({broadcastId:e,broadcastName:t}){let a=(0,u.useModal)(),{t:n}=(0,u.useTranslation)(),o=(0,de.useRouter)(),{requestJson:r}=S(),i=`delete-broadcast_${e}`;async function d(){await r(`/marketing/broadcasts/${encodeURIComponent(e)}`,{method:"DELETE"}),u.toast.success(n("general:deletedSuccessfully")),a.closeModal(i),o.refresh()}return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(C,{slug:i,children:(0,s.jsxs)(x,{children:[(0,s.jsxs)(B,{children:[(0,s.jsx)(V,{children:n("general:confirmDeletion")}),(0,s.jsx)("p",{children:`Delete draft broadcast "${t}"?`})]}),(0,s.jsxs)(A,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[(0,s.jsx)(T,{}),(0,s.jsx)(u.Button,{buttonStyle:"error",onClick:()=>{d().catch(b=>u.toast.error(b instanceof Error?b.message:"Delete failed"))},children:n("general:confirm")})]})]})}),(0,s.jsx)("button",{onClick:()=>a.openModal(i),type:"button",children:n("general:delete")})]})}function st({broadcastId:e,broadcastName:t}){let a=(0,u.useModal)(),{t:n}=(0,u.useTranslation)(),o=(0,de.useRouter)(),{requestJson:r}=S(),i=`send-broadcast_${e}`,d=(b,w)=>{let v=w.scheduledAt,M="";typeof v=="string"?M=v:v instanceof Date&&(M=v.toISOString()),(async()=>{try{await r(`/marketing/broadcasts/${encodeURIComponent(e)}/send`,{body:JSON.stringify({...M&&M.trim()!==""?{scheduledAt:M.trim()}:{}}),method:"POST"}),a.closeModal(i),u.toast.success(n("general:success")),o.refresh()}catch(q){u.toast.error(q instanceof Error?q.message:"Send failed")}})()};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(C,{slug:i,children:(0,s.jsx)(x,{style:{width:"100%",maxWidth:"24rem"},children:(0,s.jsxs)(B,{children:[(0,s.jsx)(V,{children:`Send \u201C${t}\u201D`}),(0,s.jsxs)(u.Form,{initialState:{},onSubmit:d,waitForAutocomplete:!0,children:[(0,s.jsx)(u.DateTimeField,{field:{label:"Schedule at (optional)",name:"scheduledAt",required:!1},path:"scheduledAt"}),(0,s.jsxs)(A,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[(0,s.jsx)(T,{}),(0,s.jsx)(u.Button,{size:"large",type:"submit",children:"Send"})]})]})]})})}),(0,s.jsx)(u.Pill,{pillStyle:"dark",onClick:()=>a.openModal(i),size:"small",children:"Send"})]})}var h=require("@payloadcms/ui"),me=require("next/navigation"),Ee=require("react");var p=require("react/jsx-runtime"),ue="create-audience";function pe(){let e=(0,h.useModal)(),{t}=(0,h.useTranslation)();return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(lt,{}),(0,p.jsx)(h.Button,{onClick:()=>e.openModal(ue),size:"large",type:"button",children:t("general:createNew")})]})}function lt(){let e=(0,h.useModal)(),{t}=(0,h.useTranslation)(),a=(0,me.useRouter)(),{requestJson:n}=S(),[o,r]=(0,Ee.useTransition)();return(0,p.jsx)(C,{closeOnBlur:!0,slug:ue,children:(0,p.jsx)(x,{style:{width:"100%",maxWidth:"24rem"},children:(0,p.jsx)(h.Form,{initialState:{},onSubmit:(d,b)=>{let k=b.audienceName,v=typeof k=="string"?k.trim():"";r(()=>{(async()=>{try{if(!v)throw new Error("Name is required.");await n("/marketing/audiences",{body:JSON.stringify({name:v}),method:"POST"}),e.closeModal(ue),h.toast.success(t("general:successfullyCreated")),a.refresh()}catch(M){h.toast.error(M instanceof Error?M.message:"Create failed")}})()})},waitForAutocomplete:!0,children:(0,p.jsxs)(B,{children:[(0,p.jsx)(V,{children:t("general:createNew")}),(0,p.jsx)(h.TextField,{field:{name:"audienceName",required:!0,type:"text"},path:"audienceName",validate:d=>typeof d=="string"&&d.trim().length>0?!0:"Name is required"}),(0,p.jsxs)(A,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[(0,p.jsx)(T,{}),(0,p.jsx)(h.Button,{disabled:o,size:"large",type:"submit",children:t("general:confirm")})]})]})})})})}function fe({audienceId:e,audienceName:t}){let a=(0,h.useModal)(),{t:n}=(0,h.useTranslation)(),o=(0,me.useRouter)(),{requestJson:r}=S(),i=`delete-audience_${e}`;async function d(){await r(`/marketing/audiences/${encodeURIComponent(e)}`,{method:"DELETE"}),h.toast.success(n("general:deletedSuccessfully")),a.closeModal(i),o.refresh()}return(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(C,{slug:i,children:(0,p.jsxs)(x,{children:[(0,p.jsxs)(B,{children:[(0,p.jsx)(V,{children:n("general:confirmDeletion")}),(0,p.jsx)("p",{children:`Remove audience "${t}"?`})]}),(0,p.jsxs)(A,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[(0,p.jsx)(T,{}),(0,p.jsx)(h.Button,{buttonStyle:"error",onClick:()=>{d().catch(b=>h.toast.error(b instanceof Error?b.message:"Delete failed"))},children:n("general:confirm")})]})]})}),(0,p.jsx)("button",{onClick:()=>a.openModal(i),type:"button",children:n("general:delete")})]})}var m=require("@payloadcms/ui"),ge=require("next/navigation"),te=L(require("react"),1),qe=L(require("react"),1),Le=require("react");var l=require("react/jsx-runtime");function ye({audienceId:e,contacts:t}){let[a,n]=te.default.useState(1),[o]=te.default.useState(100),r=te.default.useMemo(()=>t.slice((a-1)*o,a*o),[t,o,a]);return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(m.Table,{columns:[{Heading:"First name",accessor:"firstName",active:!0,field:{name:"firstName",type:"text"},renderedCells:r.map(i=>(0,l.jsx)("div",{children:i.firstName??"\u2014"},i.id))},{Heading:"Last name",accessor:"lastName",active:!0,field:{name:"lastName",type:"text"},renderedCells:r.map(i=>(0,l.jsx)("div",{children:i.lastName??"\u2014"},i.id))},{Heading:"Email",accessor:"email",active:!0,field:{name:"email",type:"text"},renderedCells:r.map(i=>(0,l.jsx)("div",{children:i.email},i.id))},{Heading:"Created",accessor:"createdAt",active:!0,field:{name:"createdAt",type:"text"},renderedCells:r.map(i=>(0,l.jsx)("div",{children:G(i.createdAt)},i.id))},{Heading:"Status",accessor:"subscribed",active:!0,field:{name:"subscribed",type:"text"},renderedCells:r.map(i=>(0,l.jsxs)("div",{className:"flex items-center gap-4 flex-wrap",children:[(0,l.jsx)("span",{children:i.subscribed!==!1?"\u2705 subscribed":"\u274C unsubscribed"}),(0,l.jsx)(ae,{audienceId:e,contact:i}),(0,l.jsx)(dt,{audienceId:e,contactEmail:i.email,contactId:i.id})]},i.id))}],data:r}),(0,l.jsx)(m.Pagination,{hasNextPage:a*o<t.length,hasPrevPage:a>1,limit:o,onChange:i=>{n(i)},page:a,totalPages:Math.ceil(t.length/o)})]})}function dt({audienceId:e,contactId:t,contactEmail:a}){let n=(0,m.useModal)(),{t:o}=(0,m.useTranslation)(),r=(0,ge.useRouter)(),{requestJson:i}=S(),d=`delete-contact_${t}`;async function b(){await i(`/marketing/audiences/${encodeURIComponent(e)}/contacts/${encodeURIComponent(t)}`,{method:"DELETE"}),m.toast.success(o("general:deletedSuccessfully")),n.closeModal(d),r.refresh()}return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(C,{slug:d,children:(0,l.jsxs)(x,{children:[(0,l.jsxs)(B,{children:[(0,l.jsx)("h1",{children:o("general:confirmDeletion")}),(0,l.jsx)("p",{children:`Remove contact ${a}?`})]}),(0,l.jsxs)(A,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[(0,l.jsx)(T,{}),(0,l.jsx)(m.Button,{buttonStyle:"error",onClick:()=>{b().catch(w=>m.toast.error(w instanceof Error?w.message:"Delete failed"))},children:o("general:confirm")})]})]})}),(0,l.jsx)("button",{onClick:()=>n.openModal(d),type:"button",children:o("general:delete")})]})}function ae({audienceId:e,contact:t}){let a=(0,m.useModal)(),{t:n}=(0,m.useTranslation)(),o=qe.default.useId(),r=t?`edit-contact_${t.id}`:`create-contact_${e}_${o}`;return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(ct,{audienceId:e,contact:t,modalSlug:r}),(0,l.jsx)(t?"button":m.Button,{...t?{}:{size:"large"},onClick:()=>a.openModal(r),type:"button",children:n(t?"general:edit":"general:createNew")})]})}function ct({audienceId:e,contact:t,modalSlug:a}){let n=(0,m.useModal)(),{t:o}=(0,m.useTranslation)(),r=(0,ge.useRouter)(),{requestJson:i}=S(),[,d]=(0,Le.useTransition)(),b=(w,k)=>{let v=k.email,M=String(k.firstName??""),q=String(k.lastName??""),U=!!k.subscribed;d(()=>{(async()=>{try{await i("/marketing/contacts",{body:JSON.stringify({audienceId:e,email:v,firstName:M,id:t?.id,lastName:q,subscribed:U}),method:"POST"}),m.toast.success(t?"Contact updated.":"Contact created."),n.closeModal(a),r.refresh()}catch(Y){m.toast.error(Y instanceof Error?Y.message:"Save failed")}})()})};return(0,l.jsx)(C,{slug:a,children:(0,l.jsx)(x,{style:{width:"100%",maxWidth:"32rem"},children:(0,l.jsxs)(B,{children:[(0,l.jsx)("h1",{children:o(t?"general:edit":"general:createNew")}),(0,l.jsxs)(m.Form,{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:b,waitForAutocomplete:!0,children:[(0,l.jsx)(m.TextField,{field:{label:o("general:email"),name:"email",required:!0,type:"text"},path:"email",validate:w=>typeof w=="string"&&w.includes("@")?!0:"Valid email required"}),(0,l.jsx)(m.TextField,{field:{label:"First name",name:"firstName",type:"text"},path:"firstName"}),(0,l.jsx)(m.TextField,{field:{label:"Last name",name:"lastName",type:"text"},path:"lastName"}),(0,l.jsx)(m.CheckboxField,{field:{label:"Subscribed",name:"subscribed"},path:"subscribed"}),(0,l.jsxs)(A,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[(0,l.jsx)(T,{}),(0,l.jsx)(m.Button,{size:"large",type:"submit",children:o(t?"general:save":"general:create")})]})]})]})})})}var c=require("@payloadcms/ui"),Oe=require("next/navigation"),Ve=L(require("react"),1);var f=require("react/jsx-runtime"),he="create-marketing-broadcast";function be({audiences:e,emailBroadcastTemplates:t,localeOptions:a,provider:n}){let o=(0,c.useModal)(),{t:r}=(0,c.useTranslation)();return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(mt,{audiences:e,emailBroadcastTemplates:t,localeOptions:a??[],provider:n}),(0,f.jsx)(c.Button,{onClick:()=>o.openModal(he),size:"large",type:"button",children:r("general:createNew")})]})}function ut({localeOptions:e,showReactEmailTemplates:t,showTemplateField:a,templateOptions:n}){let o=(0,c.useFormFields)(([r])=>{if(!t)return"html";let i=r?.broadcastFormat?.value;return typeof i=="string"&&i!==""?i:"html"});if(t){let r=o==="html";return(0,f.jsxs)(f.Fragment,{children:[(0,f.jsx)(c.SelectField,{field:{label:"Email content",name:"broadcastFormat",options:[{label:"<html>",value:"html"},...n.map(i=>({label:i.name,value:i.id}))],required:!0},path:"broadcastFormat"}),!r&&e.length>0?(0,f.jsx)(c.SelectField,{field:{label:"Locale",name:"locale",options:e,required:!1},path:"locale"}):null,r?(0,f.jsx)(c.TextareaField,{field:{admin:{description:"Shown when Email content is <html>."},label:"<html>",name:"htmlBody",required:!0},path:"htmlBody"}):null]})}return(0,f.jsxs)(f.Fragment,{children:[a?(0,f.jsx)(c.TextField,{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,(0,f.jsx)(c.TextareaField,{field:{admin:{description:a?"Optional plain HTML alternative to a Mailchimp template.":"HTML broadcast body."},label:a?"<html> (optional with Mailchimp)":"<html>",name:"htmlBody",required:!a},path:"htmlBody"})]})}function mt({audiences:e,emailBroadcastTemplates:t,localeOptions:a,provider:n}){let o=(0,Oe.useRouter)(),r=(0,c.useModal)(),{t:i}=(0,c.useTranslation)(),{requestJson:d}=S(),[b,w]=Ve.default.useState(!1),k=n==="mailchimp",v=t??[],M=n==="resend"&&v.length>0,q=(U,Y)=>{let N=Y,Me=N.audienceId,ke=N.name,ve=N.subject,Se=N.htmlBody,Ce=N.templateId,xe=N.replyTo,Be=N.broadcastFormat,Ae=N.locale,J=typeof Me=="string"?Me:"",j=typeof ke=="string"?ke.trim():"",z=typeof ve=="string"?ve.trim():"",D=typeof Se=="string"?Se.trim():"",le=typeof Ce=="string"?Ce.trim():"",K=typeof xe=="string"?xe.trim():"",Te=typeof Be=="string"?Be.trim():"html",Ye=typeof Ae=="string"?Ae.trim():"";w(!0),(async()=>{try{if(!J||!j||!z)throw new Error("Audience, name, and subject are required.");let Q=k,Ke=M&&Te!=="html";if(M)if(Ke)await d("/marketing/broadcasts",{body:JSON.stringify({audienceId:J,emailTemplateId:Te,locale:Ye||void 0,name:j,replyTo:K,subject:z}),method:"POST"});else if(D)await d("/marketing/broadcasts",{body:JSON.stringify({audienceId:J,html:D,name:j,replyTo:K,subject:z}),method:"POST"});else throw new Error("<html> is required when using the <html> content option.");else if(Q){if(!le&&!D)throw new Error("Provide <html> or a Mailchimp template id.");if(le&&D)throw new Error("Use either <html> or Mailchimp template id, not both.");await d("/marketing/broadcasts",{body:JSON.stringify({audienceId:J,html:D,name:j,replyTo:K,subject:z,templateId:le||void 0}),method:"POST"})}else if(D)await d("/marketing/broadcasts",{body:JSON.stringify({audienceId:J,html:D,name:j,replyTo:K,subject:z}),method:"POST"});else throw new Error("<html> is required for this provider.");r.closeModal(he),c.toast.success(i("general:successfullyCreated",{label:"Broadcast"})),o.refresh()}catch(Q){c.toast.error(Q instanceof Error?Q.message:"Create failed")}finally{w(!1)}})()};return(0,f.jsx)(c.Drawer,{slug:he,title:i("general:createNew"),children:(0,f.jsxs)(c.Form,{className:"flex w-full flex-col gap-8",initialState:M?{broadcastFormat:{value:"html"}}:{},onSubmit:q,waitForAutocomplete:!0,children:[(0,f.jsx)(c.SelectField,{field:{label:"Audience",name:"audienceId",options:e.map(U=>({label:U.name,value:U.id})),required:!0},path:"audienceId"}),(0,f.jsx)(c.TextField,{field:{label:"Campaign name",name:"name",required:!0,type:"text"},path:"name"}),(0,f.jsx)(c.TextField,{field:{label:"Subject",name:"subject",required:!0,type:"text"},path:"subject"}),(0,f.jsx)(c.TextField,{field:{label:"Reply-to (optional)",name:"replyTo",type:"text"},path:"replyTo"}),(0,f.jsx)(ut,{localeOptions:a,showReactEmailTemplates:M,showTemplateField:k,templateOptions:v}),(0,f.jsx)(c.Button,{className:"w-full",disabled:b,type:"submit",children:i("general:create")})]})})}var ze=require("react");var $e="payloadPluginMarketing";function Pe(e){return{read:e?.read??!0,write:e?.write??!0}}function $(e){return e?{audiences:Pe(e.audiences),contacts:Pe(e.contacts),broadcasts:Pe(e.broadcasts)}:{audiences:{read:!0,write:!0},broadcasts:{read:!0,write:!0},contacts:{read:!0,write:!0}}}function _e(e){let t=e.config.custom;if(!t||typeof t!="object")return;let a=t[$e];if(a?.adapter)return a}function R(e){let t=_e(e);if(!t)throw new Error(`${$e}: adapter missing on Payload config. Is marketingPlugin() registered?`);return t}function _(e){return _e(e)}var He=require("@payloadcms/next/templates"),Ue=require("react/jsx-runtime");function H({children:e,initPageResult:t,params:a,searchParams:n}){return(0,Ue.jsx)(He.DefaultTemplate,{i18n:t.req.i18n,locale:t.locale,params:a,payload:t.req.payload,permissions:t.permissions,searchParams:n,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 Je(e){if(!e)return;let t=pt(e.id);if(t)return t;let a=e.segments,n=Array.isArray(a)?a.filter(i=>typeof i=="string"&&i.length>0):typeof a=="string"?a.split("/").filter(Boolean):[];if(n.length===0)return;let o=n.lastIndexOf("audience");if(o>=0&&n[o+1])return n[o+1];let r=n[n.length-1];if(r!=="audience")return r}var P=require("react/jsx-runtime");function oe({initPageResult:e,params:t,searchParams:a}){let n=Je(t);if(!n)throw new Error("No audience id in route params");return(0,P.jsx)(H,{initPageResult:e,params:t,searchParams:a,children:(0,P.jsx)(ne.Gutter,{children:(0,P.jsx)(ft,{audienceId:n,initPageResult:e})})})}async function ft({audienceId:e,initPageResult:t}){let a=_(t.req.payload);if(!a)return(0,P.jsx)("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=$(a.permissions);if(!n.audiences.read)return(0,P.jsx)("p",{role:"alert",children:"You do not have permission to view this audience."});let{adapter:o}=R(t.req.payload),r=await o.audiences.get(e);r||(0,je.notFound)();let i=o.urls?.audience?.(e);return(0,P.jsxs)(P.Fragment,{children:[(0,P.jsxs)("header",{className:"flex flex-col gap-4",children:[(0,P.jsx)("h1",{children:r.name}),i?(0,P.jsxs)(ne.Link,{href:i,rel:"noreferrer noopener",target:"_blank",children:["Open this audience in ",o.label]}):null]}),(0,P.jsxs)("div",{className:"mt-12 flex flex-col gap-6",children:[n.contacts.write?(0,P.jsx)("div",{children:(0,P.jsx)(ae,{audienceId:e,contact:null})}):null,n.contacts.read?(0,P.jsx)(ze.Suspense,{fallback:(0,P.jsx)("div",{"aria-busy":!0,style:{minHeight:"12rem"}}),children:(0,P.jsx)(gt,{audienceId:e,initPageResult:t})}):(0,P.jsx)("p",{role:"alert",children:"You do not have permission to list contacts."})]})]})}async function gt({audienceId:e,initPageResult:t}){let{adapter:a}=R(t.req.payload),n=await a.contacts.list({audienceId:e});return(0,P.jsx)(ye,{audienceId:e,contacts:n})}var E=require("@payloadcms/ui");var Ge=require("react");var g=require("react/jsx-runtime");function re({basePath:e="",initPageResult:t,params:a,searchParams:n}){return(0,g.jsx)(H,{initPageResult:t,params:a,searchParams:n,children:(0,g.jsx)(E.Gutter,{children:(0,g.jsx)(yt,{basePath:e,initPageResult:t})})})}function yt({basePath:e,initPageResult:t}){let a=_(t.req.payload);if(!a)return(0,g.jsx)("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=$(a.permissions);if(!n.audiences.read)return(0,g.jsx)("p",{role:"alert",children:"You do not have permission to view audiences."});let o=a.adapter.urls?.audiences;return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)("header",{className:"flex flex-col gap-4",children:[(0,g.jsx)("h1",{children:"Audiences"}),o?(0,g.jsxs)(E.Link,{href:o,rel:"noreferrer noopener",target:"_blank",children:["View audiences in ",a.adapter.label]}):null]}),(0,g.jsxs)("div",{className:"mt-4 flex flex-col gap-8",children:[n.audiences.write?(0,g.jsx)("div",{children:(0,g.jsx)(pe,{})}):null,(0,g.jsx)(Ge.Suspense,{fallback:(0,g.jsx)("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:(0,g.jsx)(ht,{audiencesWrite:n.audiences.write,basePath:e,initPageResult:t})})]})]})}async function ht({audiencesWrite:e,basePath:t,initPageResult:a}){let{adapter:n}=R(a.req.payload),o=await n.audiences.list(),r={Heading:"Name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:o.map(d=>(0,g.jsx)("div",{children:(0,g.jsx)(E.Link,{href:Ne(t,"audience",d.id),children:d.name})},d.id))},i={Heading:"",accessor:"",active:!0,field:{name:"_delete",type:"text"},renderedCells:o.map(d=>(0,g.jsx)("div",{children:(0,g.jsx)(fe,{audienceId:d.id,audienceName:d.name})},d.id))};return(0,g.jsx)(E.Table,{columns:e?[r,i]:[r],data:o})}var ie=require("@payloadcms/ui");var we=require("react");function bt(e){let{label:t,code:a}=e;if(typeof t=="string")return t;if(t&&typeof t=="object"){for(let n of Object.values(t))if(typeof n=="string")return n}return a}function We(e){let t=e.localization;if(t===!1||t===void 0)return[];let a=t.locales;return a?.length?a.map(n=>({label:bt(n),value:n.code})):[]}var y=require("react/jsx-runtime");function se({initPageResult:e,params:t,searchParams:a}){return(0,y.jsx)(H,{initPageResult:e,params:t,searchParams:a,children:(0,y.jsx)(ie.Gutter,{children:(0,y.jsx)(Pt,{initPageResult:e})})})}function Pt({initPageResult:e}){let t=_(e.req.payload);if(!t)return(0,y.jsx)("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let a=$(t.permissions);if(!a.broadcasts.read)return(0,y.jsx)("p",{role:"alert",children:"You do not have permission to view broadcasts."});let{adapter:n}=R(e.req.payload),o=n.urls?.broadcasts;return(0,y.jsxs)(y.Fragment,{children:[(0,y.jsxs)("header",{className:"flex flex-col gap-4",children:[(0,y.jsx)("h1",{children:"Campaigns"}),o?(0,y.jsxs)(ie.Link,{href:o,rel:"noreferrer noopener",target:"_blank",children:["View campaigns in ",n.label]}):null]}),(0,y.jsxs)("div",{className:"mt-4 flex flex-col gap-8",children:[a.broadcasts.write?(0,y.jsx)("div",{children:(0,y.jsx)(we.Suspense,{fallback:(0,y.jsx)("div",{"aria-busy":!0,style:{minHeight:"2.5rem"}}),children:(0,y.jsx)(wt,{initPageResult:e})})}):null,(0,y.jsx)(we.Suspense,{fallback:(0,y.jsx)("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:(0,y.jsx)(Mt,{initPageResult:e})})]})]})}async function wt({initPageResult:e}){let t=R(e.req.payload),{adapter:a}=t,n=await a.audiences.list(),o=t.emailBroadcastTemplates?.map(({id:i,name:d})=>({id:i,name:d}))??[],r=We(e.req.payload.config);return(0,y.jsx)(be,{audiences:n,emailBroadcastTemplates:o,localeOptions:r,provider:a.provider})}async function Mt({initPageResult:e}){let{adapter:t}=R(e.req.payload),n=(await t.broadcasts.list()).map(o=>({...o,externalDashboardUrl:t.urls?.broadcast?.(o.id)}));return(0,y.jsx)(ce,{broadcasts:n})}0&&(module.exports={AudienceDetail,AudienceList,BroadcastList});
|
|
1
|
+
"use strict";var S=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var O=Object.prototype.hasOwnProperty;var F=(e,t)=>{for(var r in t)S(e,r,{get:t[r],enumerable:!0})},H=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of G(t))!O.call(e,i)&&i!==r&&S(e,i,{get:()=>t[i],enumerable:!(n=E(t,i))||n.enumerable});return e};var _=e=>H(S({},"__esModule",{value:!0}),e);var Z={};F(Z,{AudienceDetail:()=>k,AudienceList:()=>b,BroadcastList:()=>A});module.exports=_(Z);var y=require("@payloadcms/ui"),C=require("next/navigation"),P=require("payload-plugin-marketing/admin/client"),q=require("react");var V="payloadPluginMarketing";function M(e){return{read:e?.read??!0,write:e?.write??!0}}function m(e){return e?{audiences:M(e.audiences),contacts:M(e.contacts),broadcasts:M(e.broadcasts)}:{audiences:{read:!0,write:!0},broadcasts:{read:!0,write:!0},contacts:{read:!0,write:!0}}}function B(e){let t=e.config.custom;if(!t||typeof t!="object")return;let r=t[V];if(r?.adapter)return r}function u(e){let t=B(e);if(!t)throw new Error(`${V}: adapter missing on Payload config. Is marketingPlugin() registered?`);return t}function f(e){return B(e)}var I=require("@payloadcms/next/templates"),L=require("react/jsx-runtime");function g({children:e,initPageResult:t,params:r,searchParams:n}){return(0,L.jsx)(I.DefaultTemplate,{i18n:t.req.i18n,locale:t.locale,params:r,payload:t.req.payload,permissions:t.permissions,searchParams:n,user:t.req.user??void 0,visibleEntities:t.visibleEntities,children:e})}function $(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 R(e){if(!e)return;let t=$(e.id);if(t)return t;let r=e.segments,n=Array.isArray(r)?r.filter(l=>typeof l=="string"&&l.length>0):typeof r=="string"?r.split("/").filter(Boolean):[];if(n.length===0)return;let i=n.lastIndexOf("audience");if(i>=0&&n[i+1])return n[i+1];let d=n[n.length-1];if(d!=="audience")return d}var s=require("react/jsx-runtime");function k({initPageResult:e,params:t,searchParams:r}){let n=R(t);if(!n)throw new Error("No audience id in route params");return(0,s.jsx)(g,{initPageResult:e,params:t,searchParams:r,children:(0,s.jsx)(y.Gutter,{children:(0,s.jsx)(z,{audienceId:n,initPageResult:e})})})}async function z({audienceId:e,initPageResult:t}){let r=f(t.req.payload);if(!r)return(0,s.jsx)("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=m(r.permissions);if(!n.audiences.read)return(0,s.jsx)("p",{role:"alert",children:"You do not have permission to view this audience."});let{adapter:i}=u(t.req.payload),d=await i.audiences.get(e);d||(0,C.notFound)();let l=i.urls?.audience?.(e);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)("header",{className:"flex flex-col gap-4",children:[(0,s.jsx)("h1",{children:d.name}),l?(0,s.jsxs)(y.Link,{href:l,rel:"noreferrer noopener",target:"_blank",children:["Open this audience in ",i.label]}):null]}),(0,s.jsxs)("div",{className:"mt-12 flex flex-col gap-6",children:[n.contacts.write?(0,s.jsx)("div",{children:(0,s.jsx)(P.EditContactButton,{audienceId:e,contact:null})}):null,n.contacts.read?(0,s.jsx)(q.Suspense,{fallback:(0,s.jsx)("div",{"aria-busy":!0,style:{minHeight:"12rem"}}),children:(0,s.jsx)(U,{audienceId:e,initPageResult:t})}):(0,s.jsx)("p",{role:"alert",children:"You do not have permission to list contacts."})]})]})}async function U({audienceId:e,initPageResult:t}){let{adapter:r}=u(t.req.payload),n=await r.contacts.list({audienceId:e});return(0,s.jsx)(P.AudienceContactsTable,{audienceId:e,contacts:n})}var p=require("@payloadcms/ui"),w=require("payload-plugin-marketing/admin/client"),N=require("react");function Y(e,...t){let r=e.replace(/\/+$/,"")||"",n=t.flatMap(d=>String(d).split("/")).map(d=>d.replace(/^\/+|\/+$/g,"")).filter(Boolean).join("/");return(r===""?`/${n}`:`${r}/${n}`).replace(/\/{2,}/g,"/")}function T(e,...t){let n=[e?.replace(/^\/+|\/+$/g,"")??"",...t].filter(Boolean);return Y("/admin",...n)}var a=require("react/jsx-runtime");function b({basePath:e="",initPageResult:t,params:r,searchParams:n}){return(0,a.jsx)(g,{initPageResult:t,params:r,searchParams:n,children:(0,a.jsx)(p.Gutter,{children:(0,a.jsx)(K,{basePath:e,initPageResult:t})})})}function K({basePath:e,initPageResult:t}){let r=f(t.req.payload);if(!r)return(0,a.jsx)("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=m(r.permissions);if(!n.audiences.read)return(0,a.jsx)("p",{role:"alert",children:"You do not have permission to view audiences."});let i=r.adapter.urls?.audiences;return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)("header",{className:"flex flex-col gap-4",children:[(0,a.jsx)("h1",{children:"Audiences"}),i?(0,a.jsxs)(p.Link,{href:i,rel:"noreferrer noopener",target:"_blank",children:["View audiences in ",r.adapter.label]}):null]}),(0,a.jsxs)("div",{className:"mt-4 flex flex-col gap-8",children:[n.audiences.write?(0,a.jsx)("div",{children:(0,a.jsx)(w.CreateAudienceButton,{})}):null,(0,a.jsx)(N.Suspense,{fallback:(0,a.jsx)("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:(0,a.jsx)(W,{audiencesWrite:n.audiences.write,basePath:e,initPageResult:t})})]})]})}async function W({audiencesWrite:e,basePath:t,initPageResult:r}){let{adapter:n}=u(r.req.payload),i=await n.audiences.list(),d={Heading:"Name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:i.map(c=>(0,a.jsx)("div",{children:(0,a.jsx)(p.Link,{href:T(t,"audience",c.id),children:c.name})},c.id))},l={Heading:"",accessor:"",active:!0,field:{name:"_delete",type:"text"},renderedCells:i.map(c=>(0,a.jsx)("div",{children:(0,a.jsx)(w.DeleteAudienceButton,{audienceId:c.id,audienceName:c.name})},c.id))};return(0,a.jsx)(p.Table,{columns:e?[d,l]:[d],data:i})}var h=require("@payloadcms/ui"),v=require("payload-plugin-marketing/admin/client"),x=require("react");function j(e){let{label:t,code:r}=e;if(typeof t=="string")return t;if(t&&typeof t=="object"){for(let n of Object.values(t))if(typeof n=="string")return n}return r}function D(e){let t=e.localization;if(t===!1||t===void 0)return[];let r=t.locales;return r?.length?r.map(n=>({label:j(n),value:n.code})):[]}var o=require("react/jsx-runtime");function A({initPageResult:e,params:t,searchParams:r}){return(0,o.jsx)(g,{initPageResult:e,params:t,searchParams:r,children:(0,o.jsx)(h.Gutter,{children:(0,o.jsx)(J,{initPageResult:e})})})}function J({initPageResult:e}){let t=f(e.req.payload);if(!t)return(0,o.jsx)("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let r=m(t.permissions);if(!r.broadcasts.read)return(0,o.jsx)("p",{role:"alert",children:"You do not have permission to view broadcasts."});let{adapter:n}=u(e.req.payload),i=n.urls?.broadcasts;return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsxs)("header",{className:"flex flex-col gap-4",children:[(0,o.jsx)("h1",{children:"Campaigns"}),i?(0,o.jsxs)(h.Link,{href:i,rel:"noreferrer noopener",target:"_blank",children:["View campaigns in ",n.label]}):null]}),(0,o.jsxs)("div",{className:"mt-4 flex flex-col gap-8",children:[r.broadcasts.write?(0,o.jsx)("div",{children:(0,o.jsx)(x.Suspense,{fallback:(0,o.jsx)("div",{"aria-busy":!0,style:{minHeight:"2.5rem"}}),children:(0,o.jsx)(Q,{initPageResult:e})})}):null,(0,o.jsx)(x.Suspense,{fallback:(0,o.jsx)("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:(0,o.jsx)(X,{initPageResult:e})})]})]})}async function Q({initPageResult:e}){let t=u(e.req.payload),{adapter:r}=t,n=await r.audiences.list(),i=t.emailBroadcastTemplates?.map(({id:l,name:c})=>({id:l,name:c}))??[],d=D(e.req.payload.config);return(0,o.jsx)(v.CreateBroadcastButton,{audiences:n,emailBroadcastTemplates:i,localeOptions:d,provider:r.provider})}async function X({initPageResult:e}){let{adapter:t}=u(e.req.payload),n=(await t.broadcasts.list()).map(i=>({...i,externalDashboardUrl:t.urls?.broadcast?.(i.id)}));return(0,o.jsx)(v.BroadcastsTable,{broadcasts:n})}0&&(module.exports={AudienceDetail,AudienceList,BroadcastList});
|
|
2
2
|
//# sourceMappingURL=server.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/server.ts","../../src/admin/components/audience-detail.tsx","../../src/admin/paths.ts","../../src/admin/use-marketing-api.ts","../../src/admin/components/broadcasts-table.tsx","../../src/admin/date-format.ts","../../src/admin/components/payload-modal.tsx","../../src/admin/components/audience-buttons.tsx","../../src/admin/components/contacts-table.tsx","../../src/admin/components/create-broadcast-button.tsx","../../src/marketing-integration.ts","../../src/admin/components/marketing-view-shell.tsx","../../src/admin/components/view-params.ts","../../src/admin/components/audience-list.tsx","../../src/admin/components/broadcast-list.tsx","../../src/admin/locale-options.ts"],"sourcesContent":["export { AudienceDetail, AudienceList, BroadcastList } from \"./components/views\"\n","import { Gutter, Link } from \"@payloadcms/ui\"\nimport { notFound } from \"next/navigation\"\nimport { AudienceContactsTable, EditContactButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 <AudienceContactsTable audienceId={audienceId} contacts={contacts} />\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","\"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(\n () => `${context.serverURL ?? \"\"}${context.routes?.api ?? \"/api\"}`,\n [context.routes?.api, 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 (restInit.body !== undefined && restInit.body !== \"\" && restInit.body !== null) {\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","\"use client\"\n\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\"\nimport React from \"react\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport { useMarketingApi } from \"../use-marketing-api\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\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) => (\n <div key={b.id}>{formatMarketingDate(b.sentAt)}</div>\n )),\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\n href={broadcast.externalDashboardUrl}\n rel=\"noreferrer noopener\"\n target=\"_blank\"\n >\n <Pill>dashboard ↗</Pill>\n </Link>\n ) : null}\n {broadcast.status === \"draft\" || broadcast.status === \"save\" ? (\n <>\n <DeleteBroadcastButton\n broadcastId={broadcast.id}\n broadcastName={broadcast.name}\n />\n <SendBroadcastButton\n broadcastId={broadcast.id}\n broadcastName={broadcast.name}\n />\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)}`, {\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>{`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\n style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}\n >\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","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 { Button, Modal, useModal, useTranslation } from \"@payloadcms/ui\"\nimport React from \"react\"\n\nfunction cn(...parts: Array<string | undefined | false | null>): string {\n return parts.filter(Boolean).join(\" \")\n}\n\nconst PayloadModalContext = React.createContext({\n modalSlug: \"\",\n})\n\ninterface PayloadModalProps extends React.ComponentProps<typeof Modal> {\n children: React.ReactNode\n}\n\nfunction PayloadModal({ children, 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 {/* Fix hydration error */}\n {loaded && (\n <Modal slug={modalSlug} className={cn(\"confirmation-modal\", className)} {...props}>\n {children}\n </Modal>\n )}\n </PayloadModalContext.Provider>\n )\n}\n\nfunction PayloadModalContent({ children, className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"confirmation-modal__wrapper\", className)}\n data-slot=\"payload-modal-content\"\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction PayloadModalBody({ children, className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"confirmation-modal__content\", className)}\n data-slot=\"payload-modal-body\"\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction PayloadModalTitle({ children, className, ...props }: React.ComponentProps<\"h1\">) {\n return (\n <h1 className={cn(\"\", className)} data-slot=\"payload-modal-title\" {...props}>\n {children}\n </h1>\n )\n}\n\nfunction PayloadModalFooter({ children, className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"confirmation-modal__controls\", className)}\n data-slot=\"payload-modal-footer\"\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction PayloadModalClose({ children, 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 className={cn(\"\", className)}\n buttonStyle=\"secondary\"\n size=\"large\"\n data-slot=\"payload-modal-close\"\n {...props}\n onClick={() => modal.closeModal(modalSlug)}\n >\n {children ?? t(\"general:cancel\")}\n </Button>\n )\n}\n\nexport {\n PayloadModal,\n PayloadModalContent,\n PayloadModalBody,\n PayloadModalTitle,\n PayloadModalFooter,\n PayloadModalClose,\n}\n","\"use client\"\n\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\"\nimport { useTransition } from \"react\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\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) =>\n typeof v === \"string\" && v.trim().length > 0 ? true : \"Name is required\"\n }\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","\"use client\"\n\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 React from \"react\"\nimport ReactRaw from \"react\"\nimport { useTransition } from \"react\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport { useMarketingApi } from \"../use-marketing-api\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n} from \"./payload-modal\"\n\nimport type { MarketingContact } from \"../../types\"\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(\n `/marketing/audiences/${encodeURIComponent(audienceId)}/contacts/${encodeURIComponent(contactId)}`,\n {\n method: \"DELETE\",\n },\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\n {...(contact ? {} : { size: \"large\" })}\n onClick={() => modal.openModal(slug)}\n type=\"button\"\n >\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) =>\n typeof v === \"string\" && v.includes(\"@\") ? true : \"Valid email required\"\n }\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","\"use client\"\n\nimport {\n Button,\n Drawer,\n Form,\n SelectField,\n TextareaField,\n TextField,\n toast,\n useFormFields,\n useModal,\n useTranslation,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\nimport React from \"react\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingAudience } from \"../../types\"\nimport type { Data, FormState } from \"payload\"\n\nconst modalSlug = \"create-marketing-broadcast\"\n\nexport function CreateBroadcastButton({\n audiences,\n emailBroadcastTemplates,\n localeOptions,\n provider,\n}: {\n audiences: MarketingAudience[]\n emailBroadcastTemplates?: { id: string; name: string }[]\n localeOptions?: { label: string; value: string }[]\n provider: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n\n return (\n <>\n <CreateBroadcastModal\n audiences={audiences}\n emailBroadcastTemplates={emailBroadcastTemplates}\n localeOptions={localeOptions ?? []}\n provider={provider}\n />\n <Button onClick={() => modal.openModal(modalSlug)} size=\"large\" type=\"button\">\n {t(\"general:createNew\")}\n </Button>\n </>\n )\n}\n\nfunction BroadcastContentFields({\n localeOptions,\n showReactEmailTemplates,\n showTemplateField,\n templateOptions,\n}: {\n localeOptions: { label: string; value: string }[]\n showReactEmailTemplates: boolean\n showTemplateField: boolean\n templateOptions: { id: string; name: string }[]\n}) {\n const broadcastFormat = useFormFields(([fields]) => {\n if (!showReactEmailTemplates) {\n return \"html\"\n }\n const v = fields?.broadcastFormat?.value\n return typeof v === \"string\" && v !== \"\" ? v : \"html\"\n })\n\n if (showReactEmailTemplates) {\n const isHtml = broadcastFormat === \"html\"\n return (\n <>\n <SelectField\n field={{\n label: \"Email content\",\n name: \"broadcastFormat\",\n options: [\n { label: \"<html>\", value: \"html\" },\n ...templateOptions.map((opt) => ({ label: opt.name, value: opt.id })),\n ],\n required: true,\n }}\n path=\"broadcastFormat\"\n />\n {!isHtml && localeOptions.length > 0 ? (\n <SelectField\n field={{\n label: \"Locale\",\n name: \"locale\",\n options: localeOptions,\n required: false,\n }}\n path=\"locale\"\n />\n ) : null}\n {isHtml ? (\n <TextareaField\n field={{\n admin: {\n description: \"Shown when Email content is <html>.\",\n },\n label: \"<html>\",\n name: \"htmlBody\",\n required: true,\n }}\n path=\"htmlBody\"\n />\n ) : null}\n </>\n )\n }\n\n return (\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 <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> (optional with Mailchimp)\" : \"<html>\",\n name: \"htmlBody\",\n required: !showTemplateField,\n }}\n path=\"htmlBody\"\n />\n </>\n )\n}\n\nfunction CreateBroadcastModal({\n audiences,\n emailBroadcastTemplates,\n localeOptions,\n provider,\n}: {\n audiences: MarketingAudience[]\n emailBroadcastTemplates?: { id: string; name: string }[]\n localeOptions: { label: string; value: string }[]\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 const templateOptions = emailBroadcastTemplates ?? []\n const showReactEmailTemplates = provider === \"resend\" && templateOptions.length > 0\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 broadcastFormatRaw: unknown = row.broadcastFormat\n const localeRaw: unknown = row.locale\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 const broadcastFormat =\n typeof broadcastFormatRaw === \"string\" ? broadcastFormatRaw.trim() : \"html\"\n const locale = typeof localeRaw === \"string\" ? localeRaw.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\n const mailchimpMode = showTemplateField\n const usingReactTemplate = showReactEmailTemplates && broadcastFormat !== \"html\"\n\n if (showReactEmailTemplates) {\n if (usingReactTemplate) {\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n emailTemplateId: broadcastFormat,\n locale: locale || undefined,\n name,\n replyTo,\n subject,\n }),\n method: \"POST\",\n })\n } else if (!htmlBody) {\n throw new Error(\"<html> is required when using the <html> content option.\")\n } else {\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n html: htmlBody,\n name,\n replyTo,\n subject,\n }),\n method: \"POST\",\n })\n }\n } else if (mailchimpMode) {\n if (!templateId && !htmlBody) {\n throw new Error(\"Provide <html> or a Mailchimp template id.\")\n }\n if (templateId && htmlBody) {\n throw new Error(\"Use either <html> or Mailchimp template id, not both.\")\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 } else if (!htmlBody) {\n throw new Error(\"<html> is required for this provider.\")\n } else {\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n html: htmlBody,\n name,\n replyTo,\n subject,\n }),\n method: \"POST\",\n })\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={showReactEmailTemplates ? { broadcastFormat: { value: \"html\" } } : {}}\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 <BroadcastContentFields\n localeOptions={localeOptions}\n showReactEmailTemplates={showReactEmailTemplates}\n showTemplateField={showTemplateField}\n templateOptions={templateOptions}\n />\n\n <Button className=\"w-full\" disabled={isPending} type=\"submit\">\n {t(\"general:create\")}\n </Button>\n </Form>\n </Drawer>\n )\n}\n","import type {\n MarketingAdapter,\n MarketingEffectivePermissions,\n MarketingEmailBroadcastTemplate,\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 emailBroadcastTemplates?: MarketingEmailBroadcastTemplate[]\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(\n payload: Payload,\n): MarketingIntegrationState | undefined {\n return readIntegration(payload)\n}\n\nexport function getMarketingIntegrationFromRequest(req: PayloadRequest): MarketingIntegrationState {\n return getMarketingIntegration(req.payload)\n}\n","import { DefaultTemplate } from \"@payloadcms/next/templates\"\n\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 { Gutter, Link, Table } from \"@payloadcms/ui\"\nimport { CreateAudienceButton, DeleteAudienceButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { marketingAdminHref } from \"../paths\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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","import { Gutter, Link } from \"@payloadcms/ui\"\nimport {\n BroadcastsTable,\n CreateBroadcastButton,\n type MarketingBroadcastRow,\n} from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { getLocaleSelectOptionsFromConfig } from \"../locale-options\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 integration = getMarketingIntegration(initPageResult.req.payload)\n const { adapter } = integration\n const audiences = await adapter.audiences.list()\n const emailBroadcastTemplates =\n integration.emailBroadcastTemplates?.map(({ id, name }) => ({ id, name })) ?? []\n const localeOptions = getLocaleSelectOptionsFromConfig(initPageResult.req.payload.config)\n return (\n <CreateBroadcastButton\n audiences={audiences}\n emailBroadcastTemplates={emailBroadcastTemplates}\n localeOptions={localeOptions}\n provider={adapter.provider}\n />\n )\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","import type { Locale, SanitizedConfig } from \"payload\"\n\nfunction labelForLocale(loc: Locale): string {\n const { label, code } = loc\n if (typeof label === \"string\") {\n return label\n }\n if (label && typeof label === \"object\") {\n for (const value of Object.values(label)) {\n if (typeof value === \"string\") {\n return value\n }\n }\n }\n return code\n}\n\n/** Options for admin selects; values are locale codes from `config.localization.locales`. */\nexport function getLocaleSelectOptionsFromConfig(\n config: SanitizedConfig,\n): { label: string; value: string }[] {\n const raw = config.localization\n if (raw === false || raw === undefined) {\n return []\n }\n const locales = raw.locales\n if (!locales?.length) {\n return []\n }\n return locales.map((locItem: Locale) => ({\n label: labelForLocale(locItem),\n value: locItem.code,\n }))\n}\n"],"mappings":"ykBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,oBAAAE,GAAA,iBAAAC,GAAA,kBAAAC,KAAA,eAAAC,GAAAL,ICAA,IAAAM,GAA6B,0BAC7BC,GAAyB,2BCDlB,SAASC,GAAkBC,KAAuBC,EAA4B,CACnF,IAAMC,EAAeF,EAAW,QAAQ,OAAQ,EAAE,GAAK,GACjDG,EAAOF,EACV,QAASG,GAAM,OAAOA,CAAC,EAAE,MAAM,GAAG,CAAC,EACnC,IAAKC,GAAYA,EAAQ,QAAQ,aAAc,EAAE,CAAC,EAClD,OAAO,OAAO,EACd,KAAK,GAAG,EAEX,OADiBH,IAAiB,GAAK,IAAIC,CAAI,GAAK,GAAGD,CAAY,IAAIC,CAAI,IAC3D,QAAQ,UAAW,GAAG,CACxC,CAGO,SAASG,GAAmBC,KAAiCN,EAA4B,CAE9F,IAAMO,EAAQ,CADKD,GAAU,QAAQ,aAAc,EAAE,GAAK,GAC/B,GAAGN,CAAQ,EAAE,OAAO,OAAO,EACtD,OAAOF,GAAkB,SAAU,GAAGS,CAAK,CAC7C,CCdA,IAAAC,GAA0B,0BAC1BC,EAAqC,iBAE9B,SAASC,GAAkB,CAChC,IAAMC,KAAU,cAAU,EAKpBC,KAAO,WACX,IAAM,GAAGD,EAAQ,WAAa,EAAE,GAAGA,EAAQ,QAAQ,KAAO,MAAM,GAChE,CAACA,EAAQ,QAAQ,IAAKA,EAAQ,SAAS,CACzC,EAEME,KAAc,eAClB,MAAOC,EAAqBC,IAAyC,CACnE,GAAM,CAAE,QAASC,EAAiB,GAAGC,CAAS,EAAIF,GAAQ,CAAC,EACrDG,EAAU,IAAI,QAAQH,GAAM,OAAO,EACrCE,EAAS,OAAS,QAAaA,EAAS,OAAS,IAAMA,EAAS,OAAS,OACtEC,EAAQ,IAAI,cAAc,GAC7BA,EAAQ,IAAI,eAAgB,kBAAkB,GAIlD,IAAMC,EAAM,MAAM,MAAM,GAAGP,CAAI,GAAGE,CAAW,GAAI,CAC/C,GAAGG,EACH,YAAa,UACb,QAAAC,CACF,CAAC,EAED,GAAI,CAACC,EAAI,GAAI,CACX,IAAIC,EAAS,GAAGD,EAAI,MAAM,IAAIA,EAAI,UAAU,GAC5C,GAAI,CACF,IAAME,EAAU,MAAMF,EAAI,KAAK,EAC3B,OAAOE,EAAO,SAAY,WAAUD,EAASC,EAAO,QAC1D,MAAQ,CAER,CACA,MAAM,IAAI,MAAMD,CAAM,CACxB,CAEA,GAAID,EAAI,SAAW,IAInB,GAAI,CACF,OAAO,MAAMA,EAAI,KAAK,CACxB,MAAQ,CACN,MACF,CACF,EACA,CAACP,CAAI,CACP,EAEA,MAAO,CAAE,KAAAA,EAAM,YAAAC,CAAY,CAC7B,CCvDA,IAAAS,EAUO,0BACPC,GAAiB,0BACjBC,GAA0B,2BAC1BC,GAAkB,sBCfX,SAASC,EAAoBC,EAA6B,CAC/D,GAAI,CAACA,EAAK,MAAO,SACjB,IAAMC,EAAI,IAAI,KAAKD,CAAG,EACtB,OAAO,OAAO,MAAMC,EAAE,QAAQ,CAAC,EAC3B,OAAOD,CAAG,EACV,IAAI,KAAK,eAAe,OAAW,CAAE,UAAW,QAAS,CAAC,EAAE,OAAOC,CAAC,CAC1E,CCJA,IAAAC,EAAwD,0BACxDC,EAAkB,sBAyBVC,EAAA,6BAvBR,SAASC,KAAMC,EAAyD,CACtE,OAAOA,EAAM,OAAO,OAAO,EAAE,KAAK,GAAG,CACvC,CAEA,IAAMC,GAAsB,EAAAC,QAAM,cAAc,CAC9C,UAAW,EACb,CAAC,EAMD,SAASC,EAAa,CAAE,SAAAC,EAAU,UAAAC,EAAW,KAAMC,EAAW,GAAGC,CAAM,EAAsB,CAC3F,GAAM,CAACC,EAAQC,CAAS,EAAI,EAAAP,QAAM,SAAS,EAAK,EAEhD,SAAAA,QAAM,UAAU,IAAM,CACpBO,EAAU,EAAI,CAChB,EAAG,CAAC,CAAC,KAGH,OAACR,GAAoB,SAApB,CAA6B,MAAO,CAAE,UAAAK,CAAU,EAE9C,SAAAE,MACC,OAAC,SAAM,KAAMF,EAAW,UAAWP,EAAG,qBAAsBM,CAAS,EAAI,GAAGE,EACzE,SAAAH,EACH,EAEJ,CAEJ,CAEA,SAASM,EAAoB,CAAE,SAAAN,EAAU,UAAAC,EAAW,GAAGE,CAAM,EAAgC,CAC3F,SACE,OAAC,OACC,UAAWR,EAAG,8BAA+BM,CAAS,EACtD,YAAU,wBACT,GAAGE,EAEH,SAAAH,EACH,CAEJ,CAEA,SAASO,EAAiB,CAAE,SAAAP,EAAU,UAAAC,EAAW,GAAGE,CAAM,EAAgC,CACxF,SACE,OAAC,OACC,UAAWR,EAAG,8BAA+BM,CAAS,EACtD,YAAU,qBACT,GAAGE,EAEH,SAAAH,EACH,CAEJ,CAEA,SAASQ,EAAkB,CAAE,SAAAR,EAAU,UAAAC,EAAW,GAAGE,CAAM,EAA+B,CACxF,SACE,OAAC,MAAG,UAAWR,EAAG,GAAIM,CAAS,EAAG,YAAU,sBAAuB,GAAGE,EACnE,SAAAH,EACH,CAEJ,CAEA,SAASS,EAAmB,CAAE,SAAAT,EAAU,UAAAC,EAAW,GAAGE,CAAM,EAAgC,CAC1F,SACE,OAAC,OACC,UAAWR,EAAG,+BAAgCM,CAAS,EACvD,YAAU,uBACT,GAAGE,EAEH,SAAAH,EACH,CAEJ,CAEA,SAASU,EAAkB,CAAE,SAAAV,EAAU,UAAAC,EAAW,GAAGE,CAAM,EAAwC,CACjG,GAAM,CAAE,EAAAQ,CAAE,KAAI,kBAAe,EACvB,CAAE,UAAAT,CAAU,EAAI,EAAAJ,QAAM,WAAWD,EAAmB,EACpDe,KAAQ,YAAS,EAEvB,SACE,OAAC,UACC,UAAWjB,EAAG,GAAIM,CAAS,EAC3B,YAAY,YACZ,KAAK,QACL,YAAU,sBACT,GAAGE,EACJ,QAAS,IAAMS,EAAM,WAAWV,CAAS,EAExC,SAAAF,GAAYW,EAAE,gBAAgB,EACjC,CAEJ,CFzCkD,IAAAE,EAAA,6BAjB3C,SAASC,GAAgB,CAAE,WAAAC,CAAW,EAAyB,CACpE,GAAM,CAACC,EAAMC,CAAO,EAAI,GAAAC,QAAM,SAAS,CAAC,EAClC,CAACC,CAAK,EAAI,GAAAD,QAAM,SAAS,GAAG,EAC5BE,EAAc,GAAAF,QAAM,QACxB,IAAMH,EAAW,OAAOC,EAAO,GAAKG,EAAOH,EAAOG,CAAK,EACvD,CAACJ,EAAYI,EAAOH,CAAI,CAC1B,EAEA,SACE,oBACE,oBAAC,SACC,QAAS,CACP,CACE,QAAS,gBACT,SAAU,OACV,OAAQ,GACR,MAAO,CAAE,KAAM,OAAQ,KAAM,MAAO,EACpC,cAAeI,EAAY,IAAKC,MAAM,OAAC,OAAgB,SAAAA,EAAE,MAATA,EAAE,EAAY,CAAM,CACtE,EACA,CACE,QAAS,gBACT,SAAU,cACV,OAAQ,GACR,MAAO,CAAE,KAAM,cAAe,KAAM,MAAO,EAC3C,cAAeD,EAAY,IAAKC,MAC9B,OAAC,OAAgB,SAAAC,EAAoBD,EAAE,WAAW,GAAxCA,EAAE,EAAwC,CACrD,CACH,EACA,CACE,QAAS,YACT,SAAU,SACV,OAAQ,GACR,MAAO,CAAE,KAAM,SAAU,KAAM,MAAO,EACtC,cAAeD,EAAY,IAAKC,MAC9B,OAAC,OAAgB,SAAAC,EAAoBD,EAAE,MAAM,GAAnCA,EAAE,EAAmC,CAChD,CACH,EACA,CACE,QAAS,SACT,SAAU,SACV,OAAQ,GACR,MAAO,CAAE,KAAM,SAAU,KAAM,MAAO,EACtC,cAAeD,EAAY,IAAKG,MAC9B,OAAC,OACC,mBAACC,GAAA,CAAoB,OAAQD,EAAU,OAAQ,GADvCA,EAAU,EAEpB,CACD,CACH,EACA,CACE,QAAS,GACT,SAAU,GACV,OAAQ,GACR,MAAO,CAAE,KAAM,IAAK,KAAM,MAAO,EACjC,cAAeH,EAAY,IAAKG,MAC9B,QAAC,OAAuB,UAAU,oCAC/B,UAAAA,EAAU,wBACT,OAAC,GAAAE,QAAA,CACC,KAAMF,EAAU,qBAChB,IAAI,sBACJ,OAAO,SAEP,mBAAC,QAAK,4BAAW,EACnB,EACE,KACHA,EAAU,SAAW,SAAWA,EAAU,SAAW,UACpD,oBACE,oBAACG,GAAA,CACC,YAAaH,EAAU,GACvB,cAAeA,EAAU,KAC3B,KACA,OAACI,GAAA,CACC,YAAaJ,EAAU,GACvB,cAAeA,EAAU,KAC3B,GACF,EACE,OArBIA,EAAU,EAsBpB,CACD,CACH,CACF,EACA,KAAMH,EACR,KACA,OAAC,cACC,YAAaJ,EAAOG,EAAQJ,EAAW,OACvC,YAAaC,EAAO,EACpB,MAAOG,EACP,SAAWS,GAAMX,EAAQW,CAAC,EAC1B,KAAMZ,EACN,WAAY,KAAK,KAAKD,EAAW,OAASI,CAAK,EACjD,GACF,CAEJ,CAEA,SAASK,GAAoB,CAAE,OAAAK,CAAO,EAAuB,CAC3D,OAAQA,EAAQ,CACd,IAAK,QACL,IAAK,OACH,SAAO,OAAC,QAAK,UAAU,aAAa,iBAAK,EAE3C,IAAK,SACH,SAAO,OAAC,QAAK,UAAU,QAAQ,kBAAM,EAEvC,IAAK,OACH,SAAO,OAAC,QAAK,UAAU,UAAU,gBAAI,EAEvC,QACE,SAAO,OAAC,QAAM,SAAAA,EAAO,CAEzB,CACF,CAEA,SAASH,GAAsB,CAC7B,YAAAI,EACA,cAAAC,CACF,EAGG,CACD,IAAMC,KAAQ,YAAS,EACjB,CAAE,EAAAC,CAAE,KAAI,kBAAe,EACvBC,KAAS,cAAU,EACnB,CAAE,YAAAC,CAAY,EAAIC,EAAgB,EAClCC,EAAY,oBAAoBP,CAAW,GAEjD,eAAeQ,GAA+B,CAC5C,MAAMH,EAAY,yBAAyB,mBAAmBL,CAAW,CAAC,GAAI,CAC5E,OAAQ,QACV,CAAC,EACD,QAAM,QAAQG,EAAE,6BAA6B,CAAC,EAC9CD,EAAM,WAAWK,CAAS,EAC1BH,EAAO,QAAQ,CACjB,CAEA,SACE,oBACE,oBAACK,EAAA,CAAa,KAAMF,EAClB,oBAACG,EAAA,CACC,qBAACC,EAAA,CACC,oBAACC,EAAA,CAAmB,SAAAT,EAAE,yBAAyB,EAAE,KACjD,OAAC,KAAG,oCAA2BF,CAAa,KAAK,GACnD,KACA,QAACY,EAAA,CAAmB,MAAO,CAAE,QAAS,OAAQ,IAAK,MAAO,eAAgB,UAAW,EACnF,oBAACC,EAAA,EAAkB,KACnB,OAAC,EAAAC,OAAA,CACC,YAAY,QACZ,QAAS,IAAM,CACRP,EAAc,EAAE,MAAOQ,GAC1B,QAAM,MAAMA,aAAe,MAAQA,EAAI,QAAU,eAAe,CAClE,CACF,EAEC,SAAAb,EAAE,iBAAiB,EACtB,GACF,GACF,EACF,KACA,OAAC,UAAO,QAAS,IAAMD,EAAM,UAAUK,CAAS,EAAG,KAAK,SACrD,SAAAJ,EAAE,gBAAgB,EACrB,GACF,CAEJ,CAEO,SAASN,GAAoB,CAClC,YAAAG,EACA,cAAAC,CACF,EAGG,CACD,IAAMC,KAAQ,YAAS,EACjB,CAAE,EAAAC,CAAE,KAAI,kBAAe,EACvBC,KAAS,cAAU,EACnB,CAAE,YAAAC,CAAY,EAAIC,EAAgB,EAClCC,EAAY,kBAAkBP,CAAW,GAEzCiB,EAAS,CAACC,EAAmBC,IAAe,CAEhD,IAAMC,EADMD,EACsB,YAC9BE,EAAc,GACd,OAAOD,GAAiB,SAC1BC,EAAcD,EACLA,aAAwB,OACjCC,EAAcD,EAAa,YAAY,IAGnC,SAAY,CAChB,GAAI,CACF,MAAMf,EAAY,yBAAyB,mBAAmBL,CAAW,CAAC,QAAS,CACjF,KAAM,KAAK,UAAU,CACnB,GAAIqB,GAAeA,EAAY,KAAK,IAAM,GACtC,CAAE,YAAaA,EAAY,KAAK,CAAE,EAClC,CAAC,CACP,CAAC,EACD,OAAQ,MACV,CAAC,EACDnB,EAAM,WAAWK,CAAS,EAC1B,QAAM,QAAQJ,EAAE,iBAAiB,CAAC,EAClCC,EAAO,QAAQ,CACjB,OAASY,EAAK,CACZ,QAAM,MAAMA,aAAe,MAAQA,EAAI,QAAU,aAAa,CAChE,CACF,GAAG,CACL,EAEA,SACE,oBACE,oBAACP,EAAA,CAAa,KAAMF,EAClB,mBAACG,EAAA,CAAoB,MAAO,CAAE,MAAO,OAAQ,SAAU,OAAQ,EAC7D,oBAACC,EAAA,CACC,oBAACC,EAAA,CAAmB,uBAASX,CAAa,SAAI,KAC9C,QAAC,QAAK,aAAc,CAAC,EAAG,SAAUgB,EAAQ,oBAAmB,GAC3D,oBAAC,iBACC,MAAO,CACL,MAAO,yBACP,KAAM,cACN,SAAU,EACZ,EACA,KAAK,cACP,KACA,QAACJ,EAAA,CACC,MAAO,CAAE,QAAS,OAAQ,IAAK,MAAO,eAAgB,UAAW,EAEjE,oBAACC,EAAA,EAAkB,KACnB,OAAC,EAAAC,OAAA,CAAc,KAAK,QAAQ,KAAK,SAAS,gBAE1C,GACF,GACF,GACF,EACF,EACF,KACA,OAAC,QAAK,UAAU,OAAO,QAAS,IAAMb,EAAM,UAAUK,CAAS,EAAG,KAAK,QAAQ,gBAE/E,GACF,CAEJ,CGnRA,IAAAe,EAQO,0BACPC,GAA0B,2BAC1BC,GAA8B,iBAqB1B,IAAAC,EAAA,6BAPEC,GAAqB,kBAEpB,SAASC,IAAuB,CACrC,IAAMC,KAAQ,YAAS,EACjB,CAAE,CAAE,KAAI,kBAAe,EAE7B,SACE,oBACE,oBAACC,GAAA,EAAoB,KACrB,OAAC,UAAO,QAAS,IAAMD,EAAM,UAAUF,EAAkB,EAAG,KAAK,QAAQ,KAAK,SAC3E,WAAE,mBAAmB,EACxB,GACF,CAEJ,CAEA,SAASG,IAAsB,CAC7B,IAAMD,KAAQ,YAAS,EACjB,CAAE,CAAE,KAAI,kBAAe,EACvBE,KAAS,cAAU,EACnB,CAAE,YAAAC,CAAY,EAAIC,EAAgB,EAClC,CAACC,EAAWC,CAAe,KAAI,kBAAc,EA0BnD,SACE,OAACC,EAAA,CAAa,YAAW,GAAC,KAAMT,GAC9B,mBAACU,EAAA,CAAoB,MAAO,CAAE,MAAO,OAAQ,SAAU,OAAQ,EAC7D,mBAAC,QAAK,aAAc,CAAC,EAAG,SA3Bf,CAACC,EAAmBC,IAAe,CAEhD,IAAMC,EADMD,EACiB,aACvBE,EAAO,OAAOD,GAAY,SAAWA,EAAQ,KAAK,EAAI,GAC5DL,EAAgB,IAAM,EACd,SAAY,CAChB,GAAI,CACF,GAAI,CAACM,EACH,MAAM,IAAI,MAAM,mBAAmB,EAErC,MAAMT,EAAY,uBAAwB,CACxC,KAAM,KAAK,UAAU,CAAE,KAAAS,CAAK,CAAC,EAC7B,OAAQ,MACV,CAAC,EACDZ,EAAM,WAAWF,EAAkB,EACnC,QAAM,QAAQ,EAAE,6BAA6B,CAAC,EAC9CI,EAAO,QAAQ,CACjB,OAASW,EAAK,CACZ,QAAM,MAAMA,aAAe,MAAQA,EAAI,QAAU,eAAe,CAClE,CACF,GAAG,CACL,CAAC,CACH,EAKgD,oBAAmB,GAC3D,oBAACC,EAAA,CACC,oBAACC,EAAA,CAAmB,WAAE,mBAAmB,EAAE,KAC3C,OAAC,aACC,MAAO,CACL,KAAM,eACN,SAAU,GACV,KAAM,MACR,EACA,KAAK,eACL,SAAWC,GACT,OAAOA,GAAM,UAAYA,EAAE,KAAK,EAAE,OAAS,EAAI,GAAO,mBAE1D,KACA,QAACC,EAAA,CAAmB,MAAO,CAAE,QAAS,OAAQ,IAAK,MAAO,eAAgB,UAAW,EACnF,oBAACC,EAAA,EAAkB,KACnB,OAAC,UAAO,SAAUb,EAAW,KAAK,QAAQ,KAAK,SAC5C,WAAE,iBAAiB,EACtB,GACF,GACF,EACF,EACF,EACF,CAEJ,CAEO,SAASc,GAAqB,CACnC,WAAAC,EACA,aAAAC,CACF,EAGG,CACD,IAAMrB,KAAQ,YAAS,EACjB,CAAE,EAAAsB,CAAE,KAAI,kBAAe,EACvBpB,KAAS,cAAU,EACnB,CAAE,YAAAC,CAAY,EAAIC,EAAgB,EAClCmB,EAAY,mBAAmBH,CAAU,GAE/C,eAAeI,GAA+B,CAC5C,MAAMrB,EAAY,wBAAwB,mBAAmBiB,CAAU,CAAC,GAAI,CAC1E,OAAQ,QACV,CAAC,EACD,QAAM,QAAQE,EAAE,6BAA6B,CAAC,EAC9CtB,EAAM,WAAWuB,CAAS,EAC1BrB,EAAO,QAAQ,CACjB,CAEA,SACE,oBACE,oBAACK,EAAA,CAAa,KAAMgB,EAClB,oBAACf,EAAA,CACC,qBAACM,EAAA,CACC,oBAACC,EAAA,CAAmB,SAAAO,EAAE,yBAAyB,EAAE,KACjD,OAAC,KAAG,6BAAoBD,CAAY,KAAK,GAC3C,KACA,QAACJ,EAAA,CAAmB,MAAO,CAAE,QAAS,OAAQ,IAAK,MAAO,eAAgB,UAAW,EACnF,oBAACC,EAAA,EAAkB,KACnB,OAAC,EAAAO,OAAA,CACC,YAAY,QACZ,QAAS,IAAM,CACRD,EAAc,EAAE,MAAOX,GAC1B,QAAM,MAAMA,aAAe,MAAQA,EAAI,QAAU,eAAe,CAClE,CACF,EAEC,SAAAS,EAAE,iBAAiB,EACtB,GACF,GACF,EACF,KACA,OAAC,UAAO,QAAS,IAAMtB,EAAM,UAAUuB,CAAS,EAAG,KAAK,SACrD,SAAAD,EAAE,gBAAgB,EACrB,GACF,CAEJ,CCvJA,IAAAI,EAUO,0BACPC,GAA0B,2BAC1BC,GAAkB,sBAClBA,GAAqB,sBACrBA,GAA8B,iBA6B1B,IAAAC,EAAA,6BATG,SAASC,GAAc,CAAE,WAAAC,EAAY,SAAAC,CAAS,EAAuB,CAC1E,GAAM,CAACC,EAAMC,CAAO,EAAI,GAAAC,QAAM,SAAS,CAAC,EAClC,CAACC,CAAK,EAAI,GAAAD,QAAM,SAAS,GAAG,EAC5BE,EAAc,GAAAF,QAAM,QACxB,IAAMH,EAAS,OAAOC,EAAO,GAAKG,EAAOH,EAAOG,CAAK,EACrD,CAACJ,EAAUI,EAAOH,CAAI,CACxB,EAEA,SACE,oBACE,oBAAC,SACC,QAAS,CACP,CACE,QAAS,aACT,SAAU,YACV,OAAQ,GACR,MAAO,CAAE,KAAM,YAAa,KAAM,MAAO,EACzC,cAAeI,EAAY,IAAKC,MAC9B,OAAC,OAAsB,SAAAA,EAAQ,WAAa,UAAlCA,EAAQ,EAA8B,CACjD,CACH,EACA,CACE,QAAS,YACT,SAAU,WACV,OAAQ,GACR,MAAO,CAAE,KAAM,WAAY,KAAM,MAAO,EACxC,cAAeD,EAAY,IAAKC,MAC9B,OAAC,OAAsB,SAAAA,EAAQ,UAAY,UAAjCA,EAAQ,EAA6B,CAChD,CACH,EACA,CACE,QAAS,QACT,SAAU,QACV,OAAQ,GACR,MAAO,CAAE,KAAM,QAAS,KAAM,MAAO,EACrC,cAAeD,EAAY,IAAKC,MAC9B,OAAC,OAAsB,SAAAA,EAAQ,OAArBA,EAAQ,EAAmB,CACtC,CACH,EACA,CACE,QAAS,UACT,SAAU,YACV,OAAQ,GACR,MAAO,CAAE,KAAM,YAAa,KAAM,MAAO,EACzC,cAAeD,EAAY,IAAKC,MAC9B,OAAC,OAAsB,SAAAC,EAAoBD,EAAQ,SAAS,GAAlDA,EAAQ,EAA4C,CAC/D,CACH,EACA,CACE,QAAS,SACT,SAAU,aACV,OAAQ,GACR,MAAO,CAAE,KAAM,aAAc,KAAM,MAAO,EAC1C,cAAeD,EAAY,IAAKC,MAC9B,QAAC,OAAqB,UAAU,oCAC9B,oBAAC,QAAM,SAAAA,EAAQ,aAAe,GAAQ,oBAAiB,sBAAiB,KACxE,OAACE,GAAA,CAAkB,WAAYT,EAAY,QAASO,EAAS,KAC7D,OAACG,GAAA,CACC,WAAYV,EACZ,aAAcO,EAAQ,MACtB,UAAWA,EAAQ,GACrB,IAPQA,EAAQ,EAQlB,CACD,CACH,CACF,EACA,KAAMD,EACR,KACA,OAAC,cACC,YAAaJ,EAAOG,EAAQJ,EAAS,OACrC,YAAaC,EAAO,EACpB,MAAOG,EACP,SAAWM,GAAM,CACfR,EAAQQ,CAAC,CACX,EACA,KAAMT,EACN,WAAY,KAAK,KAAKD,EAAS,OAASI,CAAK,EAC/C,GACF,CAEJ,CAEA,SAASK,GAAoB,CAC3B,WAAAV,EACA,UAAAY,EACA,aAAAC,CACF,EAIG,CACD,IAAMC,KAAQ,YAAS,EACjB,CAAE,EAAAC,CAAE,KAAI,kBAAe,EACvBC,KAAS,cAAU,EACnB,CAAE,YAAAC,CAAY,EAAIC,EAAgB,EAClCC,EAAY,kBAAkBP,CAAS,GAE7C,eAAeQ,GAA+B,CAC5C,MAAMH,EACJ,wBAAwB,mBAAmBjB,CAAU,CAAC,aAAa,mBAAmBY,CAAS,CAAC,GAChG,CACE,OAAQ,QACV,CACF,EACA,QAAM,QAAQG,EAAE,6BAA6B,CAAC,EAC9CD,EAAM,WAAWK,CAAS,EAC1BH,EAAO,QAAQ,CACjB,CAEA,SACE,oBACE,oBAACK,EAAA,CAAa,KAAMF,EAClB,oBAACG,EAAA,CACC,qBAACC,EAAA,CACC,oBAAC,MAAI,SAAAR,EAAE,yBAAyB,EAAE,KAClC,OAAC,KAAG,2BAAkBF,CAAY,IAAI,GACxC,KACA,QAACW,EAAA,CAAmB,MAAO,CAAE,QAAS,OAAQ,IAAK,MAAO,eAAgB,UAAW,EACnF,oBAACC,EAAA,EAAkB,KACnB,OAAC,EAAAC,OAAA,CACC,YAAY,QACZ,QAAS,IAAM,CACRN,EAAc,EAAE,MAAOO,GAC1B,QAAM,MAAMA,aAAe,MAAQA,EAAI,QAAU,eAAe,CAClE,CACF,EAEC,SAAAZ,EAAE,iBAAiB,EACtB,GACF,GACF,EACF,KACA,OAAC,UAAO,QAAS,IAAMD,EAAM,UAAUK,CAAS,EAAG,KAAK,SACrD,SAAAJ,EAAE,gBAAgB,EACrB,GACF,CAEJ,CAEO,SAASN,GAAkB,CAChC,WAAAT,EACA,QAAAO,CACF,EAGG,CACD,IAAMO,KAAQ,YAAS,EACjB,CAAE,EAAAC,CAAE,KAAI,kBAAe,EACvBa,EAAK,GAAAC,QAAS,MAAM,EACpBC,EAAOvB,EAAU,gBAAgBA,EAAQ,EAAE,GAAK,kBAAkBP,CAAU,IAAI4B,CAAE,GAIxF,SACE,oBACE,oBAACG,GAAA,CAAwB,WAAY/B,EAAY,QAASO,EAAS,UAAWuB,EAAM,KACpF,OALevB,EAAU,SAAW,EAAAmB,OAKnC,CACE,GAAInB,EAAU,CAAC,EAAI,CAAE,KAAM,OAAQ,EACpC,QAAS,IAAMO,EAAM,UAAUgB,CAAI,EACnC,KAAK,SAEJ,SAAUf,EAAVR,EAAY,eAAoB,mBAAN,EAC7B,GACF,CAEJ,CAEA,SAASwB,GAAwB,CAC/B,WAAA/B,EACA,QAAAO,EACA,UAAAY,CACF,EAIG,CACD,IAAML,KAAQ,YAAS,EACjB,CAAE,EAAAC,CAAE,KAAI,kBAAe,EACvBC,KAAS,cAAU,EACnB,CAAE,YAAAC,CAAY,EAAIC,EAAgB,EAClC,CAAC,CAAEc,CAAe,KAAI,kBAAc,EAEpCC,EAAS,CAACC,EAAmBC,IAAe,CAChD,IAAMC,EAAQD,EAAK,MACbE,EAAY,OAAOF,EAAK,WAAa,EAAE,EACvCG,EAAW,OAAOH,EAAK,UAAY,EAAE,EACrCI,EAAa,EAAQJ,EAAK,WAEhCH,EAAgB,IAAM,EACd,SAAY,CAChB,GAAI,CACF,MAAMf,EAAY,sBAAuB,CACvC,KAAM,KAAK,UAAU,CACnB,WAAAjB,EACA,MAAAoC,EACA,UAAAC,EACA,GAAI9B,GAAS,GACb,SAAA+B,EACA,WAAAC,CACF,CAAC,EACD,OAAQ,MACV,CAAC,EACD,QAAM,QAAQhC,EAAU,mBAAqB,kBAAkB,EAC/DO,EAAM,WAAWK,CAAS,EAC1BH,EAAO,QAAQ,CACjB,OAASW,EAAK,CACZ,QAAM,MAAMA,aAAe,MAAQA,EAAI,QAAU,aAAa,CAChE,CACF,GAAG,CACL,CAAC,CACH,EAEA,SACE,OAACN,EAAA,CAAa,KAAMF,EAClB,mBAACG,EAAA,CAAoB,MAAO,CAAE,MAAO,OAAQ,SAAU,OAAQ,EAC7D,oBAACC,EAAA,CACC,oBAAC,MAAI,SAAUR,EAAVR,EAAY,eAAoB,mBAAN,EAA2B,KAC1D,QAAC,QACC,UAAU,6BACV,aAAc,CACZ,MAAO,CACL,MAAOA,GAAS,OAAS,EAC3B,EACA,UAAW,CACT,MAAOA,GAAS,WAAa,EAC/B,EACA,SAAU,CACR,MAAOA,GAAS,UAAY,EAC9B,EACA,WAAY,CACV,MAAOA,GAAS,aAAe,EACjC,CACF,EACA,SAAU0B,EACV,oBAAmB,GAEnB,oBAAC,aACC,MAAO,CACL,MAAOlB,EAAE,eAAe,EACxB,KAAM,QACN,SAAU,GACV,KAAM,MACR,EACA,KAAK,QACL,SAAWyB,GACT,OAAOA,GAAM,UAAYA,EAAE,SAAS,GAAG,EAAI,GAAO,uBAEtD,KACA,OAAC,aACC,MAAO,CACL,MAAO,aACP,KAAM,YACN,KAAM,MACR,EACA,KAAK,YACP,KACA,OAAC,aACC,MAAO,CACL,MAAO,YACP,KAAM,WACN,KAAM,MACR,EACA,KAAK,WACP,KACA,OAAC,iBACC,MAAO,CACL,MAAO,aACP,KAAM,YACR,EACA,KAAK,aACP,KACA,QAAChB,EAAA,CAAmB,MAAO,CAAE,QAAS,OAAQ,IAAK,MAAO,eAAgB,UAAW,EACnF,oBAACC,EAAA,EAAkB,KACnB,OAAC,EAAAC,OAAA,CAAc,KAAK,QAAQ,KAAK,SAC9B,SAAUX,EAAVR,EAAY,eAAoB,gBAAN,EAC7B,GACF,GACF,GACF,EACF,EACF,CAEJ,CC5TA,IAAAkC,EAWO,0BACPC,GAA0B,2BAC1BC,GAAkB,sBAwBd,IAAAC,EAAA,6BAjBEC,GAAY,6BAEX,SAASC,GAAsB,CACpC,UAAAC,EACA,wBAAAC,EACA,cAAAC,EACA,SAAAC,CACF,EAKG,CACD,IAAMC,KAAQ,YAAS,EACjB,CAAE,EAAAC,CAAE,KAAI,kBAAe,EAE7B,SACE,oBACE,oBAACC,GAAA,CACC,UAAWN,EACX,wBAAyBC,EACzB,cAAeC,GAAiB,CAAC,EACjC,SAAUC,EACZ,KACA,OAAC,UAAO,QAAS,IAAMC,EAAM,UAAUN,EAAS,EAAG,KAAK,QAAQ,KAAK,SAClE,SAAAO,EAAE,mBAAmB,EACxB,GACF,CAEJ,CAEA,SAASE,GAAuB,CAC9B,cAAAL,EACA,wBAAAM,EACA,kBAAAC,EACA,gBAAAC,CACF,EAKG,CACD,IAAMC,KAAkB,iBAAc,CAAC,CAACC,CAAM,IAAM,CAClD,GAAI,CAACJ,EACH,MAAO,OAET,IAAMK,EAAID,GAAQ,iBAAiB,MACnC,OAAO,OAAOC,GAAM,UAAYA,IAAM,GAAKA,EAAI,MACjD,CAAC,EAED,GAAIL,EAAyB,CAC3B,IAAMM,EAASH,IAAoB,OACnC,SACE,oBACE,oBAAC,eACC,MAAO,CACL,MAAO,gBACP,KAAM,kBACN,QAAS,CACP,CAAE,MAAO,SAAU,MAAO,MAAO,EACjC,GAAGD,EAAgB,IAAKK,IAAS,CAAE,MAAOA,EAAI,KAAM,MAAOA,EAAI,EAAG,EAAE,CACtE,EACA,SAAU,EACZ,EACA,KAAK,kBACP,EACC,CAACD,GAAUZ,EAAc,OAAS,KACjC,OAAC,eACC,MAAO,CACL,MAAO,SACP,KAAM,SACN,QAASA,EACT,SAAU,EACZ,EACA,KAAK,SACP,EACE,KACHY,KACC,OAAC,iBACC,MAAO,CACL,MAAO,CACL,YAAa,qCACf,EACA,MAAO,SACP,KAAM,WACN,SAAU,EACZ,EACA,KAAK,WACP,EACE,MACN,CAEJ,CAEA,SACE,oBACG,UAAAL,KACC,OAAC,aACC,MAAO,CACL,MAAO,CACL,YACE,iGACJ,EACA,MAAO,cACP,KAAM,aACN,SAAU,GACV,KAAM,MACR,EACA,KAAK,aACP,EACE,QACJ,OAAC,iBACC,MAAO,CACL,MAAO,CACL,YAAaA,EACT,2DACA,sBACN,EACA,MAAOA,EAAoB,mCAAqC,SAChE,KAAM,WACN,SAAU,CAACA,CACb,EACA,KAAK,WACP,GACF,CAEJ,CAEA,SAASH,GAAqB,CAC5B,UAAAN,EACA,wBAAAC,EACA,cAAAC,EACA,SAAAC,CACF,EAKG,CACD,IAAMa,KAAS,cAAU,EACnBZ,KAAQ,YAAS,EACjB,CAAE,EAAAC,CAAE,KAAI,kBAAe,EACvB,CAAE,YAAAY,CAAY,EAAIC,EAAgB,EAClC,CAACC,EAAWC,CAAY,EAAI,GAAAC,QAAM,SAAS,EAAK,EAEhDZ,EAAoBN,IAAa,YACjCO,EAAkBT,GAA2B,CAAC,EAC9CO,EAA0BL,IAAa,UAAYO,EAAgB,OAAS,EAE5EY,EAAS,CAACV,EAAmBW,IAAe,CAChD,IAAMC,EAAMD,EACNE,GAAyBD,EAAI,WAC7BE,GAAmBF,EAAI,KACvBG,GAAsBH,EAAI,QAC1BI,GAAmBJ,EAAI,SACvBK,GAAyBL,EAAI,WAC7BM,GAAsBN,EAAI,QAE1BO,GAA8BP,EAAI,gBAClCQ,GAAqBR,EAAI,OAEzBS,EAAa,OAAOR,IAAkB,SAAWA,GAAgB,GACjES,EAAO,OAAOR,IAAY,SAAWA,GAAQ,KAAK,EAAI,GACtDS,EAAU,OAAOR,IAAe,SAAWA,GAAW,KAAK,EAAI,GAC/DS,EAAW,OAAOR,IAAY,SAAWA,GAAQ,KAAK,EAAI,GAC1DS,GAAa,OAAOR,IAAkB,SAAWA,GAAc,KAAK,EAAI,GACxES,EAAU,OAAOR,IAAe,SAAWA,GAAW,KAAK,EAAI,GAC/DnB,GACJ,OAAOoB,IAAuB,SAAWA,GAAmB,KAAK,EAAI,OACjEQ,GAAS,OAAOP,IAAc,SAAWA,GAAU,KAAK,EAAI,GAElEZ,EAAa,EAAI,GACX,SAAY,CAChB,GAAI,CACF,GAAI,CAACa,GAAc,CAACC,GAAQ,CAACC,EAC3B,MAAM,IAAI,MAAM,2CAA2C,EAG7D,IAAMK,EAAgB/B,EAChBgC,GAAqBjC,GAA2BG,KAAoB,OAE1E,GAAIH,EACF,GAAIiC,GACF,MAAMxB,EAAY,wBAAyB,CACzC,KAAM,KAAK,UAAU,CACnB,WAAAgB,EACA,gBAAiBtB,GACjB,OAAQ4B,IAAU,OAClB,KAAAL,EACA,QAAAI,EACA,QAAAH,CACF,CAAC,EACD,OAAQ,MACV,CAAC,UACSC,EAGV,MAAMnB,EAAY,wBAAyB,CACzC,KAAM,KAAK,UAAU,CACnB,WAAAgB,EACA,KAAMG,EACN,KAAAF,EACA,QAAAI,EACA,QAAAH,CACF,CAAC,EACD,OAAQ,MACV,CAAC,MAXD,OAAM,IAAI,MAAM,0DAA0D,UAanEK,EAAe,CACxB,GAAI,CAACH,IAAc,CAACD,EAClB,MAAM,IAAI,MAAM,4CAA4C,EAE9D,GAAIC,IAAcD,EAChB,MAAM,IAAI,MAAM,uDAAuD,EAEzE,MAAMnB,EAAY,wBAAyB,CACzC,KAAM,KAAK,UAAU,CACnB,WAAAgB,EACA,KAAMG,EACN,KAAAF,EACA,QAAAI,EACA,QAAAH,EACA,WAAYE,IAAc,MAC5B,CAAC,EACD,OAAQ,MACV,CAAC,CACH,SAAYD,EAGV,MAAMnB,EAAY,wBAAyB,CACzC,KAAM,KAAK,UAAU,CACnB,WAAAgB,EACA,KAAMG,EACN,KAAAF,EACA,QAAAI,EACA,QAAAH,CACF,CAAC,EACD,OAAQ,MACV,CAAC,MAXD,OAAM,IAAI,MAAM,uCAAuC,EAczD/B,EAAM,WAAWN,EAAS,EAC1B,QAAM,QAAQO,EAAE,8BAA+B,CAAE,MAAO,WAAY,CAAC,CAAC,EACtEW,EAAO,QAAQ,CACjB,OAAS0B,EAAK,CACZ,QAAM,MAAMA,aAAe,MAAQA,EAAI,QAAU,eAAe,CAClE,QAAE,CACAtB,EAAa,EAAK,CACpB,CACF,GAAG,CACL,EAEA,SACE,OAAC,UAAO,KAAMtB,GAAW,MAAOO,EAAE,mBAAmB,EACnD,oBAAC,QACC,UAAU,6BACV,aAAcG,EAA0B,CAAE,gBAAiB,CAAE,MAAO,MAAO,CAAE,EAAI,CAAC,EAClF,SAAUc,EACV,oBAAmB,GAEnB,oBAAC,eACC,MAAO,CACL,MAAO,WACP,KAAM,aACN,QAAStB,EAAU,IAAK2C,IAAO,CAAE,MAAOA,EAAE,KAAM,MAAOA,EAAE,EAAG,EAAE,EAC9D,SAAU,EACZ,EACA,KAAK,aACP,KACA,OAAC,aACC,MAAO,CACL,MAAO,gBACP,KAAM,OACN,SAAU,GACV,KAAM,MACR,EACA,KAAK,OACP,KACA,OAAC,aACC,MAAO,CACL,MAAO,UACP,KAAM,UACN,SAAU,GACV,KAAM,MACR,EACA,KAAK,UACP,KACA,OAAC,aACC,MAAO,CACL,MAAO,sBACP,KAAM,UACN,KAAM,MACR,EACA,KAAK,UACP,KAEA,OAACpC,GAAA,CACC,cAAeL,EACf,wBAAyBM,EACzB,kBAAmBC,EACnB,gBAAiBC,EACnB,KAEA,OAAC,UAAO,UAAU,SAAS,SAAUS,EAAW,KAAK,SAClD,SAAAd,EAAE,gBAAgB,EACrB,GACF,EACF,CAEJ,CRxUA,IAAAuC,GAAyB,iBSKlB,IAAMC,GAA8B,yBAS3C,SAASC,GAAkBC,EAGzB,CACA,MAAO,CACL,KAAMA,GAAO,MAAQ,GACrB,MAAOA,GAAO,OAAS,EACzB,CACF,CAGO,SAASC,EACdC,EAC+B,CAC/B,OAAKA,EAOE,CACL,UAAWH,GAAkBG,EAAY,SAAS,EAClD,SAAUH,GAAkBG,EAAY,QAAQ,EAChD,WAAYH,GAAkBG,EAAY,UAAU,CACtD,EAVS,CACL,UAAW,CAAE,KAAM,GAAM,MAAO,EAAK,EACrC,WAAY,CAAE,KAAM,GAAM,MAAO,EAAK,EACtC,SAAU,CAAE,KAAM,GAAM,MAAO,EAAK,CACtC,CAOJ,CAMA,SAASC,GAAgBC,EAAyD,CAChF,IAAMC,EAASD,EAAQ,OAAO,OAC9B,GAAI,CAACC,GAAU,OAAOA,GAAW,SAC/B,OAEF,IAAMC,EAAQD,EAAOE,EAA2B,EAChD,GAAKD,GAAO,QAGZ,OAAOA,CACT,CAEO,SAASE,EAAwBJ,EAA6C,CACnF,IAAMK,EAAQN,GAAgBC,CAAO,EACrC,GAAI,CAACK,EACH,MAAM,IAAI,MACR,GAAGF,EAA2B,uEAChC,EAEF,OAAOE,CACT,CAEO,SAASC,EACdN,EACuC,CACvC,OAAOD,GAAgBC,CAAO,CAChC,CC3EA,IAAAO,GAAgC,sCAW5BC,GAAA,6BAFG,SAASC,EAAmB,CAAE,SAAAC,EAAU,eAAAC,EAAgB,OAAAC,EAAQ,aAAAC,CAAa,EAAe,CACjG,SACE,QAAC,oBACC,KAAMF,EAAe,IAAI,KACzB,OAAQA,EAAe,OACvB,OAAQC,EACR,QAASD,EAAe,IAAI,QAC5B,YAAaA,EAAe,YAC5B,aAAcE,EACd,KAAMF,EAAe,IAAI,MAAQ,OACjC,gBAAiBA,EAAe,gBAE/B,SAAAD,EACH,CAEJ,CCtBA,SAASI,GAAYC,EAA0D,CAC7E,GAAI,OAAOA,GAAU,UAAYA,EAAM,KAAK,EAC1C,OAAOA,EAAM,KAAK,EAEpB,GAAI,MAAM,QAAQA,CAAK,GAAK,OAAOA,EAAM,CAAC,GAAM,UAAYA,EAAM,CAAC,EAAE,KAAK,EACxE,OAAOA,EAAM,CAAC,EAAE,KAAK,CAGzB,CAGO,SAASC,GACdC,EACoB,CACpB,GAAI,CAACA,EACH,OAGF,IAAMC,EAASJ,GAAYG,EAAO,EAAE,EACpC,GAAIC,EACF,OAAOA,EAGT,IAAMC,EAAcF,EAAO,SACrBG,EAAwB,MAAM,QAAQD,CAAW,EACnDA,EAAY,OAAQE,GAAmB,OAAOA,GAAM,UAAYA,EAAE,OAAS,CAAC,EAC5E,OAAOF,GAAgB,SACrBA,EAAY,MAAM,GAAG,EAAE,OAAO,OAAO,EACrC,CAAC,EAEP,GAAIC,EAAY,SAAW,EACzB,OAGF,IAAME,EAAcF,EAAY,YAAY,UAAU,EACtD,GAAIE,GAAe,GAAKF,EAAYE,EAAc,CAAC,EACjD,OAAOF,EAAYE,EAAc,CAAC,EAGpC,IAAMC,EAAOH,EAAYA,EAAY,OAAS,CAAC,EAC/C,GAAIG,IAAS,WAGb,OAAOA,CACT,CXbQ,IAAAC,EAAA,6BAdO,SAARC,GAAgC,CACrC,eAAAC,EACA,OAAAC,EACA,aAAAC,CACF,EAA4B,CAC1B,IAAMC,EAAaC,GAA8BH,CAAM,EAEvD,GAAI,CAACE,EACH,MAAM,IAAI,MAAM,gCAAgC,EAGlD,SACE,OAACE,EAAA,CAAmB,eAAgBL,EAAgB,OAAQC,EAAQ,aAAcC,EAChF,mBAAC,WACC,mBAACI,GAAA,CAAmB,WAAYH,EAAY,eAAgBH,EAAgB,EAC9E,EACF,CAEJ,CAEA,eAAeM,GAAmB,CAChC,WAAAH,EACA,eAAAH,CACF,EAGG,CACD,IAAMO,EAAcC,EAA2BR,EAAe,IAAI,OAAO,EACzE,GAAI,CAACO,EACH,SACE,OAAC,KAAE,KAAK,QAAQ,mFAAuE,EAI3F,IAAME,EAAYC,EAA4BH,EAAY,WAAW,EACrE,GAAI,CAACE,EAAU,UAAU,KACvB,SAAO,OAAC,KAAE,KAAK,QAAQ,6DAAiD,EAG1E,GAAM,CAAE,QAAAE,CAAQ,EAAIC,EAAwBZ,EAAe,IAAI,OAAO,EAChEa,EAAW,MAAMF,EAAQ,UAAU,IAAIR,CAAU,EAClDU,MACH,aAAS,EAGX,IAAMC,EAAuBH,EAAQ,MAAM,WAAWR,CAAU,EAEhE,SACE,oBACE,qBAAC,UAAO,UAAU,sBAChB,oBAAC,MAAI,SAAAU,EAAS,KAAK,EAClBC,KACC,QAAC,SAAK,KAAMA,EAAsB,IAAI,sBAAsB,OAAO,SAAS,mCACnDH,EAAQ,OACjC,EACE,MACN,KAEA,QAAC,OAAI,UAAU,4BACZ,UAAAF,EAAU,SAAS,SAClB,OAAC,OACC,mBAACM,GAAA,CAAkB,WAAYZ,EAAY,QAAS,KAAM,EAC5D,EACE,KACHM,EAAU,SAAS,QAClB,OAAC,aAAS,YAAU,OAAC,OAAI,YAAS,GAAC,MAAO,CAAE,UAAW,OAAQ,EAAG,EAChE,mBAACO,GAAA,CAAe,WAAYb,EAAY,eAAgBH,EAAgB,EAC1E,KAEA,OAAC,KAAE,KAAK,QAAQ,wDAA4C,GAEhE,GACF,CAEJ,CAEA,eAAegB,GAAe,CAC5B,WAAAb,EACA,eAAAH,CACF,EAGG,CACD,GAAM,CAAE,QAAAW,CAAQ,EAAIC,EAAwBZ,EAAe,IAAI,OAAO,EAChEiB,EAAW,MAAMN,EAAQ,SAAS,KAAK,CAAE,WAAAR,CAAW,CAAC,EAC3D,SAAO,OAACe,GAAA,CAAsB,WAAYf,EAAY,SAAUc,EAAU,CAC5E,CYzGA,IAAAE,EAAoC,0BAEpC,IAAAC,GAAyB,iBAyBjB,IAAAC,EAAA,6BATO,SAARC,GAA8B,CACnC,SAAAC,EAAW,GACX,eAAAC,EACA,OAAAC,EACA,aAAAC,CACF,EAA0B,CACxB,SACE,OAACC,EAAA,CAAmB,eAAgBH,EAAgB,OAAQC,EAAQ,aAAcC,EAChF,mBAAC,UACC,mBAACE,GAAA,CAAiB,SAAUL,EAAU,eAAgBC,EAAgB,EACxE,EACF,CAEJ,CAEA,SAASI,GAAiB,CACxB,SAAAL,EACA,eAAAC,CACF,EAGG,CACD,IAAMK,EAAcC,EAA2BN,EAAe,IAAI,OAAO,EACzE,GAAI,CAACK,EACH,SACE,OAAC,KAAE,KAAK,QAAQ,mFAAuE,EAI3F,IAAME,EAAYC,EAA4BH,EAAY,WAAW,EACrE,GAAI,CAACE,EAAU,UAAU,KACvB,SAAO,OAAC,KAAE,KAAK,QAAQ,yDAA6C,EAGtE,IAAME,EAAeJ,EAAY,QAAQ,MAAM,UAE/C,SACE,oBACE,qBAAC,UAAO,UAAU,sBAChB,oBAAC,MAAG,qBAAS,EACZI,KACC,QAAC,QAAK,KAAMA,EAAc,IAAI,sBAAsB,OAAO,SAAS,+BAC/CJ,EAAY,QAAQ,OACzC,EACE,MACN,KAEA,QAAC,OAAI,UAAU,2BACZ,UAAAE,EAAU,UAAU,SACnB,OAAC,OACC,mBAACG,GAAA,EAAqB,EACxB,EACE,QACJ,OAAC,aAAS,YAAU,OAAC,OAAI,YAAS,GAAC,MAAO,CAAE,UAAW,MAAO,EAAG,EAC/D,mBAACC,GAAA,CACC,eAAgBJ,EAAU,UAAU,MACpC,SAAUR,EACV,eAAgBC,EAClB,EACF,GACF,GACF,CAEJ,CAEA,eAAeW,GAAkB,CAC/B,eAAAC,EACA,SAAAb,EACA,eAAAC,CACF,EAIG,CACD,GAAM,CAAE,QAAAa,CAAQ,EAAIC,EAAwBd,EAAe,IAAI,OAAO,EAChEe,EAAY,MAAMF,EAAQ,UAAU,KAAK,EAEzCG,EAAa,CACjB,QAAS,OACT,SAAU,OACV,OAAQ,GACR,MAAO,CAAE,KAAM,OAAQ,KAAM,MAAgB,EAC7C,cAAeD,EAAU,IAAKE,MAC5B,OAAC,OACC,mBAAC,QAAK,KAAMC,GAAmBnB,EAAU,WAAYkB,EAAS,EAAE,EAAI,SAAAA,EAAS,KAAK,GAD1EA,EAAS,EAEnB,CACD,CACH,EAEME,EAAe,CACnB,QAAS,GACT,SAAU,GACV,OAAQ,GACR,MAAO,CAAE,KAAM,UAAW,KAAM,MAAgB,EAChD,cAAeJ,EAAU,IAAKE,MAC5B,OAAC,OACC,mBAACG,GAAA,CAAqB,WAAYH,EAAS,GAAI,aAAcA,EAAS,KAAM,GADpEA,EAAS,EAEnB,CACD,CACH,EAEA,SACE,OAAC,SACC,QAASL,EAAiB,CAACI,EAAYG,CAAY,EAAI,CAACH,CAAU,EAClE,KAAMD,EACR,CAEJ,CC7HA,IAAAM,GAA6B,0BAM7B,IAAAC,GAAyB,iBCJzB,SAASC,GAAeC,EAAqB,CAC3C,GAAM,CAAE,MAAAC,EAAO,KAAAC,CAAK,EAAIF,EACxB,GAAI,OAAOC,GAAU,SACnB,OAAOA,EAET,GAAIA,GAAS,OAAOA,GAAU,UAC5B,QAAWE,KAAS,OAAO,OAAOF,CAAK,EACrC,GAAI,OAAOE,GAAU,SACnB,OAAOA,EAIb,OAAOD,CACT,CAGO,SAASE,GACdC,EACoC,CACpC,IAAMC,EAAMD,EAAO,aACnB,GAAIC,IAAQ,IAASA,IAAQ,OAC3B,MAAO,CAAC,EAEV,IAAMC,EAAUD,EAAI,QACpB,OAAKC,GAAS,OAGPA,EAAQ,IAAKC,IAAqB,CACvC,MAAOT,GAAeS,CAAO,EAC7B,MAAOA,EAAQ,IACjB,EAAE,EALO,CAAC,CAMZ,CDHQ,IAAAC,EAAA,6BARO,SAARC,GAA+B,CACpC,eAAAC,EACA,OAAAC,EACA,aAAAC,CACF,EAA2B,CACzB,SACE,OAACC,EAAA,CAAmB,eAAgBH,EAAgB,OAAQC,EAAQ,aAAcC,EAChF,mBAAC,WACC,mBAACE,GAAA,CAAkB,eAAgBJ,EAAgB,EACrD,EACF,CAEJ,CAEA,SAASI,GAAkB,CACzB,eAAAJ,CACF,EAEG,CACD,IAAMK,EAAcC,EAA2BN,EAAe,IAAI,OAAO,EACzE,GAAI,CAACK,EACH,SACE,OAAC,KAAE,KAAK,QAAQ,mFAAuE,EAI3F,IAAME,EAAYC,EAA4BH,EAAY,WAAW,EACrE,GAAI,CAACE,EAAU,WAAW,KACxB,SAAO,OAAC,KAAE,KAAK,QAAQ,0DAA8C,EAGvE,GAAM,CAAE,QAAAE,CAAQ,EAAIC,EAAwBV,EAAe,IAAI,OAAO,EAChEW,EAAgBF,EAAQ,MAAM,WAEpC,SACE,oBACE,qBAAC,UAAO,UAAU,sBAChB,oBAAC,MAAG,qBAAS,EACZE,KACC,QAAC,SAAK,KAAMA,EAAe,IAAI,sBAAsB,OAAO,SAAS,+BAChDF,EAAQ,OAC7B,EACE,MACN,KAEA,QAAC,OAAI,UAAU,2BACZ,UAAAF,EAAU,WAAW,SACpB,OAAC,OACC,mBAAC,aAAS,YAAU,OAAC,OAAI,YAAS,GAAC,MAAO,CAAE,UAAW,QAAS,EAAG,EACjE,mBAACK,GAAA,CAAsB,eAAgBZ,EAAgB,EACzD,EACF,EACE,QACJ,OAAC,aAAS,YAAU,OAAC,OAAI,YAAS,GAAC,MAAO,CAAE,UAAW,MAAO,EAAG,EAC/D,mBAACa,GAAA,CAAqB,eAAgBb,EAAgB,EACxD,GACF,GACF,CAEJ,CAEA,eAAeY,GAAsB,CACnC,eAAAZ,CACF,EAEG,CACD,IAAMK,EAAcK,EAAwBV,EAAe,IAAI,OAAO,EAChE,CAAE,QAAAS,CAAQ,EAAIJ,EACdS,EAAY,MAAML,EAAQ,UAAU,KAAK,EACzCM,EACJV,EAAY,yBAAyB,IAAI,CAAC,CAAE,GAAAW,EAAI,KAAAC,CAAK,KAAO,CAAE,GAAAD,EAAI,KAAAC,CAAK,EAAE,GAAK,CAAC,EAC3EC,EAAgBC,GAAiCnB,EAAe,IAAI,QAAQ,MAAM,EACxF,SACE,OAACoB,GAAA,CACC,UAAWN,EACX,wBAAyBC,EACzB,cAAeG,EACf,SAAUT,EAAQ,SACpB,CAEJ,CAEA,eAAeI,GAAqB,CAClC,eAAAb,CACF,EAEG,CACD,GAAM,CAAE,QAAAS,CAAQ,EAAIC,EAAwBV,EAAe,IAAI,OAAO,EAEhEqB,GADO,MAAMZ,EAAQ,WAAW,KAAK,GACM,IAAKa,IAAO,CAC3D,GAAGA,EACH,qBAAsBb,EAAQ,MAAM,YAAYa,EAAE,EAAE,CACtD,EAAE,EAEF,SAAO,OAACC,GAAA,CAAgB,WAAYF,EAAY,CAClD","names":["server_exports","__export","AudienceDetail","AudienceList","BroadcastList","__toCommonJS","import_ui","import_navigation","joinAdminSegments","adminRoute","segments","trimmedAdmin","body","s","segment","marketingAdminHref","basePath","parts","import_ui","import_react","useMarketingApi","context","base","requestJson","pathSegment","init","_headersIgnored","restInit","headers","res","detail","parsed","import_ui","import_link","import_navigation","import_react","formatMarketingDate","iso","d","import_ui","import_react","import_jsx_runtime","cn","parts","PayloadModalContext","React","PayloadModal","children","className","modalSlug","props","loaded","setLoaded","PayloadModalContent","PayloadModalBody","PayloadModalTitle","PayloadModalFooter","PayloadModalClose","t","modal","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_ui","import_navigation","import_react","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_ui","import_navigation","import_react","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_ui","import_navigation","import_react","import_jsx_runtime","modalSlug","CreateBroadcastButton","audiences","emailBroadcastTemplates","localeOptions","provider","modal","t","CreateBroadcastModal","BroadcastContentFields","showReactEmailTemplates","showTemplateField","templateOptions","broadcastFormat","fields","v","isHtml","opt","router","requestJson","useMarketingApi","isPending","setIsPending","React","submit","data","row","audienceIdRaw","nameRaw","subjectRaw","htmlRaw","templateIdRaw","replyToRaw","broadcastFormatRaw","localeRaw","audienceId","name","subject","htmlBody","templateId","replyTo","locale","mailchimpMode","usingReactTemplate","err","a","import_react","MARKETING_CUSTOM_CONFIG_KEY","effectiveResource","slice","resolveMarketingPermissions","permissions","readIntegration","payload","custom","slice","MARKETING_CUSTOM_CONFIG_KEY","getMarketingIntegration","state","tryGetMarketingIntegration","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_ui","import_react","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_ui","import_react","labelForLocale","loc","label","code","value","getLocaleSelectOptionsFromConfig","config","raw","locales","locItem","import_jsx_runtime","BroadcastList","initPageResult","params","searchParams","MarketingViewShell","BroadcastListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","broadcastsUrl","CreateBroadcastRegion","BroadcastTableRegion","audiences","emailBroadcastTemplates","id","name","localeOptions","getLocaleSelectOptionsFromConfig","CreateBroadcastButton","broadcasts","b","BroadcastsTable"]}
|
|
1
|
+
{"version":3,"sources":["../../src/admin/server.ts","../../src/admin/components/audience-detail.tsx","../../src/marketing-integration.ts","../../src/admin/components/marketing-view-shell.tsx","../../src/admin/components/view-params.ts","../../src/admin/components/audience-list.tsx","../../src/admin/paths.ts","../../src/admin/components/broadcast-list.tsx","../../src/admin/locale-options.ts"],"sourcesContent":["export { AudienceDetail, AudienceList, BroadcastList } from \"./components/views\"\n","import { Gutter, Link } from \"@payloadcms/ui\"\nimport { notFound } from \"next/navigation\"\nimport { AudienceContactsTable, EditContactButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 <AudienceContactsTable audienceId={audienceId} contacts={contacts} />\n}\n","import type {\n MarketingAdapter,\n MarketingEffectivePermissions,\n MarketingEmailBroadcastTemplate,\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 emailBroadcastTemplates?: MarketingEmailBroadcastTemplate[]\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(\n payload: Payload,\n): MarketingIntegrationState | undefined {\n return readIntegration(payload)\n}\n\nexport function getMarketingIntegrationFromRequest(req: PayloadRequest): MarketingIntegrationState {\n return getMarketingIntegration(req.payload)\n}\n","import { DefaultTemplate } from \"@payloadcms/next/templates\"\n\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 { Gutter, Link, Table } from \"@payloadcms/ui\"\nimport { CreateAudienceButton, DeleteAudienceButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { marketingAdminHref } from \"../paths\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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","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 { Gutter, Link } from \"@payloadcms/ui\"\nimport {\n BroadcastsTable,\n CreateBroadcastButton,\n type MarketingBroadcastRow,\n} from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { getLocaleSelectOptionsFromConfig } from \"../locale-options\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 integration = getMarketingIntegration(initPageResult.req.payload)\n const { adapter } = integration\n const audiences = await adapter.audiences.list()\n const emailBroadcastTemplates =\n integration.emailBroadcastTemplates?.map(({ id, name }) => ({ id, name })) ?? []\n const localeOptions = getLocaleSelectOptionsFromConfig(initPageResult.req.payload.config)\n return (\n <CreateBroadcastButton\n audiences={audiences}\n emailBroadcastTemplates={emailBroadcastTemplates}\n localeOptions={localeOptions}\n provider={adapter.provider}\n />\n )\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","import type { Locale, SanitizedConfig } from \"payload\"\n\nfunction labelForLocale(loc: Locale): string {\n const { label, code } = loc\n if (typeof label === \"string\") {\n return label\n }\n if (label && typeof label === \"object\") {\n for (const value of Object.values(label)) {\n if (typeof value === \"string\") {\n return value\n }\n }\n }\n return code\n}\n\n/** Options for admin selects; values are locale codes from `config.localization.locales`. */\nexport function getLocaleSelectOptionsFromConfig(\n config: SanitizedConfig,\n): { label: string; value: string }[] {\n const raw = config.localization\n if (raw === false || raw === undefined) {\n return []\n }\n const locales = raw.locales\n if (!locales?.length) {\n return []\n }\n return locales.map((locItem: Locale) => ({\n label: labelForLocale(locItem),\n value: locItem.code,\n }))\n}\n"],"mappings":"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","names":["server_exports","__export","AudienceDetail","AudienceList","BroadcastList","__toCommonJS","import_ui","import_navigation","import_client","import_react","MARKETING_CUSTOM_CONFIG_KEY","effectiveResource","slice","resolveMarketingPermissions","permissions","readIntegration","payload","custom","slice","MARKETING_CUSTOM_CONFIG_KEY","getMarketingIntegration","state","tryGetMarketingIntegration","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","DetailContacts","contacts","import_ui","import_client","import_react","joinAdminSegments","adminRoute","segments","trimmedAdmin","body","s","segment","marketingAdminHref","basePath","parts","import_jsx_runtime","AudienceList","basePath","initPageResult","params","searchParams","MarketingViewShell","AudienceListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","audiencesUrl","AudienceTableRows","audiencesWrite","adapter","getMarketingIntegration","audiences","nameColumn","audience","marketingAdminHref","deleteColumn","import_ui","import_client","import_react","labelForLocale","loc","label","code","value","getLocaleSelectOptionsFromConfig","config","raw","locales","locItem","import_jsx_runtime","BroadcastList","initPageResult","params","searchParams","MarketingViewShell","BroadcastListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","broadcastsUrl","CreateBroadcastRegion","BroadcastTableRegion","audiences","emailBroadcastTemplates","id","name","localeOptions","getLocaleSelectOptionsFromConfig","broadcasts","b"]}
|
package/dist/admin/server.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Gutter as jt,Link as zt}from"@payloadcms/ui";import{notFound as Gt}from"next/navigation";function it(t,...e){let a=t.replace(/\/+$/,"")||"",n=e.flatMap(o=>String(o).split("/")).map(o=>o.replace(/^\/+|\/+$/g,"")).filter(Boolean).join("/");return(a===""?`/${n}`:`${a}/${n}`).replace(/\/{2,}/g,"/")}function Le(t,...e){let n=[t?.replace(/^\/+|\/+$/g,"")??"",...e].filter(Boolean);return it("/admin",...n)}import{useConfig as st}from"@payloadcms/ui";import{useCallback as lt,useMemo as dt}from"react";function w(){let t=st(),e=dt(()=>`${t.serverURL??""}${t.routes?.api??"/api"}`,[t.routes?.api,t.serverURL]),a=lt(async(n,r)=>{let{headers:o,...i}=r??{},s=new Headers(r?.headers);i.body!==void 0&&i.body!==""&&i.body!==null&&(s.has("Content-Type")||s.set("Content-Type","application/json"));let c=await fetch(`${e}${n}`,{...i,credentials:"include",headers:s});if(!c.ok){let m=`${c.status} ${c.statusText}`;try{let y=await c.json();typeof y.message=="string"&&(m=y.message)}catch{}throw new Error(m)}if(c.status!==204)try{return await c.json()}catch{return}},[e]);return{base:e,requestJson:a}}import{Button as Ve,DateTimeField as ft,Form as gt,Pagination as yt,Pill as q,Table as ht,toast as Y,useModal as $e,useTranslation as _e}from"@payloadcms/ui";import bt from"next/link";import{useRouter as He}from"next/navigation";import ie from"react";function J(t){if(!t)return"\u2014";let e=new Date(t);return Number.isNaN(e.valueOf())?String(t):new Intl.DateTimeFormat(void 0,{dateStyle:"medium"}).format(e)}import{Button as ct,Modal as ut,useModal as mt,useTranslation as pt}from"@payloadcms/ui";import W from"react";import{jsx as N}from"react/jsx-runtime";function D(...t){return t.filter(Boolean).join(" ")}var Oe=W.createContext({modalSlug:""});function v({children:t,className:e,slug:a,...n}){let[r,o]=W.useState(!1);return W.useEffect(()=>{o(!0)},[]),N(Oe.Provider,{value:{modalSlug:a},children:r&&N(ut,{slug:a,className:D("confirmation-modal",e),...n,children:t})})}function S({children:t,className:e,...a}){return N("div",{className:D("confirmation-modal__wrapper",e),"data-slot":"payload-modal-content",...a,children:t})}function C({children:t,className:e,...a}){return N("div",{className:D("confirmation-modal__content",e),"data-slot":"payload-modal-body",...a,children:t})}function E({children:t,className:e,...a}){return N("h1",{className:D("",e),"data-slot":"payload-modal-title",...a,children:t})}function x({children:t,className:e,...a}){return N("div",{className:D("confirmation-modal__controls",e),"data-slot":"payload-modal-footer",...a,children:t})}function B({children:t,className:e,...a}){let{t:n}=pt(),{modalSlug:r}=W.useContext(Oe),o=mt();return N(ct,{className:D("",e),buttonStyle:"secondary",size:"large","data-slot":"payload-modal-close",...a,onClick:()=>o.closeModal(r),children:t??n("general:cancel")})}import{Fragment as K,jsx as l,jsxs as M}from"react/jsx-runtime";function se({broadcasts:t}){let[e,a]=ie.useState(1),[n]=ie.useState(100),r=ie.useMemo(()=>t.slice((e-1)*n,e*n),[t,n,e]);return M(K,{children:[l(ht,{columns:[{Heading:"Campaign name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:r.map(o=>l("div",{children:o.name},o.id))},{Heading:"Schedule date",accessor:"scheduledAt",active:!0,field:{name:"scheduledAt",type:"text"},renderedCells:r.map(o=>l("div",{children:J(o.scheduledAt)},o.id))},{Heading:"Sent date",accessor:"sentAt",active:!0,field:{name:"sentAt",type:"text"},renderedCells:r.map(o=>l("div",{children:J(o.sentAt)},o.id))},{Heading:"Status",accessor:"status",active:!0,field:{name:"status",type:"text"},renderedCells:r.map(o=>l("div",{children:l(Pt,{status:o.status})},o.id))},{Heading:"",accessor:"",active:!0,field:{name:"_",type:"text"},renderedCells:r.map(o=>M("div",{className:"flex items-center gap-4 flex-wrap",children:[o.externalDashboardUrl?l(bt,{href:o.externalDashboardUrl,rel:"noreferrer noopener",target:"_blank",children:l(q,{children:"dashboard \u2197"})}):null,o.status==="draft"||o.status==="save"?M(K,{children:[l(wt,{broadcastId:o.id,broadcastName:o.name}),l(Mt,{broadcastId:o.id,broadcastName:o.name})]}):null]},o.id))}],data:r}),l(yt,{hasNextPage:e*n<t.length,hasPrevPage:e>1,limit:n,onChange:o=>a(o),page:e,totalPages:Math.ceil(t.length/n)})]})}function Pt({status:t}){switch(t){case"draft":case"save":return l(q,{pillStyle:"light-gray",children:"Draft"});case"queued":return l(q,{pillStyle:"white",children:"Queued"});case"sent":return l(q,{pillStyle:"success",children:"Sent"});default:return l(q,{children:t})}}function wt({broadcastId:t,broadcastName:e}){let a=$e(),{t:n}=_e(),r=He(),{requestJson:o}=w(),i=`delete-broadcast_${t}`;async function s(){await o(`/marketing/broadcasts/${encodeURIComponent(t)}`,{method:"DELETE"}),Y.success(n("general:deletedSuccessfully")),a.closeModal(i),r.refresh()}return M(K,{children:[l(v,{slug:i,children:M(S,{children:[M(C,{children:[l(E,{children:n("general:confirmDeletion")}),l("p",{children:`Delete draft broadcast "${e}"?`})]}),M(x,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[l(B,{}),l(Ve,{buttonStyle:"error",onClick:()=>{s().catch(c=>Y.error(c instanceof Error?c.message:"Delete failed"))},children:n("general:confirm")})]})]})}),l("button",{onClick:()=>a.openModal(i),type:"button",children:n("general:delete")})]})}function Mt({broadcastId:t,broadcastName:e}){let a=$e(),{t:n}=_e(),r=He(),{requestJson:o}=w(),i=`send-broadcast_${t}`,s=(c,m)=>{let P=m.scheduledAt,p="";typeof P=="string"?p=P:P instanceof Date&&(p=P.toISOString()),(async()=>{try{await o(`/marketing/broadcasts/${encodeURIComponent(t)}/send`,{body:JSON.stringify({...p&&p.trim()!==""?{scheduledAt:p.trim()}:{}}),method:"POST"}),a.closeModal(i),Y.success(n("general:success")),r.refresh()}catch(I){Y.error(I instanceof Error?I.message:"Send failed")}})()};return M(K,{children:[l(v,{slug:i,children:l(S,{style:{width:"100%",maxWidth:"24rem"},children:M(C,{children:[l(E,{children:`Send \u201C${e}\u201D`}),M(gt,{initialState:{},onSubmit:s,waitForAutocomplete:!0,children:[l(ft,{field:{label:"Schedule at (optional)",name:"scheduledAt",required:!1},path:"scheduledAt"}),M(x,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[l(B,{}),l(Ve,{size:"large",type:"submit",children:"Send"})]})]})]})})}),l(q,{pillStyle:"dark",onClick:()=>a.openModal(i),size:"small",children:"Send"})]})}import{Button as Ue,Form as kt,TextField as vt,toast as Q,useModal as de,useTranslation as ce,Button as St}from"@payloadcms/ui";import{useRouter as Je}from"next/navigation";import{useTransition as Ct}from"react";import{Fragment as je,jsx as f,jsxs as F}from"react/jsx-runtime";var le="create-audience";function ue(){let t=de(),{t:e}=ce();return F(je,{children:[f(xt,{}),f(Ue,{onClick:()=>t.openModal(le),size:"large",type:"button",children:e("general:createNew")})]})}function xt(){let t=de(),{t:e}=ce(),a=Je(),{requestJson:n}=w(),[r,o]=Ct();return f(v,{closeOnBlur:!0,slug:le,children:f(S,{style:{width:"100%",maxWidth:"24rem"},children:f(kt,{initialState:{},onSubmit:(s,c)=>{let y=c.audienceName,P=typeof y=="string"?y.trim():"";o(()=>{(async()=>{try{if(!P)throw new Error("Name is required.");await n("/marketing/audiences",{body:JSON.stringify({name:P}),method:"POST"}),t.closeModal(le),Q.success(e("general:successfullyCreated")),a.refresh()}catch(p){Q.error(p instanceof Error?p.message:"Create failed")}})()})},waitForAutocomplete:!0,children:F(C,{children:[f(E,{children:e("general:createNew")}),f(vt,{field:{name:"audienceName",required:!0,type:"text"},path:"audienceName",validate:s=>typeof s=="string"&&s.trim().length>0?!0:"Name is required"}),F(x,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[f(B,{}),f(Ue,{disabled:r,size:"large",type:"submit",children:e("general:confirm")})]})]})})})})}function me({audienceId:t,audienceName:e}){let a=de(),{t:n}=ce(),r=Je(),{requestJson:o}=w(),i=`delete-audience_${t}`;async function s(){await o(`/marketing/audiences/${encodeURIComponent(t)}`,{method:"DELETE"}),Q.success(n("general:deletedSuccessfully")),a.closeModal(i),r.refresh()}return F(je,{children:[f(v,{slug:i,children:F(S,{children:[F(C,{children:[f(E,{children:n("general:confirmDeletion")}),f("p",{children:`Remove audience "${e}"?`})]}),F(x,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[f(B,{}),f(St,{buttonStyle:"error",onClick:()=>{s().catch(c=>Q.error(c instanceof Error?c.message:"Delete failed"))},children:n("general:confirm")})]})]})}),f("button",{onClick:()=>a.openModal(i),type:"button",children:n("general:delete")})]})}import{CheckboxField as Bt,Form as At,Pagination as Tt,Table as Rt,TextField as pe,toast as X,useModal as ge,useTranslation as ye,Button as he}from"@payloadcms/ui";import{useRouter as ze}from"next/navigation";import fe from"react";import Nt from"react";import{useTransition as Ft}from"react";import{Fragment as Pe,jsx as d,jsxs as k}from"react/jsx-runtime";function be({audienceId:t,contacts:e}){let[a,n]=fe.useState(1),[r]=fe.useState(100),o=fe.useMemo(()=>e.slice((a-1)*r,a*r),[e,r,a]);return k(Pe,{children:[d(Rt,{columns:[{Heading:"First name",accessor:"firstName",active:!0,field:{name:"firstName",type:"text"},renderedCells:o.map(i=>d("div",{children:i.firstName??"\u2014"},i.id))},{Heading:"Last name",accessor:"lastName",active:!0,field:{name:"lastName",type:"text"},renderedCells:o.map(i=>d("div",{children:i.lastName??"\u2014"},i.id))},{Heading:"Email",accessor:"email",active:!0,field:{name:"email",type:"text"},renderedCells:o.map(i=>d("div",{children:i.email},i.id))},{Heading:"Created",accessor:"createdAt",active:!0,field:{name:"createdAt",type:"text"},renderedCells:o.map(i=>d("div",{children:J(i.createdAt)},i.id))},{Heading:"Status",accessor:"subscribed",active:!0,field:{name:"subscribed",type:"text"},renderedCells:o.map(i=>k("div",{className:"flex items-center gap-4 flex-wrap",children:[d("span",{children:i.subscribed!==!1?"\u2705 subscribed":"\u274C unsubscribed"}),d(Z,{audienceId:t,contact:i}),d(It,{audienceId:t,contactEmail:i.email,contactId:i.id})]},i.id))}],data:o}),d(Tt,{hasNextPage:a*r<e.length,hasPrevPage:a>1,limit:r,onChange:i=>{n(i)},page:a,totalPages:Math.ceil(e.length/r)})]})}function It({audienceId:t,contactId:e,contactEmail:a}){let n=ge(),{t:r}=ye(),o=ze(),{requestJson:i}=w(),s=`delete-contact_${e}`;async function c(){await i(`/marketing/audiences/${encodeURIComponent(t)}/contacts/${encodeURIComponent(e)}`,{method:"DELETE"}),X.success(r("general:deletedSuccessfully")),n.closeModal(s),o.refresh()}return k(Pe,{children:[d(v,{slug:s,children:k(S,{children:[k(C,{children:[d("h1",{children:r("general:confirmDeletion")}),d("p",{children:`Remove contact ${a}?`})]}),k(x,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[d(B,{}),d(he,{buttonStyle:"error",onClick:()=>{c().catch(m=>X.error(m instanceof Error?m.message:"Delete failed"))},children:r("general:confirm")})]})]})}),d("button",{onClick:()=>n.openModal(s),type:"button",children:r("general:delete")})]})}function Z({audienceId:t,contact:e}){let a=ge(),{t:n}=ye(),r=Nt.useId(),o=e?`edit-contact_${e.id}`:`create-contact_${t}_${r}`;return k(Pe,{children:[d(Dt,{audienceId:t,contact:e,modalSlug:o}),d(e?"button":he,{...e?{}:{size:"large"},onClick:()=>a.openModal(o),type:"button",children:n(e?"general:edit":"general:createNew")})]})}function Dt({audienceId:t,contact:e,modalSlug:a}){let n=ge(),{t:r}=ye(),o=ze(),{requestJson:i}=w(),[,s]=Ft(),c=(m,y)=>{let P=y.email,p=String(y.firstName??""),I=String(y.lastName??""),$=!!y.subscribed;s(()=>{(async()=>{try{await i("/marketing/contacts",{body:JSON.stringify({audienceId:t,email:P,firstName:p,id:e?.id,lastName:I,subscribed:$}),method:"POST"}),X.success(e?"Contact updated.":"Contact created."),n.closeModal(a),o.refresh()}catch(j){X.error(j instanceof Error?j.message:"Save failed")}})()})};return d(v,{slug:a,children:d(S,{style:{width:"100%",maxWidth:"32rem"},children:k(C,{children:[d("h1",{children:r(e?"general:edit":"general:createNew")}),k(At,{className:"flex w-full flex-col gap-6",initialState:{email:{value:e?.email??""},firstName:{value:e?.firstName??""},lastName:{value:e?.lastName??""},subscribed:{value:e?.subscribed!==!1}},onSubmit:c,waitForAutocomplete:!0,children:[d(pe,{field:{label:r("general:email"),name:"email",required:!0,type:"text"},path:"email",validate:m=>typeof m=="string"&&m.includes("@")?!0:"Valid email required"}),d(pe,{field:{label:"First name",name:"firstName",type:"text"},path:"firstName"}),d(pe,{field:{label:"Last name",name:"lastName",type:"text"},path:"lastName"}),d(Bt,{field:{label:"Subscribed",name:"subscribed"},path:"subscribed"}),k(x,{style:{display:"flex",gap:"8px",justifyContent:"flex-end"},children:[d(B,{}),d(he,{size:"large",type:"submit",children:r(e?"general:save":"general:create")})]})]})]})})})}import{Button as Ye,Drawer as Et,Form as qt,SelectField as we,TextareaField as Ge,TextField as ee,toast as We,useFormFields as Lt,useModal as Ke,useTranslation as Qe}from"@payloadcms/ui";import{useRouter as Ot}from"next/navigation";import Vt from"react";import{Fragment as ke,jsx as h,jsxs as te}from"react/jsx-runtime";var Me="create-marketing-broadcast";function ve({audiences:t,emailBroadcastTemplates:e,localeOptions:a,provider:n}){let r=Ke(),{t:o}=Qe();return te(ke,{children:[h(_t,{audiences:t,emailBroadcastTemplates:e,localeOptions:a??[],provider:n}),h(Ye,{onClick:()=>r.openModal(Me),size:"large",type:"button",children:o("general:createNew")})]})}function $t({localeOptions:t,showReactEmailTemplates:e,showTemplateField:a,templateOptions:n}){let r=Lt(([o])=>{if(!e)return"html";let i=o?.broadcastFormat?.value;return typeof i=="string"&&i!==""?i:"html"});if(e){let o=r==="html";return te(ke,{children:[h(we,{field:{label:"Email content",name:"broadcastFormat",options:[{label:"<html>",value:"html"},...n.map(i=>({label:i.name,value:i.id}))],required:!0},path:"broadcastFormat"}),!o&&t.length>0?h(we,{field:{label:"Locale",name:"locale",options:t,required:!1},path:"locale"}):null,o?h(Ge,{field:{admin:{description:"Shown when Email content is <html>."},label:"<html>",name:"htmlBody",required:!0},path:"htmlBody"}):null]})}return te(ke,{children:[a?h(ee,{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,h(Ge,{field:{admin:{description:a?"Optional plain HTML alternative to a Mailchimp template.":"HTML broadcast body."},label:a?"<html> (optional with Mailchimp)":"<html>",name:"htmlBody",required:!a},path:"htmlBody"})]})}function _t({audiences:t,emailBroadcastTemplates:e,localeOptions:a,provider:n}){let r=Ot(),o=Ke(),{t:i}=Qe(),{requestJson:s}=w(),[c,m]=Vt.useState(!1),y=n==="mailchimp",P=e??[],p=n==="resend"&&P.length>0,I=($,j)=>{let T=j,Ae=T.audienceId,Te=T.name,Re=T.subject,Ne=T.htmlBody,Fe=T.templateId,Ie=T.replyTo,De=T.broadcastFormat,Ee=T.locale,_=typeof Ae=="string"?Ae:"",H=typeof Te=="string"?Te.trim():"",U=typeof Re=="string"?Re.trim():"",R=typeof Ne=="string"?Ne.trim():"",re=typeof Fe=="string"?Fe.trim():"",z=typeof Ie=="string"?Ie.trim():"",qe=typeof De=="string"?De.trim():"html",ot=typeof Ee=="string"?Ee.trim():"";m(!0),(async()=>{try{if(!_||!H||!U)throw new Error("Audience, name, and subject are required.");let G=y,rt=p&&qe!=="html";if(p)if(rt)await s("/marketing/broadcasts",{body:JSON.stringify({audienceId:_,emailTemplateId:qe,locale:ot||void 0,name:H,replyTo:z,subject:U}),method:"POST"});else if(R)await s("/marketing/broadcasts",{body:JSON.stringify({audienceId:_,html:R,name:H,replyTo:z,subject:U}),method:"POST"});else throw new Error("<html> is required when using the <html> content option.");else if(G){if(!re&&!R)throw new Error("Provide <html> or a Mailchimp template id.");if(re&&R)throw new Error("Use either <html> or Mailchimp template id, not both.");await s("/marketing/broadcasts",{body:JSON.stringify({audienceId:_,html:R,name:H,replyTo:z,subject:U,templateId:re||void 0}),method:"POST"})}else if(R)await s("/marketing/broadcasts",{body:JSON.stringify({audienceId:_,html:R,name:H,replyTo:z,subject:U}),method:"POST"});else throw new Error("<html> is required for this provider.");o.closeModal(Me),We.success(i("general:successfullyCreated",{label:"Broadcast"})),r.refresh()}catch(G){We.error(G instanceof Error?G.message:"Create failed")}finally{m(!1)}})()};return h(Et,{slug:Me,title:i("general:createNew"),children:te(qt,{className:"flex w-full flex-col gap-8",initialState:p?{broadcastFormat:{value:"html"}}:{},onSubmit:I,waitForAutocomplete:!0,children:[h(we,{field:{label:"Audience",name:"audienceId",options:t.map($=>({label:$.name,value:$.id})),required:!0},path:"audienceId"}),h(ee,{field:{label:"Campaign name",name:"name",required:!0,type:"text"},path:"name"}),h(ee,{field:{label:"Subject",name:"subject",required:!0,type:"text"},path:"subject"}),h(ee,{field:{label:"Reply-to (optional)",name:"replyTo",type:"text"},path:"replyTo"}),h($t,{localeOptions:a,showReactEmailTemplates:p,showTemplateField:y,templateOptions:P}),h(Ye,{className:"w-full",disabled:c,type:"submit",children:i("general:create")})]})})}import{Suspense as Wt}from"react";var Xe="payloadPluginMarketing";function Se(t){return{read:t?.read??!0,write:t?.write??!0}}function L(t){return t?{audiences:Se(t.audiences),contacts:Se(t.contacts),broadcasts:Se(t.broadcasts)}:{audiences:{read:!0,write:!0},broadcasts:{read:!0,write:!0},contacts:{read:!0,write:!0}}}function Ze(t){let e=t.config.custom;if(!e||typeof e!="object")return;let a=e[Xe];if(a?.adapter)return a}function A(t){let e=Ze(t);if(!e)throw new Error(`${Xe}: adapter missing on Payload config. Is marketingPlugin() registered?`);return e}function O(t){return Ze(t)}import{DefaultTemplate as Ht}from"@payloadcms/next/templates";import{jsx as Ut}from"react/jsx-runtime";function V({children:t,initPageResult:e,params:a,searchParams:n}){return Ut(Ht,{i18n:e.req.i18n,locale:e.locale,params:a,payload:e.req.payload,permissions:e.permissions,searchParams:n,user:e.req.user??void 0,visibleEntities:e.visibleEntities,children:t})}function Jt(t){if(typeof t=="string"&&t.trim())return t.trim();if(Array.isArray(t)&&typeof t[0]=="string"&&t[0].trim())return t[0].trim()}function et(t){if(!t)return;let e=Jt(t.id);if(e)return e;let a=t.segments,n=Array.isArray(a)?a.filter(i=>typeof i=="string"&&i.length>0):typeof a=="string"?a.split("/").filter(Boolean):[];if(n.length===0)return;let r=n.lastIndexOf("audience");if(r>=0&&n[r+1])return n[r+1];let o=n[n.length-1];if(o!=="audience")return o}import{Fragment as Qt,jsx as b,jsxs as ae}from"react/jsx-runtime";function Ce({initPageResult:t,params:e,searchParams:a}){let n=et(e);if(!n)throw new Error("No audience id in route params");return b(V,{initPageResult:t,params:e,searchParams:a,children:b(jt,{children:b(Yt,{audienceId:n,initPageResult:t})})})}async function Yt({audienceId:t,initPageResult:e}){let a=O(e.req.payload);if(!a)return b("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=L(a.permissions);if(!n.audiences.read)return b("p",{role:"alert",children:"You do not have permission to view this audience."});let{adapter:r}=A(e.req.payload),o=await r.audiences.get(t);o||Gt();let i=r.urls?.audience?.(t);return ae(Qt,{children:[ae("header",{className:"flex flex-col gap-4",children:[b("h1",{children:o.name}),i?ae(zt,{href:i,rel:"noreferrer noopener",target:"_blank",children:["Open this audience in ",r.label]}):null]}),ae("div",{className:"mt-12 flex flex-col gap-6",children:[n.contacts.write?b("div",{children:b(Z,{audienceId:t,contact:null})}):null,n.contacts.read?b(Wt,{fallback:b("div",{"aria-busy":!0,style:{minHeight:"12rem"}}),children:b(Kt,{audienceId:t,initPageResult:e})}):b("p",{role:"alert",children:"You do not have permission to list contacts."})]})]})}async function Kt({audienceId:t,initPageResult:e}){let{adapter:a}=A(e.req.payload),n=await a.contacts.list({audienceId:t});return b(be,{audienceId:t,contacts:n})}import{Gutter as Xt,Link as tt,Table as Zt}from"@payloadcms/ui";import{Suspense as ea}from"react";import{Fragment as na,jsx as u,jsxs as ne}from"react/jsx-runtime";function xe({basePath:t="",initPageResult:e,params:a,searchParams:n}){return u(V,{initPageResult:e,params:a,searchParams:n,children:u(Xt,{children:u(ta,{basePath:t,initPageResult:e})})})}function ta({basePath:t,initPageResult:e}){let a=O(e.req.payload);if(!a)return u("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=L(a.permissions);if(!n.audiences.read)return u("p",{role:"alert",children:"You do not have permission to view audiences."});let r=a.adapter.urls?.audiences;return ne(na,{children:[ne("header",{className:"flex flex-col gap-4",children:[u("h1",{children:"Audiences"}),r?ne(tt,{href:r,rel:"noreferrer noopener",target:"_blank",children:["View audiences in ",a.adapter.label]}):null]}),ne("div",{className:"mt-4 flex flex-col gap-8",children:[n.audiences.write?u("div",{children:u(ue,{})}):null,u(ea,{fallback:u("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:u(aa,{audiencesWrite:n.audiences.write,basePath:t,initPageResult:e})})]})]})}async function aa({audiencesWrite:t,basePath:e,initPageResult:a}){let{adapter:n}=A(a.req.payload),r=await n.audiences.list(),o={Heading:"Name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:r.map(s=>u("div",{children:u(tt,{href:Le(e,"audience",s.id),children:s.name})},s.id))},i={Heading:"",accessor:"",active:!0,field:{name:"_delete",type:"text"},renderedCells:r.map(s=>u("div",{children:u(me,{audienceId:s.id,audienceName:s.name})},s.id))};return u(Zt,{columns:t?[o,i]:[o],data:r})}import{Gutter as ra,Link as ia}from"@payloadcms/ui";import{Suspense as nt}from"react";function oa(t){let{label:e,code:a}=t;if(typeof e=="string")return e;if(e&&typeof e=="object"){for(let n of Object.values(e))if(typeof n=="string")return n}return a}function at(t){let e=t.localization;if(e===!1||e===void 0)return[];let a=e.locales;return a?.length?a.map(n=>({label:oa(n),value:n.code})):[]}import{Fragment as ca,jsx as g,jsxs as oe}from"react/jsx-runtime";function Be({initPageResult:t,params:e,searchParams:a}){return g(V,{initPageResult:t,params:e,searchParams:a,children:g(ra,{children:g(sa,{initPageResult:t})})})}function sa({initPageResult:t}){let e=O(t.req.payload);if(!e)return g("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let a=L(e.permissions);if(!a.broadcasts.read)return g("p",{role:"alert",children:"You do not have permission to view broadcasts."});let{adapter:n}=A(t.req.payload),r=n.urls?.broadcasts;return oe(ca,{children:[oe("header",{className:"flex flex-col gap-4",children:[g("h1",{children:"Campaigns"}),r?oe(ia,{href:r,rel:"noreferrer noopener",target:"_blank",children:["View campaigns in ",n.label]}):null]}),oe("div",{className:"mt-4 flex flex-col gap-8",children:[a.broadcasts.write?g("div",{children:g(nt,{fallback:g("div",{"aria-busy":!0,style:{minHeight:"2.5rem"}}),children:g(la,{initPageResult:t})})}):null,g(nt,{fallback:g("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:g(da,{initPageResult:t})})]})]})}async function la({initPageResult:t}){let e=A(t.req.payload),{adapter:a}=e,n=await a.audiences.list(),r=e.emailBroadcastTemplates?.map(({id:i,name:s})=>({id:i,name:s}))??[],o=at(t.req.payload.config);return g(ve,{audiences:n,emailBroadcastTemplates:r,localeOptions:o,provider:a.provider})}async function da({initPageResult:t}){let{adapter:e}=A(t.req.payload),n=(await e.broadcasts.list()).map(r=>({...r,externalDashboardUrl:e.urls?.broadcast?.(r.id)}));return g(se,{broadcasts:n})}export{Ce as AudienceDetail,xe as AudienceList,Be as BroadcastList};
|
|
1
|
+
import{Gutter as C,Link as q}from"@payloadcms/ui";import{notFound as T}from"next/navigation";import{AudienceContactsTable as N,EditContactButton as D}from"payload-plugin-marketing/admin/client";import{Suspense as E}from"react";var v="payloadPluginMarketing";function k(e){return{read:e?.read??!0,write:e?.write??!0}}function p(e){return e?{audiences:k(e.audiences),contacts:k(e.contacts),broadcasts:k(e.broadcasts)}:{audiences:{read:!0,write:!0},broadcasts:{read:!0,write:!0},contacts:{read:!0,write:!0}}}function A(e){let t=e.config.custom;if(!t||typeof t!="object")return;let r=t[v];if(r?.adapter)return r}function u(e){let t=A(e);if(!t)throw new Error(`${v}: adapter missing on Payload config. Is marketingPlugin() registered?`);return t}function m(e){return A(e)}import{DefaultTemplate as I}from"@payloadcms/next/templates";import{jsx as L}from"react/jsx-runtime";function f({children:e,initPageResult:t,params:r,searchParams:n}){return L(I,{i18n:t.req.i18n,locale:t.locale,params:r,payload:t.req.payload,permissions:t.permissions,searchParams:n,user:t.req.user??void 0,visibleEntities:t.visibleEntities,children:e})}function R(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 S(e){if(!e)return;let t=R(e.id);if(t)return t;let r=e.segments,n=Array.isArray(r)?r.filter(l=>typeof l=="string"&&l.length>0):typeof r=="string"?r.split("/").filter(Boolean):[];if(n.length===0)return;let i=n.lastIndexOf("audience");if(i>=0&&n[i+1])return n[i+1];let s=n[n.length-1];if(s!=="audience")return s}import{Fragment as F,jsx as d,jsxs as g}from"react/jsx-runtime";function w({initPageResult:e,params:t,searchParams:r}){let n=S(t);if(!n)throw new Error("No audience id in route params");return d(f,{initPageResult:e,params:t,searchParams:r,children:d(C,{children:d(G,{audienceId:n,initPageResult:e})})})}async function G({audienceId:e,initPageResult:t}){let r=m(t.req.payload);if(!r)return d("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=p(r.permissions);if(!n.audiences.read)return d("p",{role:"alert",children:"You do not have permission to view this audience."});let{adapter:i}=u(t.req.payload),s=await i.audiences.get(e);s||T();let l=i.urls?.audience?.(e);return g(F,{children:[g("header",{className:"flex flex-col gap-4",children:[d("h1",{children:s.name}),l?g(q,{href:l,rel:"noreferrer noopener",target:"_blank",children:["Open this audience in ",i.label]}):null]}),g("div",{className:"mt-12 flex flex-col gap-6",children:[n.contacts.write?d("div",{children:d(D,{audienceId:e,contact:null})}):null,n.contacts.read?d(E,{fallback:d("div",{"aria-busy":!0,style:{minHeight:"12rem"}}),children:d(O,{audienceId:e,initPageResult:t})}):d("p",{role:"alert",children:"You do not have permission to list contacts."})]})]})}async function O({audienceId:e,initPageResult:t}){let{adapter:r}=u(t.req.payload),n=await r.contacts.list({audienceId:e});return d(N,{audienceId:e,contacts:n})}import{Gutter as _,Link as x,Table as $}from"@payloadcms/ui";import{CreateAudienceButton as z,DeleteAudienceButton as U}from"payload-plugin-marketing/admin/client";import{Suspense as Y}from"react";function H(e,...t){let r=e.replace(/\/+$/,"")||"",n=t.flatMap(s=>String(s).split("/")).map(s=>s.replace(/^\/+|\/+$/g,"")).filter(Boolean).join("/");return(r===""?`/${n}`:`${r}/${n}`).replace(/\/{2,}/g,"/")}function M(e,...t){let n=[e?.replace(/^\/+|\/+$/g,"")??"",...t].filter(Boolean);return H("/admin",...n)}import{Fragment as j,jsx as a,jsxs as y}from"react/jsx-runtime";function b({basePath:e="",initPageResult:t,params:r,searchParams:n}){return a(f,{initPageResult:t,params:r,searchParams:n,children:a(_,{children:a(K,{basePath:e,initPageResult:t})})})}function K({basePath:e,initPageResult:t}){let r=m(t.req.payload);if(!r)return a("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let n=p(r.permissions);if(!n.audiences.read)return a("p",{role:"alert",children:"You do not have permission to view audiences."});let i=r.adapter.urls?.audiences;return y(j,{children:[y("header",{className:"flex flex-col gap-4",children:[a("h1",{children:"Audiences"}),i?y(x,{href:i,rel:"noreferrer noopener",target:"_blank",children:["View audiences in ",r.adapter.label]}):null]}),y("div",{className:"mt-4 flex flex-col gap-8",children:[n.audiences.write?a("div",{children:a(z,{})}):null,a(Y,{fallback:a("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:a(W,{audiencesWrite:n.audiences.write,basePath:e,initPageResult:t})})]})]})}async function W({audiencesWrite:e,basePath:t,initPageResult:r}){let{adapter:n}=u(r.req.payload),i=await n.audiences.list(),s={Heading:"Name",accessor:"name",active:!0,field:{name:"name",type:"text"},renderedCells:i.map(c=>a("div",{children:a(x,{href:M(t,"audience",c.id),children:c.name})},c.id))},l={Heading:"",accessor:"",active:!0,field:{name:"_delete",type:"text"},renderedCells:i.map(c=>a("div",{children:a(U,{audienceId:c.id,audienceName:c.name})},c.id))};return a($,{columns:e?[s,l]:[s],data:i})}import{Gutter as Q,Link as X}from"@payloadcms/ui";import{BroadcastsTable as Z,CreateBroadcastButton as ee}from"payload-plugin-marketing/admin/client";import{Suspense as B}from"react";function J(e){let{label:t,code:r}=e;if(typeof t=="string")return t;if(t&&typeof t=="object"){for(let n of Object.values(t))if(typeof n=="string")return n}return r}function V(e){let t=e.localization;if(t===!1||t===void 0)return[];let r=t.locales;return r?.length?r.map(n=>({label:J(n),value:n.code})):[]}import{Fragment as ie,jsx as o,jsxs as P}from"react/jsx-runtime";function h({initPageResult:e,params:t,searchParams:r}){return o(f,{initPageResult:e,params:t,searchParams:r,children:o(Q,{children:o(te,{initPageResult:e})})})}function te({initPageResult:e}){let t=m(e.req.payload);if(!t)return o("p",{role:"alert",children:"Marketing plugin is not configured (missing adapter on Payload config)."});let r=p(t.permissions);if(!r.broadcasts.read)return o("p",{role:"alert",children:"You do not have permission to view broadcasts."});let{adapter:n}=u(e.req.payload),i=n.urls?.broadcasts;return P(ie,{children:[P("header",{className:"flex flex-col gap-4",children:[o("h1",{children:"Campaigns"}),i?P(X,{href:i,rel:"noreferrer noopener",target:"_blank",children:["View campaigns in ",n.label]}):null]}),P("div",{className:"mt-4 flex flex-col gap-8",children:[r.broadcasts.write?o("div",{children:o(B,{fallback:o("div",{"aria-busy":!0,style:{minHeight:"2.5rem"}}),children:o(re,{initPageResult:e})})}):null,o(B,{fallback:o("div",{"aria-busy":!0,style:{minHeight:"4rem"}}),children:o(ne,{initPageResult:e})})]})]})}async function re({initPageResult:e}){let t=u(e.req.payload),{adapter:r}=t,n=await r.audiences.list(),i=t.emailBroadcastTemplates?.map(({id:l,name:c})=>({id:l,name:c}))??[],s=V(e.req.payload.config);return o(ee,{audiences:n,emailBroadcastTemplates:i,localeOptions:s,provider:r.provider})}async function ne({initPageResult:e}){let{adapter:t}=u(e.req.payload),n=(await t.broadcasts.list()).map(i=>({...i,externalDashboardUrl:t.urls?.broadcast?.(i.id)}));return o(Z,{broadcasts:n})}export{w as AudienceDetail,b as AudienceList,h as BroadcastList};
|
|
2
2
|
//# sourceMappingURL=server.js.map
|
package/dist/admin/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/components/audience-detail.tsx","../../src/admin/paths.ts","../../src/admin/use-marketing-api.ts","../../src/admin/components/broadcasts-table.tsx","../../src/admin/date-format.ts","../../src/admin/components/payload-modal.tsx","../../src/admin/components/audience-buttons.tsx","../../src/admin/components/contacts-table.tsx","../../src/admin/components/create-broadcast-button.tsx","../../src/marketing-integration.ts","../../src/admin/components/marketing-view-shell.tsx","../../src/admin/components/view-params.ts","../../src/admin/components/audience-list.tsx","../../src/admin/components/broadcast-list.tsx","../../src/admin/locale-options.ts"],"sourcesContent":["import { Gutter, Link } from \"@payloadcms/ui\"\nimport { notFound } from \"next/navigation\"\nimport { AudienceContactsTable, EditContactButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 <AudienceContactsTable audienceId={audienceId} contacts={contacts} />\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","\"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(\n () => `${context.serverURL ?? \"\"}${context.routes?.api ?? \"/api\"}`,\n [context.routes?.api, 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 (restInit.body !== undefined && restInit.body !== \"\" && restInit.body !== null) {\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","\"use client\"\n\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\"\nimport React from \"react\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport { useMarketingApi } from \"../use-marketing-api\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\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) => (\n <div key={b.id}>{formatMarketingDate(b.sentAt)}</div>\n )),\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\n href={broadcast.externalDashboardUrl}\n rel=\"noreferrer noopener\"\n target=\"_blank\"\n >\n <Pill>dashboard ↗</Pill>\n </Link>\n ) : null}\n {broadcast.status === \"draft\" || broadcast.status === \"save\" ? (\n <>\n <DeleteBroadcastButton\n broadcastId={broadcast.id}\n broadcastName={broadcast.name}\n />\n <SendBroadcastButton\n broadcastId={broadcast.id}\n broadcastName={broadcast.name}\n />\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)}`, {\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>{`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\n style={{ display: \"flex\", gap: \"8px\", justifyContent: \"flex-end\" }}\n >\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","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 { Button, Modal, useModal, useTranslation } from \"@payloadcms/ui\"\nimport React from \"react\"\n\nfunction cn(...parts: Array<string | undefined | false | null>): string {\n return parts.filter(Boolean).join(\" \")\n}\n\nconst PayloadModalContext = React.createContext({\n modalSlug: \"\",\n})\n\ninterface PayloadModalProps extends React.ComponentProps<typeof Modal> {\n children: React.ReactNode\n}\n\nfunction PayloadModal({ children, 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 {/* Fix hydration error */}\n {loaded && (\n <Modal slug={modalSlug} className={cn(\"confirmation-modal\", className)} {...props}>\n {children}\n </Modal>\n )}\n </PayloadModalContext.Provider>\n )\n}\n\nfunction PayloadModalContent({ children, className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"confirmation-modal__wrapper\", className)}\n data-slot=\"payload-modal-content\"\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction PayloadModalBody({ children, className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"confirmation-modal__content\", className)}\n data-slot=\"payload-modal-body\"\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction PayloadModalTitle({ children, className, ...props }: React.ComponentProps<\"h1\">) {\n return (\n <h1 className={cn(\"\", className)} data-slot=\"payload-modal-title\" {...props}>\n {children}\n </h1>\n )\n}\n\nfunction PayloadModalFooter({ children, className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\"confirmation-modal__controls\", className)}\n data-slot=\"payload-modal-footer\"\n {...props}\n >\n {children}\n </div>\n )\n}\n\nfunction PayloadModalClose({ children, 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 className={cn(\"\", className)}\n buttonStyle=\"secondary\"\n size=\"large\"\n data-slot=\"payload-modal-close\"\n {...props}\n onClick={() => modal.closeModal(modalSlug)}\n >\n {children ?? t(\"general:cancel\")}\n </Button>\n )\n}\n\nexport {\n PayloadModal,\n PayloadModalContent,\n PayloadModalBody,\n PayloadModalTitle,\n PayloadModalFooter,\n PayloadModalClose,\n}\n","\"use client\"\n\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\"\nimport { useTransition } from \"react\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n PayloadModalTitle,\n} from \"./payload-modal\"\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) =>\n typeof v === \"string\" && v.trim().length > 0 ? true : \"Name is required\"\n }\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","\"use client\"\n\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 React from \"react\"\nimport ReactRaw from \"react\"\nimport { useTransition } from \"react\"\n\nimport { formatMarketingDate } from \"../date-format\"\nimport { useMarketingApi } from \"../use-marketing-api\"\nimport {\n PayloadModal,\n PayloadModalBody,\n PayloadModalClose,\n PayloadModalContent,\n PayloadModalFooter,\n} from \"./payload-modal\"\n\nimport type { MarketingContact } from \"../../types\"\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(\n `/marketing/audiences/${encodeURIComponent(audienceId)}/contacts/${encodeURIComponent(contactId)}`,\n {\n method: \"DELETE\",\n },\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\n {...(contact ? {} : { size: \"large\" })}\n onClick={() => modal.openModal(slug)}\n type=\"button\"\n >\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) =>\n typeof v === \"string\" && v.includes(\"@\") ? true : \"Valid email required\"\n }\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","\"use client\"\n\nimport {\n Button,\n Drawer,\n Form,\n SelectField,\n TextareaField,\n TextField,\n toast,\n useFormFields,\n useModal,\n useTranslation,\n} from \"@payloadcms/ui\"\nimport { useRouter } from \"next/navigation\"\nimport React from \"react\"\n\nimport { useMarketingApi } from \"../use-marketing-api\"\n\nimport type { MarketingAudience } from \"../../types\"\nimport type { Data, FormState } from \"payload\"\n\nconst modalSlug = \"create-marketing-broadcast\"\n\nexport function CreateBroadcastButton({\n audiences,\n emailBroadcastTemplates,\n localeOptions,\n provider,\n}: {\n audiences: MarketingAudience[]\n emailBroadcastTemplates?: { id: string; name: string }[]\n localeOptions?: { label: string; value: string }[]\n provider: string\n}) {\n const modal = useModal()\n const { t } = useTranslation()\n\n return (\n <>\n <CreateBroadcastModal\n audiences={audiences}\n emailBroadcastTemplates={emailBroadcastTemplates}\n localeOptions={localeOptions ?? []}\n provider={provider}\n />\n <Button onClick={() => modal.openModal(modalSlug)} size=\"large\" type=\"button\">\n {t(\"general:createNew\")}\n </Button>\n </>\n )\n}\n\nfunction BroadcastContentFields({\n localeOptions,\n showReactEmailTemplates,\n showTemplateField,\n templateOptions,\n}: {\n localeOptions: { label: string; value: string }[]\n showReactEmailTemplates: boolean\n showTemplateField: boolean\n templateOptions: { id: string; name: string }[]\n}) {\n const broadcastFormat = useFormFields(([fields]) => {\n if (!showReactEmailTemplates) {\n return \"html\"\n }\n const v = fields?.broadcastFormat?.value\n return typeof v === \"string\" && v !== \"\" ? v : \"html\"\n })\n\n if (showReactEmailTemplates) {\n const isHtml = broadcastFormat === \"html\"\n return (\n <>\n <SelectField\n field={{\n label: \"Email content\",\n name: \"broadcastFormat\",\n options: [\n { label: \"<html>\", value: \"html\" },\n ...templateOptions.map((opt) => ({ label: opt.name, value: opt.id })),\n ],\n required: true,\n }}\n path=\"broadcastFormat\"\n />\n {!isHtml && localeOptions.length > 0 ? (\n <SelectField\n field={{\n label: \"Locale\",\n name: \"locale\",\n options: localeOptions,\n required: false,\n }}\n path=\"locale\"\n />\n ) : null}\n {isHtml ? (\n <TextareaField\n field={{\n admin: {\n description: \"Shown when Email content is <html>.\",\n },\n label: \"<html>\",\n name: \"htmlBody\",\n required: true,\n }}\n path=\"htmlBody\"\n />\n ) : null}\n </>\n )\n }\n\n return (\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 <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> (optional with Mailchimp)\" : \"<html>\",\n name: \"htmlBody\",\n required: !showTemplateField,\n }}\n path=\"htmlBody\"\n />\n </>\n )\n}\n\nfunction CreateBroadcastModal({\n audiences,\n emailBroadcastTemplates,\n localeOptions,\n provider,\n}: {\n audiences: MarketingAudience[]\n emailBroadcastTemplates?: { id: string; name: string }[]\n localeOptions: { label: string; value: string }[]\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 const templateOptions = emailBroadcastTemplates ?? []\n const showReactEmailTemplates = provider === \"resend\" && templateOptions.length > 0\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 broadcastFormatRaw: unknown = row.broadcastFormat\n const localeRaw: unknown = row.locale\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 const broadcastFormat =\n typeof broadcastFormatRaw === \"string\" ? broadcastFormatRaw.trim() : \"html\"\n const locale = typeof localeRaw === \"string\" ? localeRaw.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\n const mailchimpMode = showTemplateField\n const usingReactTemplate = showReactEmailTemplates && broadcastFormat !== \"html\"\n\n if (showReactEmailTemplates) {\n if (usingReactTemplate) {\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n emailTemplateId: broadcastFormat,\n locale: locale || undefined,\n name,\n replyTo,\n subject,\n }),\n method: \"POST\",\n })\n } else if (!htmlBody) {\n throw new Error(\"<html> is required when using the <html> content option.\")\n } else {\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n html: htmlBody,\n name,\n replyTo,\n subject,\n }),\n method: \"POST\",\n })\n }\n } else if (mailchimpMode) {\n if (!templateId && !htmlBody) {\n throw new Error(\"Provide <html> or a Mailchimp template id.\")\n }\n if (templateId && htmlBody) {\n throw new Error(\"Use either <html> or Mailchimp template id, not both.\")\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 } else if (!htmlBody) {\n throw new Error(\"<html> is required for this provider.\")\n } else {\n await requestJson(\"/marketing/broadcasts\", {\n body: JSON.stringify({\n audienceId,\n html: htmlBody,\n name,\n replyTo,\n subject,\n }),\n method: \"POST\",\n })\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={showReactEmailTemplates ? { broadcastFormat: { value: \"html\" } } : {}}\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 <BroadcastContentFields\n localeOptions={localeOptions}\n showReactEmailTemplates={showReactEmailTemplates}\n showTemplateField={showTemplateField}\n templateOptions={templateOptions}\n />\n\n <Button className=\"w-full\" disabled={isPending} type=\"submit\">\n {t(\"general:create\")}\n </Button>\n </Form>\n </Drawer>\n )\n}\n","import type {\n MarketingAdapter,\n MarketingEffectivePermissions,\n MarketingEmailBroadcastTemplate,\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 emailBroadcastTemplates?: MarketingEmailBroadcastTemplate[]\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(\n payload: Payload,\n): MarketingIntegrationState | undefined {\n return readIntegration(payload)\n}\n\nexport function getMarketingIntegrationFromRequest(req: PayloadRequest): MarketingIntegrationState {\n return getMarketingIntegration(req.payload)\n}\n","import { DefaultTemplate } from \"@payloadcms/next/templates\"\n\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 { Gutter, Link, Table } from \"@payloadcms/ui\"\nimport { CreateAudienceButton, DeleteAudienceButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { marketingAdminHref } from \"../paths\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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","import { Gutter, Link } from \"@payloadcms/ui\"\nimport {\n BroadcastsTable,\n CreateBroadcastButton,\n type MarketingBroadcastRow,\n} from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { getLocaleSelectOptionsFromConfig } from \"../locale-options\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 integration = getMarketingIntegration(initPageResult.req.payload)\n const { adapter } = integration\n const audiences = await adapter.audiences.list()\n const emailBroadcastTemplates =\n integration.emailBroadcastTemplates?.map(({ id, name }) => ({ id, name })) ?? []\n const localeOptions = getLocaleSelectOptionsFromConfig(initPageResult.req.payload.config)\n return (\n <CreateBroadcastButton\n audiences={audiences}\n emailBroadcastTemplates={emailBroadcastTemplates}\n localeOptions={localeOptions}\n provider={adapter.provider}\n />\n )\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","import type { Locale, SanitizedConfig } from \"payload\"\n\nfunction labelForLocale(loc: Locale): string {\n const { label, code } = loc\n if (typeof label === \"string\") {\n return label\n }\n if (label && typeof label === \"object\") {\n for (const value of Object.values(label)) {\n if (typeof value === \"string\") {\n return value\n }\n }\n }\n return code\n}\n\n/** Options for admin selects; values are locale codes from `config.localization.locales`. */\nexport function getLocaleSelectOptionsFromConfig(\n config: SanitizedConfig,\n): { label: string; value: string }[] {\n const raw = config.localization\n if (raw === false || raw === undefined) {\n return []\n }\n const locales = raw.locales\n if (!locales?.length) {\n return []\n }\n return locales.map((locItem: Locale) => ({\n label: labelForLocale(locItem),\n value: locItem.code,\n }))\n}\n"],"mappings":"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","names":["Gutter","Link","notFound","joinAdminSegments","adminRoute","segments","trimmedAdmin","body","s","segment","marketingAdminHref","basePath","parts","useConfig","useCallback","useMemo","useMarketingApi","context","base","requestJson","pathSegment","init","_headersIgnored","restInit","headers","res","detail","parsed","PayloadButton","DateTimeField","Form","Pagination","Pill","Table","toast","useModal","useTranslation","Link","useRouter","React","formatMarketingDate","iso","d","Button","Modal","useModal","useTranslation","React","jsx","cn","parts","PayloadModalContext","PayloadModal","children","className","modalSlug","props","loaded","setLoaded","PayloadModalContent","PayloadModalBody","PayloadModalTitle","PayloadModalFooter","PayloadModalClose","t","modal","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","Button","Form","TextField","toast","useModal","useTranslation","PayloadButton","useRouter","useTransition","Fragment","jsx","jsxs","createAudienceSlug","CreateAudienceButton","modal","useModal","t","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","modalSlug","confirmDelete","PayloadButton","CheckboxField","Form","Pagination","Table","TextField","toast","useModal","useTranslation","PayloadButton","useRouter","React","ReactRaw","useTransition","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","Button","Drawer","Form","SelectField","TextareaField","TextField","toast","useFormFields","useModal","useTranslation","useRouter","React","Fragment","jsx","jsxs","modalSlug","CreateBroadcastButton","audiences","emailBroadcastTemplates","localeOptions","provider","modal","useModal","t","useTranslation","CreateBroadcastModal","Button","BroadcastContentFields","showReactEmailTemplates","showTemplateField","templateOptions","broadcastFormat","useFormFields","fields","v","isHtml","SelectField","opt","TextareaField","TextField","router","useRouter","requestJson","useMarketingApi","isPending","setIsPending","React","submit","data","row","audienceIdRaw","nameRaw","subjectRaw","htmlRaw","templateIdRaw","replyToRaw","broadcastFormatRaw","localeRaw","audienceId","name","subject","htmlBody","templateId","replyTo","locale","mailchimpMode","usingReactTemplate","toast","err","Drawer","Form","a","Suspense","MARKETING_CUSTOM_CONFIG_KEY","effectiveResource","slice","resolveMarketingPermissions","permissions","readIntegration","payload","custom","slice","MARKETING_CUSTOM_CONFIG_KEY","getMarketingIntegration","state","tryGetMarketingIntegration","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","Gutter","Link","Table","Suspense","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","Gutter","Link","Suspense","labelForLocale","loc","label","code","value","getLocaleSelectOptionsFromConfig","config","raw","locales","locItem","Fragment","jsx","jsxs","BroadcastList","initPageResult","params","searchParams","MarketingViewShell","Gutter","BroadcastListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","broadcastsUrl","Link","Suspense","CreateBroadcastRegion","BroadcastTableRegion","audiences","emailBroadcastTemplates","id","name","localeOptions","getLocaleSelectOptionsFromConfig","CreateBroadcastButton","broadcasts","b","BroadcastsTable"]}
|
|
1
|
+
{"version":3,"sources":["../../src/admin/components/audience-detail.tsx","../../src/marketing-integration.ts","../../src/admin/components/marketing-view-shell.tsx","../../src/admin/components/view-params.ts","../../src/admin/components/audience-list.tsx","../../src/admin/paths.ts","../../src/admin/components/broadcast-list.tsx","../../src/admin/locale-options.ts"],"sourcesContent":["import { Gutter, Link } from \"@payloadcms/ui\"\nimport { notFound } from \"next/navigation\"\nimport { AudienceContactsTable, EditContactButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 <AudienceContactsTable audienceId={audienceId} contacts={contacts} />\n}\n","import type {\n MarketingAdapter,\n MarketingEffectivePermissions,\n MarketingEmailBroadcastTemplate,\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 emailBroadcastTemplates?: MarketingEmailBroadcastTemplate[]\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(\n payload: Payload,\n): MarketingIntegrationState | undefined {\n return readIntegration(payload)\n}\n\nexport function getMarketingIntegrationFromRequest(req: PayloadRequest): MarketingIntegrationState {\n return getMarketingIntegration(req.payload)\n}\n","import { DefaultTemplate } from \"@payloadcms/next/templates\"\n\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 { Gutter, Link, Table } from \"@payloadcms/ui\"\nimport { CreateAudienceButton, DeleteAudienceButton } from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { marketingAdminHref } from \"../paths\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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","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 { Gutter, Link } from \"@payloadcms/ui\"\nimport {\n BroadcastsTable,\n CreateBroadcastButton,\n type MarketingBroadcastRow,\n} from \"../client\"\nimport { Suspense } from \"react\"\n\nimport {\n getMarketingIntegration,\n resolveMarketingPermissions,\n tryGetMarketingIntegration,\n} from \"../../marketing-integration\"\nimport { getLocaleSelectOptionsFromConfig } from \"../locale-options\"\nimport { MarketingViewShell } from \"./marketing-view-shell\"\n\nimport type { AdminViewServerProps } from \"payload\"\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\">Marketing plugin is not configured (missing adapter on Payload config).</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 integration = getMarketingIntegration(initPageResult.req.payload)\n const { adapter } = integration\n const audiences = await adapter.audiences.list()\n const emailBroadcastTemplates =\n integration.emailBroadcastTemplates?.map(({ id, name }) => ({ id, name })) ?? []\n const localeOptions = getLocaleSelectOptionsFromConfig(initPageResult.req.payload.config)\n return (\n <CreateBroadcastButton\n audiences={audiences}\n emailBroadcastTemplates={emailBroadcastTemplates}\n localeOptions={localeOptions}\n provider={adapter.provider}\n />\n )\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","import type { Locale, SanitizedConfig } from \"payload\"\n\nfunction labelForLocale(loc: Locale): string {\n const { label, code } = loc\n if (typeof label === \"string\") {\n return label\n }\n if (label && typeof label === \"object\") {\n for (const value of Object.values(label)) {\n if (typeof value === \"string\") {\n return value\n }\n }\n }\n return code\n}\n\n/** Options for admin selects; values are locale codes from `config.localization.locales`. */\nexport function getLocaleSelectOptionsFromConfig(\n config: SanitizedConfig,\n): { label: string; value: string }[] {\n const raw = config.localization\n if (raw === false || raw === undefined) {\n return []\n }\n const locales = raw.locales\n if (!locales?.length) {\n return []\n }\n return locales.map((locItem: Locale) => ({\n label: labelForLocale(locItem),\n value: locItem.code,\n }))\n}\n"],"mappings":"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","names":["Gutter","Link","notFound","AudienceContactsTable","EditContactButton","Suspense","MARKETING_CUSTOM_CONFIG_KEY","effectiveResource","slice","resolveMarketingPermissions","permissions","readIntegration","payload","custom","slice","MARKETING_CUSTOM_CONFIG_KEY","getMarketingIntegration","state","tryGetMarketingIntegration","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","AudienceContactsTable","Gutter","Link","Table","CreateAudienceButton","DeleteAudienceButton","Suspense","joinAdminSegments","adminRoute","segments","trimmedAdmin","body","segment","marketingAdminHref","basePath","parts","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","Gutter","Link","BroadcastsTable","CreateBroadcastButton","Suspense","labelForLocale","loc","label","code","value","getLocaleSelectOptionsFromConfig","config","raw","locales","locItem","Fragment","jsx","jsxs","BroadcastList","initPageResult","params","searchParams","MarketingViewShell","Gutter","BroadcastListBody","integration","tryGetMarketingIntegration","effective","resolveMarketingPermissions","adapter","getMarketingIntegration","broadcastsUrl","Link","Suspense","CreateBroadcastRegion","BroadcastTableRegion","audiences","emailBroadcastTemplates","id","name","localeOptions","getLocaleSelectOptionsFromConfig","CreateBroadcastButton","broadcasts","b","BroadcastsTable"]}
|