payload-plugin-newsletter 0.17.4 → 0.19.0
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 +103 -0
- package/dist/collections.cjs +256 -23
- package/dist/collections.cjs.map +1 -1
- package/dist/collections.js +256 -23
- package/dist/collections.js.map +1 -1
- package/dist/components.cjs +166 -18
- package/dist/components.cjs.map +1 -1
- package/dist/components.js +166 -18
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +256 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +256 -23
- package/dist/index.js.map +1 -1
- package/dist/types.d.cts +18 -0
- package/dist/types.d.ts +18 -0
- package/dist/utils.cjs +166 -18
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +2 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +166 -18
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,106 @@
|
|
|
1
|
+
## [0.19.0] - 2025-07-30
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- **Responsive Email Design** - Complete overhaul of email template for mobile-first responsive design
|
|
5
|
+
- Mobile-optimized email template with responsive CSS media queries
|
|
6
|
+
- Responsive typography with proper mobile font sizes and line heights
|
|
7
|
+
- Mobile-friendly image scaling and spacing
|
|
8
|
+
- Dark mode support with `prefers-color-scheme` media queries
|
|
9
|
+
- Comprehensive email client compatibility (Outlook, Gmail, Apple Mail)
|
|
10
|
+
- Mobile-specific CSS classes for precise responsive control
|
|
11
|
+
|
|
12
|
+
### Enhanced
|
|
13
|
+
- **Email Template Architecture**
|
|
14
|
+
- Completely redesigned `wrapInEmailTemplate` function with responsive structure
|
|
15
|
+
- Added proper viewport meta tags and email client compatibility headers
|
|
16
|
+
- Enhanced preheader text formatting with proper hiding techniques
|
|
17
|
+
- Improved table-based layout structure for email client consistency
|
|
18
|
+
- Better font rendering with `-webkit-font-smoothing` and `-moz-osx-font-smoothing`
|
|
19
|
+
|
|
20
|
+
- **Typography System**
|
|
21
|
+
- Responsive heading sizes that scale appropriately on mobile devices
|
|
22
|
+
- H1: 32px desktop → 24px mobile with optimized line-height
|
|
23
|
+
- H2: 24px desktop → 20px mobile with optimized line-height
|
|
24
|
+
- H3: 20px desktop → 16px mobile with optimized line-height
|
|
25
|
+
- Enhanced paragraph styling with consistent font-size and line-height
|
|
26
|
+
- Improved list styling with proper spacing and typography
|
|
27
|
+
|
|
28
|
+
- **Image Handling**
|
|
29
|
+
- Responsive images with `mobile-width-100` class for full-width scaling
|
|
30
|
+
- Enhanced image captions with mobile-optimized typography
|
|
31
|
+
- Proper image border-radius for modern email design
|
|
32
|
+
- Better image centering and spacing on all screen sizes
|
|
33
|
+
|
|
34
|
+
### Technical Improvements
|
|
35
|
+
- **CSS Media Queries** - Comprehensive mobile-first responsive design
|
|
36
|
+
- `@media only screen and (max-width: 640px)` breakpoint
|
|
37
|
+
- Mobile utility classes: `.mobile-hide`, `.mobile-center`, `.mobile-width-100`
|
|
38
|
+
- Mobile padding classes: `.mobile-padding`, `.mobile-padding-sm`
|
|
39
|
+
- Mobile typography classes: `.mobile-font-size-14/16/20/24`
|
|
40
|
+
- Mobile spacing classes: `.mobile-margin-bottom-16/20`
|
|
41
|
+
|
|
42
|
+
- **Email Client Compatibility**
|
|
43
|
+
- Outlook-specific MSO conditional comments and fixes
|
|
44
|
+
- Apple Mail message reformatting prevention
|
|
45
|
+
- Gmail and other client table-based layout optimization
|
|
46
|
+
- Cross-client font fallback stack
|
|
47
|
+
|
|
48
|
+
- **Dark Mode Support**
|
|
49
|
+
- CSS custom properties for dark mode backgrounds and text
|
|
50
|
+
- Proper border color adjustments for dark themes
|
|
51
|
+
- Future-ready design system for theme customization
|
|
52
|
+
|
|
53
|
+
### Breaking Changes
|
|
54
|
+
- None - all changes maintain backward compatibility with existing email content
|
|
55
|
+
|
|
56
|
+
### Browser/Client Support
|
|
57
|
+
- ✅ Outlook 2016+ (Windows/Mac)
|
|
58
|
+
- ✅ Gmail (Web/Mobile/App)
|
|
59
|
+
- ✅ Apple Mail (macOS/iOS)
|
|
60
|
+
- ✅ Yahoo Mail
|
|
61
|
+
- ✅ Thunderbird
|
|
62
|
+
- ✅ Mobile email clients (iOS/Android)
|
|
63
|
+
|
|
64
|
+
## [0.18.0] - 2025-07-30
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
- **Media Field Population in Custom Blocks** - Fixed critical issue where media fields in custom blocks weren't populated during email conversion
|
|
68
|
+
- Added automatic media field population in preview endpoint before email conversion
|
|
69
|
+
- Media fields now receive full media objects with URLs instead of just ID strings
|
|
70
|
+
- Added `populateFields` option to `BroadcastCustomizations` interface for configurable field population
|
|
71
|
+
- Added recursive population support for array fields containing upload fields
|
|
72
|
+
- Comprehensive logging for media population success and failures
|
|
73
|
+
- Both email previews and sent emails now properly populate media relationships
|
|
74
|
+
|
|
75
|
+
### Enhanced
|
|
76
|
+
- **Preview Endpoint** - Significantly improved custom block support
|
|
77
|
+
- Preview endpoint now populates media fields before calling custom block converters
|
|
78
|
+
- Custom blocks with images now display correctly in email previews
|
|
79
|
+
- Added detailed logging for debugging media population issues
|
|
80
|
+
|
|
81
|
+
- **Broadcast Sync Logic** - Applied media population to all broadcast operations
|
|
82
|
+
- Create operation now populates media fields before provider sync
|
|
83
|
+
- Update operation populates media fields when content changes
|
|
84
|
+
- Deferred create operation (empty → content) now handles media population
|
|
85
|
+
- Ensures consistency between previews and actual sent emails
|
|
86
|
+
|
|
87
|
+
### Technical
|
|
88
|
+
- **New Helper Functions**
|
|
89
|
+
- `populateMediaFields()` - Recursively finds and populates upload fields in Lexical content
|
|
90
|
+
- `populateBlockMediaFields()` - Handles individual block media field population
|
|
91
|
+
- Support for both direct upload fields and upload fields within arrays
|
|
92
|
+
- Automatic detection of upload fields based on custom block configuration
|
|
93
|
+
- MongoDB ObjectId pattern matching for field population decisions
|
|
94
|
+
|
|
95
|
+
### Types
|
|
96
|
+
- **Enhanced BroadcastCustomizations Interface**
|
|
97
|
+
- Added `populateFields` option with string array or function signature
|
|
98
|
+
- Comprehensive documentation with usage examples
|
|
99
|
+
- Support for block-type-specific field population logic
|
|
100
|
+
|
|
101
|
+
### Breaking Changes
|
|
102
|
+
- None - all changes are backward compatible and additive
|
|
103
|
+
|
|
1
104
|
## [0.17.4] - 2025-07-30
|
|
2
105
|
|
|
3
106
|
### Fixed
|
package/dist/collections.cjs
CHANGED
|
@@ -1029,9 +1029,9 @@ async function convertParagraph(node, mediaUrl, customBlockConverter) {
|
|
|
1029
1029
|
);
|
|
1030
1030
|
const children = childParts.join("");
|
|
1031
1031
|
if (!children.trim()) {
|
|
1032
|
-
return '<p style="margin: 0 0 16px 0; min-height: 1em;"> </p>';
|
|
1032
|
+
return '<p class="mobile-margin-bottom-16" style="margin: 0 0 16px 0; min-height: 1em;"> </p>';
|
|
1033
1033
|
}
|
|
1034
|
-
return `<p style="margin: 0 0 16px 0; text-align: ${align};">${children}</p>`;
|
|
1034
|
+
return `<p class="mobile-margin-bottom-16" style="margin: 0 0 16px 0; text-align: ${align}; font-size: 16px; line-height: 1.5;">${children}</p>`;
|
|
1035
1035
|
}
|
|
1036
1036
|
async function convertHeading(node, mediaUrl, customBlockConverter) {
|
|
1037
1037
|
const tag = node.tag || "h1";
|
|
@@ -1045,8 +1045,14 @@ async function convertHeading(node, mediaUrl, customBlockConverter) {
|
|
|
1045
1045
|
h2: "font-size: 24px; font-weight: 600; margin: 0 0 16px 0; line-height: 1.3;",
|
|
1046
1046
|
h3: "font-size: 20px; font-weight: 600; margin: 0 0 12px 0; line-height: 1.4;"
|
|
1047
1047
|
};
|
|
1048
|
+
const mobileClasses = {
|
|
1049
|
+
h1: "mobile-font-size-24",
|
|
1050
|
+
h2: "mobile-font-size-20",
|
|
1051
|
+
h3: "mobile-font-size-16"
|
|
1052
|
+
};
|
|
1048
1053
|
const style = `${styles2[tag] || styles2.h3} text-align: ${align};`;
|
|
1049
|
-
|
|
1054
|
+
const mobileClass = mobileClasses[tag] || mobileClasses.h3;
|
|
1055
|
+
return `<${tag} class="${mobileClass}" style="${style}">${children}</${tag}>`;
|
|
1050
1056
|
}
|
|
1051
1057
|
async function convertList(node, mediaUrl, customBlockConverter) {
|
|
1052
1058
|
const tag = node.listType === "number" ? "ol" : "ul";
|
|
@@ -1054,8 +1060,8 @@ async function convertList(node, mediaUrl, customBlockConverter) {
|
|
|
1054
1060
|
(node.children || []).map((child) => convertNode(child, mediaUrl, customBlockConverter))
|
|
1055
1061
|
);
|
|
1056
1062
|
const children = childParts.join("");
|
|
1057
|
-
const style = tag === "ul" ? "margin: 0 0 16px 0; padding-left: 24px; list-style-type: disc;" : "margin: 0 0 16px 0; padding-left: 24px; list-style-type: decimal;";
|
|
1058
|
-
return `<${tag} style="${style}">${children}</${tag}>`;
|
|
1063
|
+
const style = tag === "ul" ? "margin: 0 0 16px 0; padding-left: 24px; list-style-type: disc; font-size: 16px; line-height: 1.5;" : "margin: 0 0 16px 0; padding-left: 24px; list-style-type: decimal; font-size: 16px; line-height: 1.5;";
|
|
1064
|
+
return `<${tag} class="mobile-margin-bottom-16" style="${style}">${children}</${tag}>`;
|
|
1059
1065
|
}
|
|
1060
1066
|
async function convertListItem(node, mediaUrl, customBlockConverter) {
|
|
1061
1067
|
const childParts = await Promise.all(
|
|
@@ -1112,16 +1118,16 @@ function convertUpload(node, mediaUrl) {
|
|
|
1112
1118
|
}
|
|
1113
1119
|
const alt = node.fields?.altText || upload.alt || "";
|
|
1114
1120
|
const caption = node.fields?.caption || "";
|
|
1115
|
-
const imgHtml = `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" style="max-width: 100%; height: auto; display: block; margin: 0 auto;" />`;
|
|
1121
|
+
const imgHtml = `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" class="mobile-width-100" style="max-width: 100%; height: auto; display: block; margin: 0 auto; border-radius: 6px;" />`;
|
|
1116
1122
|
if (caption) {
|
|
1117
1123
|
return `
|
|
1118
|
-
<div style="margin: 0 0 16px 0; text-align: center;">
|
|
1124
|
+
<div style="margin: 0 0 16px 0; text-align: center;" class="mobile-margin-bottom-16">
|
|
1119
1125
|
${imgHtml}
|
|
1120
|
-
<p style="margin: 8px 0 0 0; font-size: 14px; color: #6b7280; font-style: italic;">${escapeHtml(caption)}</p>
|
|
1126
|
+
<p style="margin: 8px 0 0 0; font-size: 14px; color: #6b7280; font-style: italic; text-align: center;" class="mobile-font-size-14">${escapeHtml(caption)}</p>
|
|
1121
1127
|
</div>
|
|
1122
1128
|
`;
|
|
1123
1129
|
}
|
|
1124
|
-
return `<div style="margin: 0 0 16px 0; text-align: center;">${imgHtml}</div>`;
|
|
1130
|
+
return `<div style="margin: 0 0 16px 0; text-align: center;" class="mobile-margin-bottom-16">${imgHtml}</div>`;
|
|
1125
1131
|
}
|
|
1126
1132
|
async function convertBlock(node, mediaUrl, customBlockConverter) {
|
|
1127
1133
|
const blockType = node.fields?.blockName || node.blockName;
|
|
@@ -1194,11 +1200,14 @@ function escapeHtml(text) {
|
|
|
1194
1200
|
}
|
|
1195
1201
|
function wrapInEmailTemplate(content, preheader) {
|
|
1196
1202
|
return `<!DOCTYPE html>
|
|
1197
|
-
<html lang="en">
|
|
1203
|
+
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
1198
1204
|
<head>
|
|
1199
1205
|
<meta charset="UTF-8">
|
|
1200
1206
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1201
|
-
<
|
|
1207
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
1208
|
+
<meta name="x-apple-disable-message-reformatting">
|
|
1209
|
+
<title>Newsletter</title>
|
|
1210
|
+
|
|
1202
1211
|
<!--[if mso]>
|
|
1203
1212
|
<noscript>
|
|
1204
1213
|
<xml>
|
|
@@ -1208,16 +1217,155 @@ function wrapInEmailTemplate(content, preheader) {
|
|
|
1208
1217
|
</xml>
|
|
1209
1218
|
</noscript>
|
|
1210
1219
|
<![endif]-->
|
|
1220
|
+
|
|
1221
|
+
<style>
|
|
1222
|
+
/* Reset and base styles */
|
|
1223
|
+
* {
|
|
1224
|
+
-webkit-text-size-adjust: 100%;
|
|
1225
|
+
-ms-text-size-adjust: 100%;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
body {
|
|
1229
|
+
margin: 0 !important;
|
|
1230
|
+
padding: 0 !important;
|
|
1231
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
|
|
1232
|
+
font-size: 16px;
|
|
1233
|
+
line-height: 1.5;
|
|
1234
|
+
color: #1A1A1A;
|
|
1235
|
+
background-color: #f8f9fa;
|
|
1236
|
+
-webkit-font-smoothing: antialiased;
|
|
1237
|
+
-moz-osx-font-smoothing: grayscale;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
table {
|
|
1241
|
+
border-spacing: 0 !important;
|
|
1242
|
+
border-collapse: collapse !important;
|
|
1243
|
+
table-layout: fixed !important;
|
|
1244
|
+
margin: 0 auto !important;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
table table table {
|
|
1248
|
+
table-layout: auto;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
img {
|
|
1252
|
+
-ms-interpolation-mode: bicubic;
|
|
1253
|
+
max-width: 100%;
|
|
1254
|
+
height: auto;
|
|
1255
|
+
border: 0;
|
|
1256
|
+
outline: none;
|
|
1257
|
+
text-decoration: none;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/* Responsive styles */
|
|
1261
|
+
@media only screen and (max-width: 640px) {
|
|
1262
|
+
.mobile-hide {
|
|
1263
|
+
display: none !important;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
.mobile-center {
|
|
1267
|
+
text-align: center !important;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
.mobile-width-100 {
|
|
1271
|
+
width: 100% !important;
|
|
1272
|
+
max-width: 100% !important;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
.mobile-padding {
|
|
1276
|
+
padding: 20px !important;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
.mobile-padding-sm {
|
|
1280
|
+
padding: 16px !important;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
.mobile-font-size-14 {
|
|
1284
|
+
font-size: 14px !important;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
.mobile-font-size-16 {
|
|
1288
|
+
font-size: 16px !important;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
.mobile-font-size-20 {
|
|
1292
|
+
font-size: 20px !important;
|
|
1293
|
+
line-height: 1.3 !important;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
.mobile-font-size-24 {
|
|
1297
|
+
font-size: 24px !important;
|
|
1298
|
+
line-height: 1.2 !important;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
/* Stack sections on mobile */
|
|
1302
|
+
.mobile-stack {
|
|
1303
|
+
display: block !important;
|
|
1304
|
+
width: 100% !important;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
/* Mobile-specific spacing */
|
|
1308
|
+
.mobile-margin-bottom-16 {
|
|
1309
|
+
margin-bottom: 16px !important;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
.mobile-margin-bottom-20 {
|
|
1313
|
+
margin-bottom: 20px !important;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
/* Dark mode support */
|
|
1318
|
+
@media (prefers-color-scheme: dark) {
|
|
1319
|
+
.dark-mode-bg {
|
|
1320
|
+
background-color: #1a1a1a !important;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
.dark-mode-text {
|
|
1324
|
+
color: #ffffff !important;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
.dark-mode-border {
|
|
1328
|
+
border-color: #333333 !important;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
/* Outlook-specific fixes */
|
|
1333
|
+
<!--[if mso]>
|
|
1334
|
+
<style>
|
|
1335
|
+
table {
|
|
1336
|
+
border-collapse: collapse;
|
|
1337
|
+
border-spacing: 0;
|
|
1338
|
+
border: none;
|
|
1339
|
+
margin: 0;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
div, p {
|
|
1343
|
+
margin: 0;
|
|
1344
|
+
}
|
|
1345
|
+
</style>
|
|
1346
|
+
<![endif]-->
|
|
1347
|
+
</style>
|
|
1211
1348
|
</head>
|
|
1212
|
-
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 16px; line-height: 1.5; color: #
|
|
1213
|
-
${preheader ?
|
|
1214
|
-
|
|
1349
|
+
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; font-size: 16px; line-height: 1.5; color: #1A1A1A; background-color: #f8f9fa;">
|
|
1350
|
+
${preheader ? `
|
|
1351
|
+
<!-- Preheader text -->
|
|
1352
|
+
<div style="display: none; max-height: 0; overflow: hidden; font-size: 1px; line-height: 1px; color: transparent;">
|
|
1353
|
+
${escapeHtml(preheader)}
|
|
1354
|
+
</div>
|
|
1355
|
+
` : ""}
|
|
1356
|
+
|
|
1357
|
+
<!-- Main container -->
|
|
1358
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="margin: 0; padding: 0; background-color: #f8f9fa;">
|
|
1215
1359
|
<tr>
|
|
1216
|
-
<td align="center" style="padding: 20px
|
|
1217
|
-
|
|
1360
|
+
<td align="center" style="padding: 20px 10px;">
|
|
1361
|
+
<!-- Email wrapper -->
|
|
1362
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="600" class="mobile-width-100" style="margin: 0 auto; max-width: 600px;">
|
|
1218
1363
|
<tr>
|
|
1219
|
-
<td style="padding:
|
|
1220
|
-
|
|
1364
|
+
<td class="mobile-padding" style="padding: 0;">
|
|
1365
|
+
<!-- Content area with light background -->
|
|
1366
|
+
<div style="background-color: #ffffff; padding: 40px 30px; border-radius: 8px;" class="mobile-padding">
|
|
1367
|
+
${content}
|
|
1368
|
+
</div>
|
|
1221
1369
|
</td>
|
|
1222
1370
|
</tr>
|
|
1223
1371
|
</table>
|
|
@@ -1625,6 +1773,86 @@ var createTestBroadcastEndpoint = (config, collectionSlug) => {
|
|
|
1625
1773
|
};
|
|
1626
1774
|
|
|
1627
1775
|
// src/endpoints/broadcasts/preview.ts
|
|
1776
|
+
async function populateMediaFields(content, payload, config) {
|
|
1777
|
+
if (!content || typeof content !== "object") return content;
|
|
1778
|
+
if (content.root?.children) {
|
|
1779
|
+
for (const child of content.root.children) {
|
|
1780
|
+
await populateBlockMediaFields(child, payload, config);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
return content;
|
|
1784
|
+
}
|
|
1785
|
+
async function populateBlockMediaFields(node, payload, config) {
|
|
1786
|
+
if (node.type === "block" && node.fields) {
|
|
1787
|
+
const blockType = node.fields.blockType || node.fields.blockName;
|
|
1788
|
+
const customBlocks = config.customizations?.broadcasts?.customBlocks || [];
|
|
1789
|
+
const blockConfig = customBlocks.find((b) => b.slug === blockType);
|
|
1790
|
+
if (blockConfig && blockConfig.fields) {
|
|
1791
|
+
for (const field of blockConfig.fields) {
|
|
1792
|
+
if (field.type === "upload" && field.relationTo && node.fields[field.name]) {
|
|
1793
|
+
const fieldValue = node.fields[field.name];
|
|
1794
|
+
if (typeof fieldValue === "string" && fieldValue.match(/^[a-f0-9]{24}$/i)) {
|
|
1795
|
+
try {
|
|
1796
|
+
const media = await payload.findByID({
|
|
1797
|
+
collection: field.relationTo,
|
|
1798
|
+
id: fieldValue,
|
|
1799
|
+
depth: 0
|
|
1800
|
+
});
|
|
1801
|
+
if (media) {
|
|
1802
|
+
node.fields[field.name] = media;
|
|
1803
|
+
payload.logger?.info(`Populated ${field.name} for block ${blockType}:`, {
|
|
1804
|
+
mediaId: fieldValue,
|
|
1805
|
+
mediaUrl: media.url,
|
|
1806
|
+
filename: media.filename
|
|
1807
|
+
});
|
|
1808
|
+
}
|
|
1809
|
+
} catch (error) {
|
|
1810
|
+
payload.logger?.error(`Failed to populate ${field.name} for block ${blockType}:`, error);
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
if (field.type === "array" && field.fields) {
|
|
1815
|
+
const arrayValue = node.fields[field.name];
|
|
1816
|
+
if (Array.isArray(arrayValue)) {
|
|
1817
|
+
for (const arrayItem of arrayValue) {
|
|
1818
|
+
if (arrayItem && typeof arrayItem === "object") {
|
|
1819
|
+
for (const arrayField of field.fields) {
|
|
1820
|
+
if (arrayField.type === "upload" && arrayField.relationTo && arrayItem[arrayField.name]) {
|
|
1821
|
+
const arrayFieldValue = arrayItem[arrayField.name];
|
|
1822
|
+
if (typeof arrayFieldValue === "string" && arrayFieldValue.match(/^[a-f0-9]{24}$/i)) {
|
|
1823
|
+
try {
|
|
1824
|
+
const media = await payload.findByID({
|
|
1825
|
+
collection: arrayField.relationTo,
|
|
1826
|
+
id: arrayFieldValue,
|
|
1827
|
+
depth: 0
|
|
1828
|
+
});
|
|
1829
|
+
if (media) {
|
|
1830
|
+
arrayItem[arrayField.name] = media;
|
|
1831
|
+
payload.logger?.info(`Populated array ${arrayField.name} for block ${blockType}:`, {
|
|
1832
|
+
mediaId: arrayFieldValue,
|
|
1833
|
+
mediaUrl: media.url,
|
|
1834
|
+
filename: media.filename
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
} catch (error) {
|
|
1838
|
+
payload.logger?.error(`Failed to populate array ${arrayField.name} for block ${blockType}:`, error);
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
if (node.children) {
|
|
1851
|
+
for (const child of node.children) {
|
|
1852
|
+
await populateBlockMediaFields(child, payload, config);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1628
1856
|
var createBroadcastPreviewEndpoint = (config, _collectionSlug) => {
|
|
1629
1857
|
return {
|
|
1630
1858
|
path: "/preview",
|
|
@@ -1640,7 +1868,9 @@ var createBroadcastPreviewEndpoint = (config, _collectionSlug) => {
|
|
|
1640
1868
|
}, { status: 400 });
|
|
1641
1869
|
}
|
|
1642
1870
|
const mediaUrl = req.payload.config.serverURL ? `${req.payload.config.serverURL}/api/media` : "/api/media";
|
|
1643
|
-
|
|
1871
|
+
req.payload.logger?.info("Populating media fields for email preview...");
|
|
1872
|
+
const populatedContent = await populateMediaFields(content, req.payload, config);
|
|
1873
|
+
const htmlContent = await convertToEmailSafeHtml(populatedContent, {
|
|
1644
1874
|
wrapInTemplate: true,
|
|
1645
1875
|
preheader,
|
|
1646
1876
|
mediaUrl,
|
|
@@ -1939,8 +2169,9 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
1939
2169
|
}
|
|
1940
2170
|
const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
|
|
1941
2171
|
const provider = new BroadcastApiProvider2(providerConfig);
|
|
1942
|
-
req.payload.logger.info("
|
|
1943
|
-
const
|
|
2172
|
+
req.payload.logger.info("Populating media fields and converting content to HTML...");
|
|
2173
|
+
const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
|
|
2174
|
+
const htmlContent = await convertToEmailSafeHtml(populatedContent, {
|
|
1944
2175
|
customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
|
|
1945
2176
|
});
|
|
1946
2177
|
if (!htmlContent || htmlContent.trim() === "") {
|
|
@@ -2039,7 +2270,8 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
2039
2270
|
return doc;
|
|
2040
2271
|
}
|
|
2041
2272
|
req.payload.logger.info("Creating broadcast in provider (deferred from initial create)...");
|
|
2042
|
-
const
|
|
2273
|
+
const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
|
|
2274
|
+
const htmlContent = await convertToEmailSafeHtml(populatedContent, {
|
|
2043
2275
|
customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
|
|
2044
2276
|
});
|
|
2045
2277
|
if (!htmlContent || htmlContent.trim() === "") {
|
|
@@ -2100,7 +2332,8 @@ var createBroadcastsCollection = (pluginConfig) => {
|
|
|
2100
2332
|
updates.preheader = doc.contentSection?.preheader;
|
|
2101
2333
|
}
|
|
2102
2334
|
if (JSON.stringify(doc.contentSection?.content) !== JSON.stringify(previousDoc?.contentSection?.content)) {
|
|
2103
|
-
|
|
2335
|
+
const populatedContent = await populateMediaFields(doc.contentSection?.content, req.payload, pluginConfig);
|
|
2336
|
+
updates.content = await convertToEmailSafeHtml(populatedContent, {
|
|
2104
2337
|
customBlockConverter: pluginConfig.customizations?.broadcasts?.customBlockConverter
|
|
2105
2338
|
});
|
|
2106
2339
|
}
|