payload-plugin-newsletter 0.20.6 → 0.20.7

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/CHANGELOG.md CHANGED
@@ -1,3 +1,47 @@
1
+ ## [0.20.7] - 2025-08-02
2
+
3
+ ### Added
4
+ - **Comprehensive Email Wrapper System** - Unified email rendering that uses the same wrapper for previews and actual sends
5
+ - Preview component now passes ALL form fields to the preview endpoint as `documentData`
6
+ - Custom wrappers receive complete document data, not just content
7
+ - Consistent HTML output between preview and actual email sends
8
+ - Support for accessing any custom fields added to broadcasts collection
9
+ - Wrapper is applied during actual send operations, not just previews
10
+
11
+ ### Enhanced
12
+ - **Email Preview Component** - Builds document data from all form fields for wrapper access
13
+ - Collects all field values using `useFormFields` hook
14
+ - Passes complete form state to preview endpoint
15
+ - Enables custom wrappers to access metadata like slug, issueNumber, custom fields
16
+
17
+ - **Preview Endpoint** - Updated to accept and forward documentData to email wrapper
18
+ - Receives documentData from preview component
19
+ - Passes through to convertToEmailSafeHtml function
20
+ - Maintains backward compatibility with existing implementations
21
+
22
+ - **Email Wrapper Interface** - Enhanced type definitions for better developer experience
23
+ - Added `EmailWrapperOptions` interface with documentData support
24
+ - Updated `CustomEmailWrapper` type for consistency
25
+ - Generic `Record<string, any>` allows any custom fields
26
+
27
+ - **Broadcast Sync Hooks** - Now apply wrapper during actual email sends
28
+ - Create operation uses wrapper when syncing to provider
29
+ - Update operation maintains wrapper consistency
30
+ - Deferred creates (from draft to published) include wrapper
31
+ - Same HTML template used for both preview and actual sends
32
+
33
+ ### Technical Changes
34
+ - Updated `convertToEmailSafeHtml` to accept documentData in options
35
+ - Modified all sync operations in Broadcasts collection to use email preview config
36
+ - Wrapper customization now available throughout the email lifecycle
37
+ - No breaking changes - wrapper remains optional with sensible defaults
38
+
39
+ ### Benefits
40
+ - **Flexibility** - Users can pass any custom fields without plugin modifications
41
+ - **Consistency** - Identical HTML in preview and actual email sends
42
+ - **Future Proof** - Add new fields to broadcasts without updating plugin code
43
+ - **No Breaking Changes** - Existing implementations continue to work unchanged
44
+
1
45
  ## [0.20.6] - 2025-08-01
2
46
 
3
47
  ### Fixed
package/dist/admin.js CHANGED
@@ -22,10 +22,20 @@ var BroadcastInlinePreview = () => {
22
22
  setLoading(false);
23
23
  return;
24
24
  }
25
+ const documentData = {};
26
+ Object.entries(fields || {}).forEach(([key, field]) => {
27
+ if (field && typeof field === "object" && "value" in field) {
28
+ documentData[key] = field.value;
29
+ }
30
+ });
25
31
  const response = await fetch("/api/broadcasts/preview", {
26
32
  method: "POST",
27
33
  headers: { "Content-Type": "application/json" },
28
- body: JSON.stringify({ content: contentValue })
34
+ body: JSON.stringify({
35
+ content: contentValue,
36
+ documentData
37
+ // Pass all form data
38
+ })
29
39
  });
30
40
  if (!response.ok) {
31
41
  throw new Error(`Preview failed: ${response.statusText}`);
@@ -979,7 +979,8 @@ async function convertToEmailSafeHtml(editorState, options) {
979
979
  if (options.customWrapper) {
980
980
  return await Promise.resolve(options.customWrapper(sanitizedHtml, {
981
981
  preheader: options.preheader,
982
- subject: options.subject
982
+ subject: options.subject,
983
+ documentData: options.documentData
983
984
  }));
984
985
  }
985
986
  return wrapInEmailTemplate(sanitizedHtml, options.preheader);
@@ -1866,7 +1867,7 @@ var createBroadcastPreviewEndpoint = (config, _collectionSlug) => {
1866
1867
  handler: async (req) => {
1867
1868
  try {
1868
1869
  const data = await (req.json?.() || Promise.resolve({}));
1869
- const { content, preheader, subject } = data;
1870
+ const { content, preheader, subject, documentData } = data;
1870
1871
  if (!content) {
1871
1872
  return Response.json({
1872
1873
  success: false,
@@ -1882,6 +1883,8 @@ var createBroadcastPreviewEndpoint = (config, _collectionSlug) => {
1882
1883
  preheader,
1883
1884
  subject,
1884
1885
  mediaUrl,
1886
+ documentData,
1887
+ // Pass all document data
1885
1888
  customBlockConverter: config.customizations?.broadcasts?.customBlockConverter,
1886
1889
  customWrapper: emailPreviewConfig?.customWrapper
1887
1890
  });
@@ -2181,7 +2184,14 @@ var createBroadcastsCollection = (pluginConfig) => {
2181
2184
  const provider = new BroadcastApiProvider2(providerConfig);
2182
2185
  req.payload.logger.info("Populating media fields and converting content to HTML...");
2183
2186
  const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
2187
+ const emailPreviewConfig = pluginConfig.customizations?.broadcasts?.emailPreview;
2184
2188
  const htmlContent = await convertToEmailSafeHtml(populatedContent, {
2189
+ wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,
2190
+ customWrapper: emailPreviewConfig?.customWrapper,
2191
+ preheader: doc.contentSection?.preheader,
2192
+ subject: doc.subject,
2193
+ documentData: doc,
2194
+ // Pass entire document
2185
2195
  customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
2186
2196
  });
2187
2197
  if (!htmlContent || htmlContent.trim() === "") {
@@ -2281,7 +2291,14 @@ var createBroadcastsCollection = (pluginConfig) => {
2281
2291
  }
2282
2292
  req.payload.logger.info("Creating broadcast in provider (deferred from initial create)...");
2283
2293
  const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
2294
+ const emailPreviewConfig = pluginConfig.customizations?.broadcasts?.emailPreview;
2284
2295
  const htmlContent = await convertToEmailSafeHtml(populatedContent, {
2296
+ wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,
2297
+ customWrapper: emailPreviewConfig?.customWrapper,
2298
+ preheader: doc.contentSection?.preheader,
2299
+ subject: doc.subject,
2300
+ documentData: doc,
2301
+ // Pass entire document
2285
2302
  customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
2286
2303
  });
2287
2304
  if (!htmlContent || htmlContent.trim() === "") {
@@ -2343,7 +2360,14 @@ var createBroadcastsCollection = (pluginConfig) => {
2343
2360
  }
2344
2361
  if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {
2345
2362
  const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
2363
+ const emailPreviewConfig = pluginConfig.customizations?.broadcasts?.emailPreview;
2346
2364
  updates.content = await convertToEmailSafeHtml(populatedContent, {
2365
+ wrapInTemplate: emailPreviewConfig?.wrapInTemplate ?? true,
2366
+ customWrapper: emailPreviewConfig?.customWrapper,
2367
+ preheader: doc.contentSection?.preheader,
2368
+ subject: doc.subject,
2369
+ documentData: doc,
2370
+ // Pass entire document
2347
2371
  customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
2348
2372
  });
2349
2373
  }