payload-plugin-newsletter 0.20.0 → 0.20.2
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 +43 -0
- package/dist/admin.d.ts +706 -0
- package/dist/{components.js → admin.js} +832 -1458
- package/dist/broadcast-VMCYSZRY.js +6 -0
- package/dist/chunk-XVMYJQRQ.js +490 -0
- package/dist/client.d.ts +131 -15
- package/dist/client.js +1 -1
- package/dist/server.d.ts +735 -0
- package/dist/{index.js → server.js} +30 -654
- package/package.json +17 -27
- package/ESM_FIX_SUMMARY.md +0 -74
- package/PREVIEW_CUSTOMIZATION_TASK.md +0 -201
- package/dist/client.cjs +0 -891
- package/dist/client.cjs.map +0 -1
- package/dist/client.d.cts +0 -53
- package/dist/client.js.map +0 -1
- package/dist/components.cjs +0 -2460
- package/dist/components.cjs.map +0 -1
- package/dist/components.d.cts +0 -66
- package/dist/components.d.ts +0 -66
- package/dist/components.js.map +0 -1
- package/dist/index.cjs +0 -5545
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -90
- package/dist/index.d.ts +0 -90
- package/dist/index.js.map +0 -1
|
@@ -1,855 +1,338 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
// src/components/Broadcasts/BroadcastInlinePreview.tsx
|
|
5
|
+
import { useState, useCallback } from "react";
|
|
6
|
+
import { useFormFields } from "@payloadcms/ui";
|
|
2
7
|
|
|
3
|
-
// src/components/
|
|
4
|
-
import { useState } from "react";
|
|
8
|
+
// src/components/Broadcasts/PreviewControls.tsx
|
|
5
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
var
|
|
7
|
-
|
|
10
|
+
var PreviewControls = ({
|
|
11
|
+
onUpdate,
|
|
12
|
+
device,
|
|
13
|
+
onDeviceChange,
|
|
14
|
+
isLoading = false
|
|
15
|
+
}) => {
|
|
16
|
+
const controlsStyle = {
|
|
8
17
|
display: "flex",
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
alignItems: "center",
|
|
19
|
+
justifyContent: "space-between",
|
|
20
|
+
padding: "1rem",
|
|
21
|
+
background: "white",
|
|
22
|
+
borderBottom: "1px solid #e5e7eb"
|
|
23
|
+
};
|
|
24
|
+
const updateButtonStyle = {
|
|
25
|
+
padding: "0.5rem 1rem",
|
|
26
|
+
background: "#10b981",
|
|
27
|
+
color: "white",
|
|
28
|
+
border: "none",
|
|
29
|
+
borderRadius: "4px",
|
|
30
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
31
|
+
fontSize: "14px",
|
|
32
|
+
fontWeight: 500,
|
|
33
|
+
opacity: isLoading ? 0.6 : 1
|
|
34
|
+
};
|
|
35
|
+
const deviceSelectorStyle = {
|
|
15
36
|
display: "flex",
|
|
16
|
-
flexDirection: "column",
|
|
17
37
|
gap: "0.5rem"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
fontSize: "0.875rem",
|
|
21
|
-
fontWeight: "500",
|
|
22
|
-
color: "#374151"
|
|
23
|
-
},
|
|
24
|
-
input: {
|
|
25
|
-
padding: "0.5rem 0.75rem",
|
|
26
|
-
fontSize: "1rem",
|
|
27
|
-
border: "1px solid #e5e7eb",
|
|
28
|
-
borderRadius: "0.375rem",
|
|
29
|
-
outline: "none",
|
|
30
|
-
transition: "border-color 0.2s"
|
|
31
|
-
},
|
|
32
|
-
button: {
|
|
33
|
-
padding: "0.75rem 1.5rem",
|
|
34
|
-
fontSize: "1rem",
|
|
35
|
-
fontWeight: "500",
|
|
36
|
-
color: "#ffffff",
|
|
37
|
-
backgroundColor: "#3b82f6",
|
|
38
|
-
border: "none",
|
|
39
|
-
borderRadius: "0.375rem",
|
|
40
|
-
cursor: "pointer",
|
|
41
|
-
transition: "background-color 0.2s"
|
|
42
|
-
},
|
|
43
|
-
buttonDisabled: {
|
|
44
|
-
opacity: 0.5,
|
|
45
|
-
cursor: "not-allowed"
|
|
46
|
-
},
|
|
47
|
-
error: {
|
|
48
|
-
fontSize: "0.875rem",
|
|
49
|
-
color: "#ef4444",
|
|
50
|
-
marginTop: "0.25rem"
|
|
51
|
-
},
|
|
52
|
-
success: {
|
|
53
|
-
fontSize: "0.875rem",
|
|
54
|
-
color: "#10b981",
|
|
55
|
-
marginTop: "0.25rem"
|
|
56
|
-
},
|
|
57
|
-
checkbox: {
|
|
38
|
+
};
|
|
39
|
+
const deviceButtonStyle = (isActive) => ({
|
|
58
40
|
display: "flex",
|
|
59
41
|
alignItems: "center",
|
|
60
|
-
gap: "0.5rem"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
fontSize: "
|
|
68
|
-
color: "#374151"
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
var NewsletterForm = ({
|
|
72
|
-
onSuccess,
|
|
73
|
-
onError,
|
|
74
|
-
showName = false,
|
|
75
|
-
showPreferences = false,
|
|
76
|
-
leadMagnet,
|
|
77
|
-
className,
|
|
78
|
-
styles: customStyles = {},
|
|
79
|
-
apiEndpoint = "/api/newsletter/subscribe",
|
|
80
|
-
buttonText = "Subscribe",
|
|
81
|
-
loadingText = "Subscribing...",
|
|
82
|
-
successMessage = "Successfully subscribed!",
|
|
83
|
-
placeholders = {
|
|
84
|
-
email: "Enter your email",
|
|
85
|
-
name: "Enter your name"
|
|
86
|
-
},
|
|
87
|
-
labels = {
|
|
88
|
-
email: "Email",
|
|
89
|
-
name: "Name",
|
|
90
|
-
newsletter: "Newsletter updates",
|
|
91
|
-
announcements: "Product announcements"
|
|
92
|
-
}
|
|
93
|
-
}) => {
|
|
94
|
-
const [email, setEmail] = useState("");
|
|
95
|
-
const [name, setName] = useState("");
|
|
96
|
-
const [preferences, setPreferences] = useState({
|
|
97
|
-
newsletter: true,
|
|
98
|
-
announcements: true
|
|
42
|
+
gap: "0.5rem",
|
|
43
|
+
padding: "0.5rem 0.75rem",
|
|
44
|
+
background: isActive ? "#1f2937" : "white",
|
|
45
|
+
color: isActive ? "white" : "#374151",
|
|
46
|
+
border: `1px solid ${isActive ? "#1f2937" : "#e5e7eb"}`,
|
|
47
|
+
borderRadius: "4px",
|
|
48
|
+
cursor: "pointer",
|
|
49
|
+
fontSize: "14px"
|
|
99
50
|
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
button: { ...defaultStyles.button, ...customStyles.button },
|
|
109
|
-
buttonDisabled: { ...defaultStyles.buttonDisabled, ...customStyles.buttonDisabled },
|
|
110
|
-
error: { ...defaultStyles.error, ...customStyles.error },
|
|
111
|
-
success: { ...defaultStyles.success, ...customStyles.success },
|
|
112
|
-
checkbox: { ...defaultStyles.checkbox, ...customStyles.checkbox },
|
|
113
|
-
checkboxInput: { ...defaultStyles.checkboxInput, ...customStyles.checkboxInput },
|
|
114
|
-
checkboxLabel: { ...defaultStyles.checkboxLabel, ...customStyles.checkboxLabel }
|
|
115
|
-
};
|
|
116
|
-
const handleSubmit = async (e) => {
|
|
117
|
-
e.preventDefault();
|
|
118
|
-
setError(null);
|
|
119
|
-
setLoading(true);
|
|
120
|
-
try {
|
|
121
|
-
const payload = {
|
|
122
|
-
email,
|
|
123
|
-
...showName && name && { name },
|
|
124
|
-
...showPreferences && { preferences },
|
|
125
|
-
...leadMagnet && { leadMagnet: leadMagnet.id },
|
|
126
|
-
metadata: {
|
|
127
|
-
signupPage: window.location.href,
|
|
128
|
-
...typeof window !== "undefined" && window.location.search && {
|
|
129
|
-
utmParams: Object.fromEntries(new URLSearchParams(window.location.search))
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
const response = await fetch(apiEndpoint, {
|
|
134
|
-
method: "POST",
|
|
135
|
-
headers: {
|
|
136
|
-
"Content-Type": "application/json"
|
|
137
|
-
},
|
|
138
|
-
body: JSON.stringify(payload)
|
|
139
|
-
});
|
|
140
|
-
const data = await response.json();
|
|
141
|
-
if (!response.ok) {
|
|
142
|
-
throw new Error(data.error || data.errors?.join(", ") || "Subscription failed");
|
|
143
|
-
}
|
|
144
|
-
setSuccess(true);
|
|
145
|
-
setEmail("");
|
|
146
|
-
setName("");
|
|
147
|
-
if (onSuccess) {
|
|
148
|
-
onSuccess(data.subscriber);
|
|
149
|
-
}
|
|
150
|
-
} catch (err) {
|
|
151
|
-
const errorMessage = err instanceof Error ? err.message : "An error occurred";
|
|
152
|
-
setError(errorMessage);
|
|
153
|
-
if (onError) {
|
|
154
|
-
onError(new Error(errorMessage));
|
|
51
|
+
return /* @__PURE__ */ jsxs("div", { style: controlsStyle, children: [
|
|
52
|
+
/* @__PURE__ */ jsx(
|
|
53
|
+
"button",
|
|
54
|
+
{
|
|
55
|
+
style: updateButtonStyle,
|
|
56
|
+
onClick: onUpdate,
|
|
57
|
+
disabled: isLoading,
|
|
58
|
+
children: isLoading ? "Updating..." : "Update Preview"
|
|
155
59
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (success && !showPreferences) {
|
|
161
|
-
return /* @__PURE__ */ jsx("div", { className, style: styles.form, children: /* @__PURE__ */ jsx("p", { style: styles.success, children: successMessage }) });
|
|
162
|
-
}
|
|
163
|
-
return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, style: styles.form, children: [
|
|
164
|
-
/* @__PURE__ */ jsxs("div", { style: styles.inputGroup, children: [
|
|
165
|
-
/* @__PURE__ */ jsx("label", { htmlFor: "email", style: styles.label, children: labels.email }),
|
|
166
|
-
/* @__PURE__ */ jsx(
|
|
167
|
-
"input",
|
|
60
|
+
),
|
|
61
|
+
/* @__PURE__ */ jsxs("div", { style: deviceSelectorStyle, children: [
|
|
62
|
+
/* @__PURE__ */ jsxs(
|
|
63
|
+
"button",
|
|
168
64
|
{
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
65
|
+
style: deviceButtonStyle(device === "desktop"),
|
|
66
|
+
onClick: () => onDeviceChange("desktop"),
|
|
67
|
+
"aria-label": "Desktop view",
|
|
68
|
+
children: [
|
|
69
|
+
/* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
70
|
+
/* @__PURE__ */ jsx("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }),
|
|
71
|
+
/* @__PURE__ */ jsx("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
|
|
72
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
|
|
73
|
+
] }),
|
|
74
|
+
"Desktop"
|
|
75
|
+
]
|
|
180
76
|
}
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
/* @__PURE__ */ jsx("label", { htmlFor: "name", style: styles.label, children: labels.name }),
|
|
185
|
-
/* @__PURE__ */ jsx(
|
|
186
|
-
"input",
|
|
77
|
+
),
|
|
78
|
+
/* @__PURE__ */ jsxs(
|
|
79
|
+
"button",
|
|
187
80
|
{
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
81
|
+
style: deviceButtonStyle(device === "mobile"),
|
|
82
|
+
onClick: () => onDeviceChange("mobile"),
|
|
83
|
+
"aria-label": "Mobile view",
|
|
84
|
+
children: [
|
|
85
|
+
/* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
86
|
+
/* @__PURE__ */ jsx("rect", { x: "5", y: "2", width: "14", height: "20", rx: "2", ry: "2" }),
|
|
87
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "18", x2: "12", y2: "18" })
|
|
88
|
+
] }),
|
|
89
|
+
"Mobile"
|
|
90
|
+
]
|
|
198
91
|
}
|
|
199
92
|
)
|
|
200
|
-
] })
|
|
201
|
-
showPreferences && /* @__PURE__ */ jsxs("div", { style: styles.inputGroup, children: [
|
|
202
|
-
/* @__PURE__ */ jsx("label", { style: styles.label, children: "Email Preferences" }),
|
|
203
|
-
/* @__PURE__ */ jsxs("div", { style: styles.checkbox, children: [
|
|
204
|
-
/* @__PURE__ */ jsx(
|
|
205
|
-
"input",
|
|
206
|
-
{
|
|
207
|
-
id: "newsletter",
|
|
208
|
-
type: "checkbox",
|
|
209
|
-
checked: preferences.newsletter,
|
|
210
|
-
onChange: (e) => setPreferences({ ...preferences, newsletter: e.target.checked }),
|
|
211
|
-
disabled: loading,
|
|
212
|
-
style: styles.checkboxInput
|
|
213
|
-
}
|
|
214
|
-
),
|
|
215
|
-
/* @__PURE__ */ jsx("label", { htmlFor: "newsletter", style: styles.checkboxLabel, children: labels.newsletter })
|
|
216
|
-
] }),
|
|
217
|
-
/* @__PURE__ */ jsxs("div", { style: styles.checkbox, children: [
|
|
218
|
-
/* @__PURE__ */ jsx(
|
|
219
|
-
"input",
|
|
220
|
-
{
|
|
221
|
-
id: "announcements",
|
|
222
|
-
type: "checkbox",
|
|
223
|
-
checked: preferences.announcements,
|
|
224
|
-
onChange: (e) => setPreferences({ ...preferences, announcements: e.target.checked }),
|
|
225
|
-
disabled: loading,
|
|
226
|
-
style: styles.checkboxInput
|
|
227
|
-
}
|
|
228
|
-
),
|
|
229
|
-
/* @__PURE__ */ jsx("label", { htmlFor: "announcements", style: styles.checkboxLabel, children: labels.announcements })
|
|
230
|
-
] })
|
|
231
|
-
] }),
|
|
232
|
-
/* @__PURE__ */ jsx(
|
|
233
|
-
"button",
|
|
234
|
-
{
|
|
235
|
-
type: "submit",
|
|
236
|
-
disabled: loading,
|
|
237
|
-
style: {
|
|
238
|
-
...styles.button,
|
|
239
|
-
...loading && styles.buttonDisabled
|
|
240
|
-
},
|
|
241
|
-
children: loading ? loadingText : buttonText
|
|
242
|
-
}
|
|
243
|
-
),
|
|
244
|
-
error && /* @__PURE__ */ jsx("p", { style: styles.error, children: error }),
|
|
245
|
-
success && /* @__PURE__ */ jsx("p", { style: styles.success, children: successMessage })
|
|
93
|
+
] })
|
|
246
94
|
] });
|
|
247
95
|
};
|
|
248
|
-
function createNewsletterForm(defaultProps) {
|
|
249
|
-
return (props) => /* @__PURE__ */ jsx(NewsletterForm, { ...defaultProps, ...props });
|
|
250
|
-
}
|
|
251
96
|
|
|
252
|
-
// src/components/
|
|
253
|
-
import {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
flexDirection: "column",
|
|
270
|
-
gap: "1.5rem"
|
|
271
|
-
},
|
|
272
|
-
section: {
|
|
273
|
-
padding: "1.5rem",
|
|
274
|
-
backgroundColor: "#f9fafb",
|
|
275
|
-
borderRadius: "0.5rem",
|
|
276
|
-
border: "1px solid #e5e7eb"
|
|
277
|
-
},
|
|
278
|
-
sectionTitle: {
|
|
279
|
-
fontSize: "1.125rem",
|
|
280
|
-
fontWeight: "500",
|
|
281
|
-
marginBottom: "1rem",
|
|
282
|
-
color: "#111827"
|
|
283
|
-
},
|
|
284
|
-
inputGroup: {
|
|
285
|
-
display: "flex",
|
|
286
|
-
flexDirection: "column",
|
|
287
|
-
gap: "0.5rem"
|
|
288
|
-
},
|
|
289
|
-
label: {
|
|
290
|
-
fontSize: "0.875rem",
|
|
291
|
-
fontWeight: "500",
|
|
292
|
-
color: "#374151"
|
|
293
|
-
},
|
|
294
|
-
input: {
|
|
295
|
-
padding: "0.5rem 0.75rem",
|
|
296
|
-
fontSize: "1rem",
|
|
297
|
-
border: "1px solid #e5e7eb",
|
|
298
|
-
borderRadius: "0.375rem",
|
|
299
|
-
outline: "none",
|
|
300
|
-
transition: "border-color 0.2s"
|
|
301
|
-
},
|
|
302
|
-
select: {
|
|
303
|
-
padding: "0.5rem 0.75rem",
|
|
304
|
-
fontSize: "1rem",
|
|
305
|
-
border: "1px solid #e5e7eb",
|
|
306
|
-
borderRadius: "0.375rem",
|
|
307
|
-
outline: "none",
|
|
308
|
-
backgroundColor: "#ffffff"
|
|
309
|
-
},
|
|
310
|
-
checkbox: {
|
|
311
|
-
display: "flex",
|
|
312
|
-
alignItems: "center",
|
|
313
|
-
gap: "0.5rem",
|
|
314
|
-
marginBottom: "0.5rem"
|
|
315
|
-
},
|
|
316
|
-
checkboxInput: {
|
|
317
|
-
width: "1rem",
|
|
318
|
-
height: "1rem"
|
|
319
|
-
},
|
|
320
|
-
checkboxLabel: {
|
|
321
|
-
fontSize: "0.875rem",
|
|
322
|
-
color: "#374151"
|
|
323
|
-
},
|
|
324
|
-
buttonGroup: {
|
|
325
|
-
display: "flex",
|
|
326
|
-
gap: "1rem",
|
|
327
|
-
marginTop: "1rem"
|
|
328
|
-
},
|
|
329
|
-
button: {
|
|
330
|
-
padding: "0.75rem 1.5rem",
|
|
331
|
-
fontSize: "1rem",
|
|
332
|
-
fontWeight: "500",
|
|
333
|
-
borderRadius: "0.375rem",
|
|
334
|
-
cursor: "pointer",
|
|
335
|
-
transition: "all 0.2s",
|
|
336
|
-
border: "none"
|
|
337
|
-
},
|
|
338
|
-
primaryButton: {
|
|
339
|
-
color: "#ffffff",
|
|
340
|
-
backgroundColor: "#3b82f6"
|
|
341
|
-
},
|
|
342
|
-
secondaryButton: {
|
|
343
|
-
color: "#374151",
|
|
344
|
-
backgroundColor: "#ffffff",
|
|
345
|
-
border: "1px solid #e5e7eb"
|
|
346
|
-
},
|
|
347
|
-
dangerButton: {
|
|
348
|
-
color: "#ffffff",
|
|
349
|
-
backgroundColor: "#ef4444"
|
|
350
|
-
},
|
|
351
|
-
error: {
|
|
352
|
-
fontSize: "0.875rem",
|
|
353
|
-
color: "#ef4444",
|
|
354
|
-
marginTop: "0.5rem"
|
|
355
|
-
},
|
|
356
|
-
success: {
|
|
357
|
-
fontSize: "0.875rem",
|
|
358
|
-
color: "#10b981",
|
|
359
|
-
marginTop: "0.5rem"
|
|
360
|
-
},
|
|
361
|
-
info: {
|
|
362
|
-
fontSize: "0.875rem",
|
|
363
|
-
color: "#6b7280",
|
|
364
|
-
marginTop: "0.5rem"
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
var PreferencesForm = ({
|
|
368
|
-
subscriber: initialSubscriber,
|
|
369
|
-
onSuccess,
|
|
370
|
-
onError,
|
|
371
|
-
className,
|
|
372
|
-
styles: customStyles = {},
|
|
373
|
-
sessionToken,
|
|
374
|
-
apiEndpoint = "/api/newsletter/preferences",
|
|
375
|
-
showUnsubscribe = true,
|
|
376
|
-
locales = ["en"],
|
|
377
|
-
labels = {
|
|
378
|
-
title: "Newsletter Preferences",
|
|
379
|
-
personalInfo: "Personal Information",
|
|
380
|
-
emailPreferences: "Email Preferences",
|
|
381
|
-
name: "Name",
|
|
382
|
-
language: "Preferred Language",
|
|
383
|
-
newsletter: "Newsletter updates",
|
|
384
|
-
announcements: "Product announcements",
|
|
385
|
-
saveButton: "Save Preferences",
|
|
386
|
-
unsubscribeButton: "Unsubscribe",
|
|
387
|
-
saving: "Saving...",
|
|
388
|
-
saved: "Preferences saved successfully!",
|
|
389
|
-
unsubscribeConfirm: "Are you sure you want to unsubscribe? This cannot be undone."
|
|
390
|
-
}
|
|
391
|
-
}) => {
|
|
392
|
-
const [subscriber, setSubscriber] = useState2(initialSubscriber || {});
|
|
393
|
-
const [loading, setLoading] = useState2(false);
|
|
394
|
-
const [loadingData, setLoadingData] = useState2(!initialSubscriber);
|
|
395
|
-
const [error, setError] = useState2(null);
|
|
396
|
-
const [success, setSuccess] = useState2(false);
|
|
397
|
-
const styles = {
|
|
398
|
-
container: { ...defaultStyles2.container, ...customStyles.container },
|
|
399
|
-
heading: { ...defaultStyles2.heading, ...customStyles.heading },
|
|
400
|
-
form: { ...defaultStyles2.form, ...customStyles.form },
|
|
401
|
-
section: { ...defaultStyles2.section, ...customStyles.section },
|
|
402
|
-
sectionTitle: { ...defaultStyles2.sectionTitle, ...customStyles.sectionTitle },
|
|
403
|
-
inputGroup: { ...defaultStyles2.inputGroup, ...customStyles.inputGroup },
|
|
404
|
-
label: { ...defaultStyles2.label, ...customStyles.label },
|
|
405
|
-
input: { ...defaultStyles2.input, ...customStyles.input },
|
|
406
|
-
select: { ...defaultStyles2.select, ...customStyles.select },
|
|
407
|
-
checkbox: { ...defaultStyles2.checkbox, ...customStyles.checkbox },
|
|
408
|
-
checkboxInput: { ...defaultStyles2.checkboxInput, ...customStyles.checkboxInput },
|
|
409
|
-
checkboxLabel: { ...defaultStyles2.checkboxLabel, ...customStyles.checkboxLabel },
|
|
410
|
-
buttonGroup: { ...defaultStyles2.buttonGroup, ...customStyles.buttonGroup },
|
|
411
|
-
button: { ...defaultStyles2.button, ...customStyles.button },
|
|
412
|
-
primaryButton: { ...defaultStyles2.primaryButton, ...customStyles.primaryButton },
|
|
413
|
-
secondaryButton: { ...defaultStyles2.secondaryButton, ...customStyles.secondaryButton },
|
|
414
|
-
dangerButton: { ...defaultStyles2.dangerButton, ...customStyles.dangerButton },
|
|
415
|
-
error: { ...defaultStyles2.error, ...customStyles.error },
|
|
416
|
-
success: { ...defaultStyles2.success, ...customStyles.success },
|
|
417
|
-
info: { ...defaultStyles2.info, ...customStyles.info }
|
|
418
|
-
};
|
|
419
|
-
useEffect(() => {
|
|
420
|
-
if (!initialSubscriber && sessionToken) {
|
|
421
|
-
fetchPreferences();
|
|
422
|
-
}
|
|
423
|
-
}, []);
|
|
424
|
-
const fetchPreferences = async () => {
|
|
425
|
-
try {
|
|
426
|
-
const response = await fetch(apiEndpoint, {
|
|
427
|
-
headers: {
|
|
428
|
-
"Authorization": `Bearer ${sessionToken}`
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
if (!response.ok) {
|
|
432
|
-
throw new Error("Failed to load preferences");
|
|
433
|
-
}
|
|
434
|
-
const data = await response.json();
|
|
435
|
-
setSubscriber(data.subscriber);
|
|
436
|
-
} catch (err) {
|
|
437
|
-
setError(err instanceof Error ? err.message : "Failed to load preferences");
|
|
438
|
-
if (onError) {
|
|
439
|
-
onError(err instanceof Error ? err : new Error("Failed to load preferences"));
|
|
440
|
-
}
|
|
441
|
-
} finally {
|
|
442
|
-
setLoadingData(false);
|
|
97
|
+
// src/components/Broadcasts/BroadcastInlinePreview.tsx
|
|
98
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
99
|
+
var BroadcastInlinePreview = () => {
|
|
100
|
+
const [device, setDevice] = useState("desktop");
|
|
101
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
102
|
+
const [showPreview, setShowPreview] = useState(false);
|
|
103
|
+
const [previewHtml, setPreviewHtml] = useState(null);
|
|
104
|
+
const [error, setError] = useState(null);
|
|
105
|
+
const fields = useFormFields(([fields2]) => ({
|
|
106
|
+
subject: fields2["subject"]?.value,
|
|
107
|
+
preheader: fields2["contentSection.preheader"]?.value,
|
|
108
|
+
content: fields2["contentSection.content"]?.value
|
|
109
|
+
}));
|
|
110
|
+
const updatePreview = useCallback(async () => {
|
|
111
|
+
if (!fields.content) {
|
|
112
|
+
setError(new Error("Please add some content before previewing"));
|
|
113
|
+
return;
|
|
443
114
|
}
|
|
444
|
-
|
|
445
|
-
const handleSave = async (e) => {
|
|
446
|
-
e.preventDefault();
|
|
115
|
+
setIsLoading(true);
|
|
447
116
|
setError(null);
|
|
448
|
-
setSuccess(false);
|
|
449
|
-
setLoading(true);
|
|
450
117
|
try {
|
|
451
|
-
const response = await fetch(
|
|
118
|
+
const response = await fetch("/api/broadcasts/preview", {
|
|
452
119
|
method: "POST",
|
|
453
120
|
headers: {
|
|
454
|
-
"Content-Type": "application/json"
|
|
455
|
-
"Authorization": `Bearer ${sessionToken}`
|
|
121
|
+
"Content-Type": "application/json"
|
|
456
122
|
},
|
|
457
123
|
body: JSON.stringify({
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
124
|
+
content: fields.content,
|
|
125
|
+
preheader: fields.preheader,
|
|
126
|
+
subject: fields.subject
|
|
461
127
|
})
|
|
462
128
|
});
|
|
463
129
|
const data = await response.json();
|
|
464
|
-
if (!response.ok) {
|
|
465
|
-
throw new Error(data.error || "Failed to
|
|
466
|
-
}
|
|
467
|
-
setSubscriber(data.subscriber);
|
|
468
|
-
setSuccess(true);
|
|
469
|
-
if (onSuccess) {
|
|
470
|
-
onSuccess(data.subscriber);
|
|
130
|
+
if (!response.ok || !data.success) {
|
|
131
|
+
throw new Error(data.error || "Failed to generate preview");
|
|
471
132
|
}
|
|
133
|
+
setPreviewHtml(data.preview.html);
|
|
134
|
+
setShowPreview(true);
|
|
472
135
|
} catch (err) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
if (onError) {
|
|
476
|
-
onError(new Error(errorMessage));
|
|
477
|
-
}
|
|
136
|
+
setError(err);
|
|
137
|
+
console.error("Failed to update preview:", err);
|
|
478
138
|
} finally {
|
|
479
|
-
|
|
139
|
+
setIsLoading(false);
|
|
480
140
|
}
|
|
141
|
+
}, [fields]);
|
|
142
|
+
const containerStyle = {
|
|
143
|
+
border: "1px solid #e5e7eb",
|
|
144
|
+
borderRadius: "8px",
|
|
145
|
+
overflow: "hidden",
|
|
146
|
+
height: "100%",
|
|
147
|
+
display: "flex",
|
|
148
|
+
flexDirection: "column"
|
|
481
149
|
};
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const response = await fetch("/api/newsletter/unsubscribe", {
|
|
490
|
-
method: "POST",
|
|
491
|
-
headers: {
|
|
492
|
-
"Content-Type": "application/json",
|
|
493
|
-
"Authorization": `Bearer ${sessionToken}`
|
|
494
|
-
},
|
|
495
|
-
body: JSON.stringify({
|
|
496
|
-
email: subscriber.email
|
|
497
|
-
})
|
|
498
|
-
});
|
|
499
|
-
if (!response.ok) {
|
|
500
|
-
throw new Error("Failed to unsubscribe");
|
|
501
|
-
}
|
|
502
|
-
setSubscriber({ ...subscriber, subscriptionStatus: "unsubscribed" });
|
|
503
|
-
if (onSuccess) {
|
|
504
|
-
onSuccess({ ...subscriber, subscriptionStatus: "unsubscribed" });
|
|
505
|
-
}
|
|
506
|
-
} catch (err) {
|
|
507
|
-
setError("Failed to unsubscribe. Please try again.");
|
|
508
|
-
if (onError) {
|
|
509
|
-
onError(err instanceof Error ? err : new Error("Failed to unsubscribe"));
|
|
510
|
-
}
|
|
511
|
-
} finally {
|
|
512
|
-
setLoading(false);
|
|
513
|
-
}
|
|
150
|
+
const headerStyle = {
|
|
151
|
+
display: "flex",
|
|
152
|
+
alignItems: "center",
|
|
153
|
+
justifyContent: "space-between",
|
|
154
|
+
padding: "1rem",
|
|
155
|
+
background: "#f9fafb",
|
|
156
|
+
borderBottom: "1px solid #e5e7eb"
|
|
514
157
|
};
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
"
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
158
|
+
const titleStyle = {
|
|
159
|
+
fontSize: "16px",
|
|
160
|
+
fontWeight: 600,
|
|
161
|
+
color: "#1f2937",
|
|
162
|
+
margin: 0
|
|
163
|
+
};
|
|
164
|
+
const previewContainerStyle = {
|
|
165
|
+
flex: 1,
|
|
166
|
+
display: "flex",
|
|
167
|
+
flexDirection: "column",
|
|
168
|
+
background: "#f3f4f6",
|
|
169
|
+
overflow: "hidden"
|
|
170
|
+
};
|
|
171
|
+
const errorStyle = {
|
|
172
|
+
padding: "2rem",
|
|
173
|
+
textAlign: "center"
|
|
174
|
+
};
|
|
175
|
+
const toggleButtonStyle = {
|
|
176
|
+
padding: "0.5rem 1rem",
|
|
177
|
+
background: showPreview ? "#ef4444" : "#3b82f6",
|
|
178
|
+
color: "white",
|
|
179
|
+
border: "none",
|
|
180
|
+
borderRadius: "4px",
|
|
181
|
+
cursor: "pointer",
|
|
182
|
+
fontSize: "14px",
|
|
183
|
+
fontWeight: 500
|
|
184
|
+
};
|
|
185
|
+
return /* @__PURE__ */ jsxs2("div", { style: containerStyle, children: [
|
|
186
|
+
/* @__PURE__ */ jsxs2("div", { style: headerStyle, children: [
|
|
187
|
+
/* @__PURE__ */ jsx2("h3", { style: titleStyle, children: "Email Preview" }),
|
|
188
|
+
/* @__PURE__ */ jsx2(
|
|
189
|
+
"button",
|
|
190
|
+
{
|
|
191
|
+
onClick: () => showPreview ? setShowPreview(false) : updatePreview(),
|
|
192
|
+
style: toggleButtonStyle,
|
|
193
|
+
disabled: isLoading,
|
|
194
|
+
children: isLoading ? "Loading..." : showPreview ? "Hide Preview" : "Show Preview"
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
] }),
|
|
198
|
+
showPreview && /* @__PURE__ */ jsx2("div", { style: previewContainerStyle, children: error ? /* @__PURE__ */ jsxs2("div", { style: errorStyle, children: [
|
|
199
|
+
/* @__PURE__ */ jsx2("p", { style: { color: "#ef4444", margin: "0 0 1rem" }, children: error.message }),
|
|
200
|
+
/* @__PURE__ */ jsx2(
|
|
201
|
+
"button",
|
|
202
|
+
{
|
|
203
|
+
onClick: updatePreview,
|
|
204
|
+
style: {
|
|
205
|
+
padding: "0.5rem 1rem",
|
|
206
|
+
background: "#3b82f6",
|
|
207
|
+
color: "white",
|
|
208
|
+
border: "none",
|
|
209
|
+
borderRadius: "4px",
|
|
210
|
+
cursor: "pointer"
|
|
211
|
+
},
|
|
212
|
+
children: "Retry"
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
] }) : previewHtml ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
216
|
+
/* @__PURE__ */ jsx2(
|
|
217
|
+
PreviewControls,
|
|
218
|
+
{
|
|
219
|
+
onUpdate: updatePreview,
|
|
220
|
+
device,
|
|
221
|
+
onDeviceChange: setDevice,
|
|
222
|
+
isLoading
|
|
223
|
+
}
|
|
224
|
+
),
|
|
225
|
+
/* @__PURE__ */ jsx2(
|
|
226
|
+
"div",
|
|
227
|
+
{
|
|
228
|
+
style: {
|
|
229
|
+
flex: 1,
|
|
230
|
+
padding: device === "mobile" ? "1rem" : "2rem",
|
|
231
|
+
display: "flex",
|
|
232
|
+
justifyContent: "center",
|
|
233
|
+
overflow: "auto"
|
|
234
|
+
},
|
|
235
|
+
children: /* @__PURE__ */ jsx2(
|
|
236
|
+
"div",
|
|
583
237
|
{
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
238
|
+
style: {
|
|
239
|
+
width: device === "mobile" ? "375px" : "600px",
|
|
240
|
+
maxWidth: "100%",
|
|
241
|
+
background: "white",
|
|
242
|
+
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
243
|
+
borderRadius: "8px",
|
|
244
|
+
overflow: "hidden"
|
|
245
|
+
},
|
|
246
|
+
children: /* @__PURE__ */ jsx2(
|
|
247
|
+
"iframe",
|
|
248
|
+
{
|
|
249
|
+
srcDoc: previewHtml,
|
|
250
|
+
style: {
|
|
251
|
+
width: "100%",
|
|
252
|
+
height: "100%",
|
|
253
|
+
minHeight: "600px",
|
|
254
|
+
border: "none"
|
|
255
|
+
},
|
|
256
|
+
title: "Email Preview"
|
|
592
257
|
}
|
|
593
|
-
|
|
594
|
-
disabled: loading,
|
|
595
|
-
style: styles.checkboxInput
|
|
258
|
+
)
|
|
596
259
|
}
|
|
597
|
-
)
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
/* @__PURE__ */ jsxs2("div", { style: styles.buttonGroup, children: [
|
|
602
|
-
/* @__PURE__ */ jsx2(
|
|
603
|
-
"button",
|
|
604
|
-
{
|
|
605
|
-
type: "submit",
|
|
606
|
-
disabled: loading,
|
|
607
|
-
style: {
|
|
608
|
-
...styles.button,
|
|
609
|
-
...styles.primaryButton,
|
|
610
|
-
...loading && { opacity: 0.5, cursor: "not-allowed" }
|
|
611
|
-
},
|
|
612
|
-
children: loading ? labels.saving : labels.saveButton
|
|
613
|
-
}
|
|
614
|
-
),
|
|
615
|
-
showUnsubscribe && /* @__PURE__ */ jsx2(
|
|
616
|
-
"button",
|
|
617
|
-
{
|
|
618
|
-
type: "button",
|
|
619
|
-
onClick: handleUnsubscribe,
|
|
620
|
-
disabled: loading,
|
|
621
|
-
style: {
|
|
622
|
-
...styles.button,
|
|
623
|
-
...styles.dangerButton,
|
|
624
|
-
...loading && { opacity: 0.5, cursor: "not-allowed" }
|
|
625
|
-
},
|
|
626
|
-
children: labels.unsubscribeButton
|
|
627
|
-
}
|
|
628
|
-
)
|
|
629
|
-
] }),
|
|
630
|
-
error && /* @__PURE__ */ jsx2("p", { style: styles.error, children: error }),
|
|
631
|
-
success && /* @__PURE__ */ jsx2("p", { style: styles.success, children: labels.saved })
|
|
632
|
-
] })
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
] }) : null })
|
|
633
264
|
] });
|
|
634
265
|
};
|
|
635
|
-
function createPreferencesForm(defaultProps) {
|
|
636
|
-
return (props) => /* @__PURE__ */ jsx2(PreferencesForm, { ...defaultProps, ...props });
|
|
637
|
-
}
|
|
638
266
|
|
|
639
|
-
// src/components/
|
|
640
|
-
import {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
267
|
+
// src/components/Broadcasts/StatusBadge.tsx
|
|
268
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
269
|
+
var statusConfig = {
|
|
270
|
+
["draft" /* DRAFT */]: {
|
|
271
|
+
label: "Draft",
|
|
272
|
+
color: "#6B7280",
|
|
273
|
+
// gray
|
|
274
|
+
backgroundColor: "#F3F4F6"
|
|
275
|
+
},
|
|
276
|
+
["scheduled" /* SCHEDULED */]: {
|
|
277
|
+
label: "Scheduled",
|
|
278
|
+
color: "#2563EB",
|
|
279
|
+
// blue
|
|
280
|
+
backgroundColor: "#DBEAFE"
|
|
281
|
+
},
|
|
282
|
+
["sending" /* SENDING */]: {
|
|
283
|
+
label: "Sending",
|
|
284
|
+
color: "#D97706",
|
|
285
|
+
// yellow/orange
|
|
286
|
+
backgroundColor: "#FEF3C7"
|
|
648
287
|
},
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
288
|
+
["sent" /* SENT */]: {
|
|
289
|
+
label: "Sent",
|
|
290
|
+
color: "#059669",
|
|
291
|
+
// green
|
|
292
|
+
backgroundColor: "#D1FAE5"
|
|
654
293
|
},
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
color: "#
|
|
658
|
-
|
|
294
|
+
["failed" /* FAILED */]: {
|
|
295
|
+
label: "Failed",
|
|
296
|
+
color: "#DC2626",
|
|
297
|
+
// red
|
|
298
|
+
backgroundColor: "#FEE2E2"
|
|
659
299
|
},
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
color: "#
|
|
663
|
-
|
|
300
|
+
["paused" /* PAUSED */]: {
|
|
301
|
+
label: "Paused",
|
|
302
|
+
color: "#9333EA",
|
|
303
|
+
// purple
|
|
304
|
+
backgroundColor: "#EDE9FE"
|
|
664
305
|
},
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
backgroundColor: "#3b82f6",
|
|
671
|
-
border: "none",
|
|
672
|
-
borderRadius: "0.375rem",
|
|
673
|
-
cursor: "pointer",
|
|
674
|
-
transition: "background-color 0.2s"
|
|
306
|
+
["canceled" /* CANCELED */]: {
|
|
307
|
+
label: "Canceled",
|
|
308
|
+
color: "#6B7280",
|
|
309
|
+
// gray
|
|
310
|
+
backgroundColor: "#F3F4F6"
|
|
675
311
|
}
|
|
676
312
|
};
|
|
677
|
-
var
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const [status, setStatus] = useState3("verifying");
|
|
695
|
-
const [error, setError] = useState3(null);
|
|
696
|
-
const [_sessionToken, setSessionToken] = useState3(null);
|
|
697
|
-
const styles = {
|
|
698
|
-
container: { ...defaultStyles3.container, ...customStyles.container },
|
|
699
|
-
heading: { ...defaultStyles3.heading, ...customStyles.heading },
|
|
700
|
-
message: { ...defaultStyles3.message, ...customStyles.message },
|
|
701
|
-
error: { ...defaultStyles3.error, ...customStyles.error },
|
|
702
|
-
button: { ...defaultStyles3.button, ...customStyles.button }
|
|
703
|
-
};
|
|
704
|
-
useEffect2(() => {
|
|
705
|
-
const token = propToken || new URLSearchParams(window.location.search).get("token");
|
|
706
|
-
if (token) {
|
|
707
|
-
verifyToken(token);
|
|
708
|
-
} else {
|
|
709
|
-
setStatus("error");
|
|
710
|
-
setError(labels.invalid || "Invalid magic link");
|
|
711
|
-
}
|
|
712
|
-
}, [propToken]);
|
|
713
|
-
const verifyToken = async (token) => {
|
|
714
|
-
try {
|
|
715
|
-
const response = await fetch(apiEndpoint, {
|
|
716
|
-
method: "POST",
|
|
717
|
-
headers: {
|
|
718
|
-
"Content-Type": "application/json"
|
|
719
|
-
},
|
|
720
|
-
body: JSON.stringify({ token })
|
|
721
|
-
});
|
|
722
|
-
const data = await response.json();
|
|
723
|
-
if (!response.ok) {
|
|
724
|
-
if (data.error?.includes("expired")) {
|
|
725
|
-
throw new Error(labels.expired);
|
|
726
|
-
}
|
|
727
|
-
throw new Error(data.error || labels.error);
|
|
728
|
-
}
|
|
729
|
-
setStatus("success");
|
|
730
|
-
setSessionToken(data.sessionToken);
|
|
731
|
-
if (typeof window !== "undefined" && data.sessionToken) {
|
|
732
|
-
localStorage.setItem("newsletter_session", data.sessionToken);
|
|
733
|
-
}
|
|
734
|
-
if (onSuccess) {
|
|
735
|
-
onSuccess(data.sessionToken, data.subscriber);
|
|
736
|
-
}
|
|
737
|
-
} catch (err) {
|
|
738
|
-
setStatus("error");
|
|
739
|
-
const errorMessage = err instanceof Error ? err.message : labels.error || "Verification failed";
|
|
740
|
-
setError(errorMessage);
|
|
741
|
-
if (onError) {
|
|
742
|
-
onError(err instanceof Error ? err : new Error(errorMessage));
|
|
743
|
-
}
|
|
313
|
+
var StatusBadge = ({ cellData }) => {
|
|
314
|
+
const status = cellData;
|
|
315
|
+
const config = statusConfig[status] || statusConfig["draft" /* DRAFT */];
|
|
316
|
+
return /* @__PURE__ */ jsx3(
|
|
317
|
+
"span",
|
|
318
|
+
{
|
|
319
|
+
style: {
|
|
320
|
+
display: "inline-flex",
|
|
321
|
+
alignItems: "center",
|
|
322
|
+
padding: "2px 10px",
|
|
323
|
+
borderRadius: "12px",
|
|
324
|
+
fontSize: "12px",
|
|
325
|
+
fontWeight: "500",
|
|
326
|
+
color: config.color,
|
|
327
|
+
backgroundColor: config.backgroundColor
|
|
328
|
+
},
|
|
329
|
+
children: config.label
|
|
744
330
|
}
|
|
745
|
-
|
|
746
|
-
const handleTryAgain = () => {
|
|
747
|
-
window.location.href = "/";
|
|
748
|
-
};
|
|
749
|
-
return /* @__PURE__ */ jsxs3("div", { className, style: styles.container, children: [
|
|
750
|
-
status === "verifying" && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
751
|
-
/* @__PURE__ */ jsx3("h2", { style: styles.heading, children: "Verifying" }),
|
|
752
|
-
/* @__PURE__ */ jsx3("p", { style: styles.message, children: labels.verifying })
|
|
753
|
-
] }),
|
|
754
|
-
status === "success" && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
755
|
-
/* @__PURE__ */ jsx3("h2", { style: styles.heading, children: "Success!" }),
|
|
756
|
-
/* @__PURE__ */ jsx3("p", { style: styles.message, children: labels.success })
|
|
757
|
-
] }),
|
|
758
|
-
status === "error" && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
759
|
-
/* @__PURE__ */ jsx3("h2", { style: styles.heading, children: "Verification Failed" }),
|
|
760
|
-
/* @__PURE__ */ jsx3("p", { style: styles.error, children: error }),
|
|
761
|
-
/* @__PURE__ */ jsx3("button", { onClick: handleTryAgain, style: styles.button, children: labels.tryAgain })
|
|
762
|
-
] })
|
|
763
|
-
] });
|
|
331
|
+
);
|
|
764
332
|
};
|
|
765
|
-
function createMagicLinkVerify(defaultProps) {
|
|
766
|
-
return (props) => /* @__PURE__ */ jsx3(MagicLinkVerify, { ...defaultProps, ...props });
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// src/hooks/useNewsletterAuth.ts
|
|
770
|
-
import { useState as useState4, useEffect as useEffect3, useCallback } from "react";
|
|
771
|
-
function useNewsletterAuth(_options = {}) {
|
|
772
|
-
const [subscriber, setSubscriber] = useState4(null);
|
|
773
|
-
const [isLoading, setIsLoading] = useState4(true);
|
|
774
|
-
const [error, setError] = useState4(null);
|
|
775
|
-
const checkAuth = useCallback(async () => {
|
|
776
|
-
try {
|
|
777
|
-
const response = await fetch("/api/newsletter/me", {
|
|
778
|
-
method: "GET",
|
|
779
|
-
credentials: "include",
|
|
780
|
-
headers: {
|
|
781
|
-
"Content-Type": "application/json"
|
|
782
|
-
}
|
|
783
|
-
});
|
|
784
|
-
if (response.ok) {
|
|
785
|
-
const data = await response.json();
|
|
786
|
-
setSubscriber(data.subscriber);
|
|
787
|
-
setError(null);
|
|
788
|
-
} else {
|
|
789
|
-
setSubscriber(null);
|
|
790
|
-
if (response.status !== 401) {
|
|
791
|
-
setError(new Error("Failed to check authentication"));
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
} catch (err) {
|
|
795
|
-
console.error("Auth check failed:", err);
|
|
796
|
-
setError(err instanceof Error ? err : new Error("An error occurred"));
|
|
797
|
-
setSubscriber(null);
|
|
798
|
-
} finally {
|
|
799
|
-
setIsLoading(false);
|
|
800
|
-
}
|
|
801
|
-
}, []);
|
|
802
|
-
useEffect3(() => {
|
|
803
|
-
checkAuth();
|
|
804
|
-
}, [checkAuth]);
|
|
805
|
-
const signOut = useCallback(async () => {
|
|
806
|
-
try {
|
|
807
|
-
const response = await fetch("/api/newsletter/signout", {
|
|
808
|
-
method: "POST",
|
|
809
|
-
credentials: "include",
|
|
810
|
-
headers: {
|
|
811
|
-
"Content-Type": "application/json"
|
|
812
|
-
}
|
|
813
|
-
});
|
|
814
|
-
if (response.ok) {
|
|
815
|
-
setSubscriber(null);
|
|
816
|
-
setError(null);
|
|
817
|
-
} else {
|
|
818
|
-
throw new Error("Failed to sign out");
|
|
819
|
-
}
|
|
820
|
-
} catch (err) {
|
|
821
|
-
console.error("Sign out error:", err);
|
|
822
|
-
setError(err instanceof Error ? err : new Error("Sign out failed"));
|
|
823
|
-
throw err;
|
|
824
|
-
}
|
|
825
|
-
}, []);
|
|
826
|
-
const refreshAuth = useCallback(async () => {
|
|
827
|
-
setIsLoading(true);
|
|
828
|
-
await checkAuth();
|
|
829
|
-
}, [checkAuth]);
|
|
830
|
-
const login = useCallback(async (_token) => {
|
|
831
|
-
await refreshAuth();
|
|
832
|
-
}, [refreshAuth]);
|
|
833
|
-
return {
|
|
834
|
-
subscriber,
|
|
835
|
-
isAuthenticated: !!subscriber,
|
|
836
|
-
isLoading,
|
|
837
|
-
loading: isLoading,
|
|
838
|
-
// Alias for backward compatibility
|
|
839
|
-
error,
|
|
840
|
-
signOut,
|
|
841
|
-
logout: signOut,
|
|
842
|
-
// Alias for backward compatibility
|
|
843
|
-
refreshAuth,
|
|
844
|
-
refreshSubscriber: refreshAuth,
|
|
845
|
-
// Alias for backward compatibility
|
|
846
|
-
login
|
|
847
|
-
// For backward compatibility
|
|
848
|
-
};
|
|
849
|
-
}
|
|
850
333
|
|
|
851
334
|
// src/components/Broadcasts/EmailPreview.tsx
|
|
852
|
-
import { useState as
|
|
335
|
+
import { useState as useState2, useEffect, useRef } from "react";
|
|
853
336
|
|
|
854
337
|
// src/utils/emailSafeHtml.ts
|
|
855
338
|
import DOMPurify from "isomorphic-dompurify";
|
|
@@ -1430,7 +913,7 @@ var usePluginConfigOptional = () => {
|
|
|
1430
913
|
};
|
|
1431
914
|
|
|
1432
915
|
// src/components/Broadcasts/EmailPreview.tsx
|
|
1433
|
-
import { jsx as jsx5, jsxs as
|
|
916
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1434
917
|
var SAMPLE_DATA = {
|
|
1435
918
|
"subscriber.name": "John Doe",
|
|
1436
919
|
"subscriber.firstName": "John",
|
|
@@ -1451,11 +934,11 @@ var EmailPreview = ({
|
|
|
1451
934
|
}) => {
|
|
1452
935
|
const contextPluginConfig = usePluginConfigOptional();
|
|
1453
936
|
const pluginConfig = propPluginConfig || contextPluginConfig;
|
|
1454
|
-
const [html, setHtml] =
|
|
1455
|
-
const [loading, setLoading] =
|
|
1456
|
-
const [validationResult, setValidationResult] =
|
|
937
|
+
const [html, setHtml] = useState2("");
|
|
938
|
+
const [loading, setLoading] = useState2(false);
|
|
939
|
+
const [validationResult, setValidationResult] = useState2(null);
|
|
1457
940
|
const iframeRef = useRef(null);
|
|
1458
|
-
|
|
941
|
+
useEffect(() => {
|
|
1459
942
|
const convertContent = async () => {
|
|
1460
943
|
if (!content) {
|
|
1461
944
|
setHtml("");
|
|
@@ -1490,7 +973,7 @@ var EmailPreview = ({
|
|
|
1490
973
|
};
|
|
1491
974
|
convertContent();
|
|
1492
975
|
}, [content, subject, preheader, onValidation, pluginConfig]);
|
|
1493
|
-
|
|
976
|
+
useEffect(() => {
|
|
1494
977
|
if (iframeRef.current && html) {
|
|
1495
978
|
const doc = iframeRef.current.contentDocument;
|
|
1496
979
|
if (doc) {
|
|
@@ -1501,18 +984,18 @@ var EmailPreview = ({
|
|
|
1501
984
|
}
|
|
1502
985
|
}, [html]);
|
|
1503
986
|
const viewport = VIEWPORT_SIZES[mode];
|
|
1504
|
-
return /* @__PURE__ */
|
|
1505
|
-
validationResult && (validationResult.errors.length > 0 || validationResult.warnings.length > 0) && /* @__PURE__ */
|
|
1506
|
-
validationResult.errors.length > 0 && /* @__PURE__ */
|
|
1507
|
-
/* @__PURE__ */
|
|
987
|
+
return /* @__PURE__ */ jsxs3("div", { style: { height: "100%", display: "flex", flexDirection: "column" }, children: [
|
|
988
|
+
validationResult && (validationResult.errors.length > 0 || validationResult.warnings.length > 0) && /* @__PURE__ */ jsxs3("div", { style: { padding: "16px", borderBottom: "1px solid #e5e7eb" }, children: [
|
|
989
|
+
validationResult.errors.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "12px" }, children: [
|
|
990
|
+
/* @__PURE__ */ jsxs3("h4", { style: { color: "#dc2626", margin: "0 0 8px 0", fontSize: "14px" }, children: [
|
|
1508
991
|
"Errors (",
|
|
1509
992
|
validationResult.errors.length,
|
|
1510
993
|
")"
|
|
1511
994
|
] }),
|
|
1512
995
|
/* @__PURE__ */ jsx5("ul", { style: { margin: 0, paddingLeft: "20px", fontSize: "13px", color: "#dc2626" }, children: validationResult.errors.map((error, index) => /* @__PURE__ */ jsx5("li", { children: error }, index)) })
|
|
1513
996
|
] }),
|
|
1514
|
-
validationResult.warnings.length > 0 && /* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
997
|
+
validationResult.warnings.length > 0 && /* @__PURE__ */ jsxs3("div", { children: [
|
|
998
|
+
/* @__PURE__ */ jsxs3("h4", { style: { color: "#d97706", margin: "0 0 8px 0", fontSize: "14px" }, children: [
|
|
1516
999
|
"Warnings (",
|
|
1517
1000
|
validationResult.warnings.length,
|
|
1518
1001
|
")"
|
|
@@ -1549,7 +1032,7 @@ var EmailPreview = ({
|
|
|
1549
1032
|
sandbox: "allow-same-origin"
|
|
1550
1033
|
}
|
|
1551
1034
|
) }) : /* @__PURE__ */ jsx5("div", { style: { textAlign: "center", color: "#6b7280" }, children: /* @__PURE__ */ jsx5("p", { children: "Start typing to see the email preview" }) }) }),
|
|
1552
|
-
validationResult && /* @__PURE__ */
|
|
1035
|
+
validationResult && /* @__PURE__ */ jsxs3("div", { style: {
|
|
1553
1036
|
padding: "12px 16px",
|
|
1554
1037
|
borderTop: "1px solid #e5e7eb",
|
|
1555
1038
|
fontSize: "13px",
|
|
@@ -1557,194 +1040,52 @@ var EmailPreview = ({
|
|
|
1557
1040
|
display: "flex",
|
|
1558
1041
|
gap: "24px"
|
|
1559
1042
|
}, children: [
|
|
1560
|
-
/* @__PURE__ */
|
|
1043
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1561
1044
|
"Size: ",
|
|
1562
1045
|
Math.round(validationResult.stats.sizeInBytes / 1024),
|
|
1563
1046
|
"KB"
|
|
1564
1047
|
] }),
|
|
1565
|
-
/* @__PURE__ */
|
|
1048
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1566
1049
|
"Links: ",
|
|
1567
1050
|
validationResult.stats.linkCount
|
|
1568
1051
|
] }),
|
|
1569
|
-
/* @__PURE__ */
|
|
1052
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1570
1053
|
"Images: ",
|
|
1571
1054
|
validationResult.stats.imageCount
|
|
1572
1055
|
] }),
|
|
1573
|
-
/* @__PURE__ */
|
|
1056
|
+
/* @__PURE__ */ jsxs3("span", { children: [
|
|
1574
1057
|
"Viewport: ",
|
|
1575
1058
|
mode === "desktop" ? "600px" : "320px"
|
|
1576
1059
|
] })
|
|
1577
|
-
] })
|
|
1578
|
-
] });
|
|
1579
|
-
};
|
|
1580
|
-
function addEmailHeader(html, headers) {
|
|
1581
|
-
const headerHtml = `
|
|
1582
|
-
<div style="background-color: #f9fafb; border-bottom: 1px solid #e5e7eb; padding: 16px; font-family: monospace; font-size: 13px;">
|
|
1583
|
-
<div style="margin-bottom: 8px;"><strong>Subject:</strong> ${escapeHtml2(headers.subject)}</div>
|
|
1584
|
-
<div style="margin-bottom: 8px;"><strong>From:</strong> ${escapeHtml2(headers.from)}</div>
|
|
1585
|
-
<div><strong>To:</strong> ${escapeHtml2(headers.to)}</div>
|
|
1586
|
-
</div>
|
|
1587
|
-
`;
|
|
1588
|
-
return html.replace(/<body[^>]*>/, `$&${headerHtml}`);
|
|
1589
|
-
}
|
|
1590
|
-
function escapeHtml2(text) {
|
|
1591
|
-
const div = document.createElement("div");
|
|
1592
|
-
div.textContent = text;
|
|
1593
|
-
return div.innerHTML;
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
// src/components/Broadcasts/EmailPreviewField.tsx
|
|
1597
|
-
import { useState as useState6 } from "react";
|
|
1598
|
-
import { useFormFields } from "@payloadcms/ui";
|
|
1599
|
-
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1600
|
-
var EmailPreviewField = () => {
|
|
1601
|
-
const [previewMode, setPreviewMode] = useState6("desktop");
|
|
1602
|
-
const [isValid, setIsValid] = useState6(true);
|
|
1603
|
-
const [validationSummary, setValidationSummary] = useState6("");
|
|
1604
|
-
const pluginConfig = usePluginConfigOptional();
|
|
1605
|
-
const fields = useFormFields(([fields2]) => ({
|
|
1606
|
-
content: fields2["contentSection.content"],
|
|
1607
|
-
subject: fields2["subject"],
|
|
1608
|
-
preheader: fields2["contentSection.preheader"],
|
|
1609
|
-
channel: fields2.channel
|
|
1610
|
-
}));
|
|
1611
|
-
const handleValidation = (result) => {
|
|
1612
|
-
setIsValid(result.valid);
|
|
1613
|
-
const errorCount = result.errors.length;
|
|
1614
|
-
const warningCount = result.warnings.length;
|
|
1615
|
-
if (errorCount > 0) {
|
|
1616
|
-
setValidationSummary(`${errorCount} error${errorCount !== 1 ? "s" : ""}, ${warningCount} warning${warningCount !== 1 ? "s" : ""}`);
|
|
1617
|
-
} else if (warningCount > 0) {
|
|
1618
|
-
setValidationSummary(`${warningCount} warning${warningCount !== 1 ? "s" : ""}`);
|
|
1619
|
-
} else {
|
|
1620
|
-
setValidationSummary("");
|
|
1621
|
-
}
|
|
1622
|
-
};
|
|
1623
|
-
const handleTestEmail = async () => {
|
|
1624
|
-
const pathParts = window.location.pathname.split("/");
|
|
1625
|
-
const broadcastId = pathParts[pathParts.length - 1];
|
|
1626
|
-
if (!broadcastId || broadcastId === "create") {
|
|
1627
|
-
alert("Please save the broadcast before sending a test email");
|
|
1628
|
-
return;
|
|
1629
|
-
}
|
|
1630
|
-
try {
|
|
1631
|
-
const response = await fetch(`/api/broadcasts/${broadcastId}/test`, {
|
|
1632
|
-
method: "POST",
|
|
1633
|
-
headers: {
|
|
1634
|
-
"Content-Type": "application/json"
|
|
1635
|
-
}
|
|
1636
|
-
});
|
|
1637
|
-
if (!response.ok) {
|
|
1638
|
-
const data = await response.json();
|
|
1639
|
-
throw new Error(data.error || "Failed to send test email");
|
|
1640
|
-
}
|
|
1641
|
-
alert("Test email sent successfully! Check your inbox.");
|
|
1642
|
-
} catch (error) {
|
|
1643
|
-
alert(error instanceof Error ? error.message : "Failed to send test email");
|
|
1644
|
-
}
|
|
1645
|
-
};
|
|
1646
|
-
return /* @__PURE__ */ jsxs5("div", { style: {
|
|
1647
|
-
marginTop: "24px",
|
|
1648
|
-
border: "1px solid #e5e7eb",
|
|
1649
|
-
borderRadius: "8px",
|
|
1650
|
-
overflow: "hidden"
|
|
1651
|
-
}, children: [
|
|
1652
|
-
/* @__PURE__ */ jsxs5("div", { style: {
|
|
1653
|
-
display: "flex",
|
|
1654
|
-
alignItems: "center",
|
|
1655
|
-
justifyContent: "space-between",
|
|
1656
|
-
padding: "12px 16px",
|
|
1657
|
-
borderBottom: "1px solid #e5e7eb",
|
|
1658
|
-
backgroundColor: "#f9fafb"
|
|
1659
|
-
}, children: [
|
|
1660
|
-
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", alignItems: "center", gap: "16px" }, children: [
|
|
1661
|
-
/* @__PURE__ */ jsx6("h3", { style: { margin: 0, fontSize: "16px", fontWeight: 600 }, children: "Email Preview" }),
|
|
1662
|
-
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
1663
|
-
/* @__PURE__ */ jsx6(
|
|
1664
|
-
"button",
|
|
1665
|
-
{
|
|
1666
|
-
type: "button",
|
|
1667
|
-
onClick: () => setPreviewMode("desktop"),
|
|
1668
|
-
style: {
|
|
1669
|
-
padding: "6px 12px",
|
|
1670
|
-
backgroundColor: previewMode === "desktop" ? "#6366f1" : "#e5e7eb",
|
|
1671
|
-
color: previewMode === "desktop" ? "white" : "#374151",
|
|
1672
|
-
border: "none",
|
|
1673
|
-
borderRadius: "4px 0 0 4px",
|
|
1674
|
-
fontSize: "14px",
|
|
1675
|
-
cursor: "pointer"
|
|
1676
|
-
},
|
|
1677
|
-
children: "Desktop"
|
|
1678
|
-
}
|
|
1679
|
-
),
|
|
1680
|
-
/* @__PURE__ */ jsx6(
|
|
1681
|
-
"button",
|
|
1682
|
-
{
|
|
1683
|
-
type: "button",
|
|
1684
|
-
onClick: () => setPreviewMode("mobile"),
|
|
1685
|
-
style: {
|
|
1686
|
-
padding: "6px 12px",
|
|
1687
|
-
backgroundColor: previewMode === "mobile" ? "#6366f1" : "#e5e7eb",
|
|
1688
|
-
color: previewMode === "mobile" ? "white" : "#374151",
|
|
1689
|
-
border: "none",
|
|
1690
|
-
borderRadius: "0 4px 4px 0",
|
|
1691
|
-
fontSize: "14px",
|
|
1692
|
-
cursor: "pointer"
|
|
1693
|
-
},
|
|
1694
|
-
children: "Mobile"
|
|
1695
|
-
}
|
|
1696
|
-
)
|
|
1697
|
-
] }),
|
|
1698
|
-
validationSummary && /* @__PURE__ */ jsx6("div", { style: {
|
|
1699
|
-
padding: "6px 12px",
|
|
1700
|
-
backgroundColor: isValid ? "#fef3c7" : "#fee2e2",
|
|
1701
|
-
color: isValid ? "#92400e" : "#991b1b",
|
|
1702
|
-
borderRadius: "4px",
|
|
1703
|
-
fontSize: "13px"
|
|
1704
|
-
}, children: validationSummary })
|
|
1705
|
-
] }),
|
|
1706
|
-
/* @__PURE__ */ jsx6(
|
|
1707
|
-
"button",
|
|
1708
|
-
{
|
|
1709
|
-
type: "button",
|
|
1710
|
-
onClick: handleTestEmail,
|
|
1711
|
-
style: {
|
|
1712
|
-
padding: "6px 12px",
|
|
1713
|
-
backgroundColor: "#10b981",
|
|
1714
|
-
color: "white",
|
|
1715
|
-
border: "none",
|
|
1716
|
-
borderRadius: "4px",
|
|
1717
|
-
fontSize: "14px",
|
|
1718
|
-
cursor: "pointer"
|
|
1719
|
-
},
|
|
1720
|
-
children: "Send Test Email"
|
|
1721
|
-
}
|
|
1722
|
-
)
|
|
1723
|
-
] }),
|
|
1724
|
-
/* @__PURE__ */ jsx6("div", { style: { height: "600px" }, children: /* @__PURE__ */ jsx6(
|
|
1725
|
-
EmailPreview,
|
|
1726
|
-
{
|
|
1727
|
-
content: fields.content?.value || null,
|
|
1728
|
-
subject: fields.subject?.value || "Email Subject",
|
|
1729
|
-
preheader: fields.preheader?.value,
|
|
1730
|
-
mode: previewMode,
|
|
1731
|
-
onValidation: handleValidation,
|
|
1732
|
-
pluginConfig: pluginConfig || void 0
|
|
1733
|
-
}
|
|
1734
|
-
) })
|
|
1060
|
+
] })
|
|
1735
1061
|
] });
|
|
1736
1062
|
};
|
|
1063
|
+
function addEmailHeader(html, headers) {
|
|
1064
|
+
const headerHtml = `
|
|
1065
|
+
<div style="background-color: #f9fafb; border-bottom: 1px solid #e5e7eb; padding: 16px; font-family: monospace; font-size: 13px;">
|
|
1066
|
+
<div style="margin-bottom: 8px;"><strong>Subject:</strong> ${escapeHtml2(headers.subject)}</div>
|
|
1067
|
+
<div style="margin-bottom: 8px;"><strong>From:</strong> ${escapeHtml2(headers.from)}</div>
|
|
1068
|
+
<div><strong>To:</strong> ${escapeHtml2(headers.to)}</div>
|
|
1069
|
+
</div>
|
|
1070
|
+
`;
|
|
1071
|
+
return html.replace(/<body[^>]*>/, `$&${headerHtml}`);
|
|
1072
|
+
}
|
|
1073
|
+
function escapeHtml2(text) {
|
|
1074
|
+
const div = document.createElement("div");
|
|
1075
|
+
div.textContent = text;
|
|
1076
|
+
return div.innerHTML;
|
|
1077
|
+
}
|
|
1737
1078
|
|
|
1738
1079
|
// src/components/Broadcasts/BroadcastEditor.tsx
|
|
1739
|
-
import { useState as
|
|
1080
|
+
import { useState as useState3, useCallback as useCallback2 } from "react";
|
|
1740
1081
|
import { useField, useFormFields as useFormFields2 } from "@payloadcms/ui";
|
|
1741
|
-
import { jsx as
|
|
1082
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1742
1083
|
var BroadcastEditor = (props) => {
|
|
1743
1084
|
const { value } = useField({ path: props.path });
|
|
1744
|
-
const [showPreview, setShowPreview] =
|
|
1745
|
-
const [previewMode, setPreviewMode] =
|
|
1746
|
-
const [isValid, setIsValid] =
|
|
1747
|
-
const [validationSummary, setValidationSummary] =
|
|
1085
|
+
const [showPreview, setShowPreview] = useState3(true);
|
|
1086
|
+
const [previewMode, setPreviewMode] = useState3("desktop");
|
|
1087
|
+
const [isValid, setIsValid] = useState3(true);
|
|
1088
|
+
const [validationSummary, setValidationSummary] = useState3("");
|
|
1748
1089
|
const fields = useFormFields2(([fields2]) => ({
|
|
1749
1090
|
subject: fields2["subject"],
|
|
1750
1091
|
preheader: fields2["contentSection.preheader"]
|
|
@@ -1784,8 +1125,8 @@ var BroadcastEditor = (props) => {
|
|
|
1784
1125
|
alert(error instanceof Error ? error.message : "Failed to send test email");
|
|
1785
1126
|
}
|
|
1786
1127
|
};
|
|
1787
|
-
return /* @__PURE__ */
|
|
1788
|
-
/* @__PURE__ */
|
|
1128
|
+
return /* @__PURE__ */ jsxs4("div", { style: { height: "600px", display: "flex", flexDirection: "column" }, children: [
|
|
1129
|
+
/* @__PURE__ */ jsxs4("div", { style: {
|
|
1789
1130
|
display: "flex",
|
|
1790
1131
|
alignItems: "center",
|
|
1791
1132
|
justifyContent: "space-between",
|
|
@@ -1793,8 +1134,8 @@ var BroadcastEditor = (props) => {
|
|
|
1793
1134
|
borderBottom: "1px solid #e5e7eb",
|
|
1794
1135
|
backgroundColor: "#f9fafb"
|
|
1795
1136
|
}, children: [
|
|
1796
|
-
/* @__PURE__ */
|
|
1797
|
-
/* @__PURE__ */
|
|
1137
|
+
/* @__PURE__ */ jsxs4("div", { style: { display: "flex", alignItems: "center", gap: "16px" }, children: [
|
|
1138
|
+
/* @__PURE__ */ jsx6(
|
|
1798
1139
|
"button",
|
|
1799
1140
|
{
|
|
1800
1141
|
type: "button",
|
|
@@ -1811,8 +1152,8 @@ var BroadcastEditor = (props) => {
|
|
|
1811
1152
|
children: showPreview ? "Hide Preview" : "Show Preview"
|
|
1812
1153
|
}
|
|
1813
1154
|
),
|
|
1814
|
-
showPreview && /* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1155
|
+
showPreview && /* @__PURE__ */ jsxs4("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
1156
|
+
/* @__PURE__ */ jsx6(
|
|
1816
1157
|
"button",
|
|
1817
1158
|
{
|
|
1818
1159
|
type: "button",
|
|
@@ -1829,7 +1170,7 @@ var BroadcastEditor = (props) => {
|
|
|
1829
1170
|
children: "Desktop"
|
|
1830
1171
|
}
|
|
1831
1172
|
),
|
|
1832
|
-
/* @__PURE__ */
|
|
1173
|
+
/* @__PURE__ */ jsx6(
|
|
1833
1174
|
"button",
|
|
1834
1175
|
{
|
|
1835
1176
|
type: "button",
|
|
@@ -1847,7 +1188,7 @@ var BroadcastEditor = (props) => {
|
|
|
1847
1188
|
}
|
|
1848
1189
|
)
|
|
1849
1190
|
] }),
|
|
1850
|
-
showPreview && validationSummary && /* @__PURE__ */
|
|
1191
|
+
showPreview && validationSummary && /* @__PURE__ */ jsx6("div", { style: {
|
|
1851
1192
|
padding: "6px 12px",
|
|
1852
1193
|
backgroundColor: isValid ? "#fef3c7" : "#fee2e2",
|
|
1853
1194
|
color: isValid ? "#92400e" : "#991b1b",
|
|
@@ -1855,7 +1196,7 @@ var BroadcastEditor = (props) => {
|
|
|
1855
1196
|
fontSize: "13px"
|
|
1856
1197
|
}, children: validationSummary })
|
|
1857
1198
|
] }),
|
|
1858
|
-
showPreview && /* @__PURE__ */
|
|
1199
|
+
showPreview && /* @__PURE__ */ jsx6(
|
|
1859
1200
|
"button",
|
|
1860
1201
|
{
|
|
1861
1202
|
type: "button",
|
|
@@ -1873,13 +1214,13 @@ var BroadcastEditor = (props) => {
|
|
|
1873
1214
|
}
|
|
1874
1215
|
)
|
|
1875
1216
|
] }),
|
|
1876
|
-
/* @__PURE__ */
|
|
1877
|
-
/* @__PURE__ */
|
|
1217
|
+
/* @__PURE__ */ jsxs4("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
|
|
1218
|
+
/* @__PURE__ */ jsx6("div", { style: {
|
|
1878
1219
|
flex: showPreview ? "0 0 50%" : "1",
|
|
1879
1220
|
overflow: "auto",
|
|
1880
1221
|
borderRight: showPreview ? "1px solid #e5e7eb" : "none"
|
|
1881
|
-
}, children: /* @__PURE__ */
|
|
1882
|
-
showPreview && /* @__PURE__ */
|
|
1222
|
+
}, children: /* @__PURE__ */ jsx6("div", { style: { padding: "16px" }, children: /* @__PURE__ */ jsx6("div", { className: "rich-text-lexical" }) }) }),
|
|
1223
|
+
showPreview && /* @__PURE__ */ jsx6("div", { style: { flex: "0 0 50%", overflow: "hidden" }, children: /* @__PURE__ */ jsx6(
|
|
1883
1224
|
EmailPreview,
|
|
1884
1225
|
{
|
|
1885
1226
|
content: value,
|
|
@@ -1893,273 +1234,152 @@ var BroadcastEditor = (props) => {
|
|
|
1893
1234
|
] });
|
|
1894
1235
|
};
|
|
1895
1236
|
|
|
1896
|
-
// src/components/Broadcasts/
|
|
1897
|
-
import { useState as
|
|
1237
|
+
// src/components/Broadcasts/EmailPreviewField.tsx
|
|
1238
|
+
import { useState as useState4 } from "react";
|
|
1898
1239
|
import { useFormFields as useFormFields3 } from "@payloadcms/ui";
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
onDeviceChange,
|
|
1906
|
-
isLoading = false
|
|
1907
|
-
}) => {
|
|
1908
|
-
const controlsStyle = {
|
|
1909
|
-
display: "flex",
|
|
1910
|
-
alignItems: "center",
|
|
1911
|
-
justifyContent: "space-between",
|
|
1912
|
-
padding: "1rem",
|
|
1913
|
-
background: "white",
|
|
1914
|
-
borderBottom: "1px solid #e5e7eb"
|
|
1915
|
-
};
|
|
1916
|
-
const updateButtonStyle = {
|
|
1917
|
-
padding: "0.5rem 1rem",
|
|
1918
|
-
background: "#10b981",
|
|
1919
|
-
color: "white",
|
|
1920
|
-
border: "none",
|
|
1921
|
-
borderRadius: "4px",
|
|
1922
|
-
cursor: isLoading ? "not-allowed" : "pointer",
|
|
1923
|
-
fontSize: "14px",
|
|
1924
|
-
fontWeight: 500,
|
|
1925
|
-
opacity: isLoading ? 0.6 : 1
|
|
1926
|
-
};
|
|
1927
|
-
const deviceSelectorStyle = {
|
|
1928
|
-
display: "flex",
|
|
1929
|
-
gap: "0.5rem"
|
|
1930
|
-
};
|
|
1931
|
-
const deviceButtonStyle = (isActive) => ({
|
|
1932
|
-
display: "flex",
|
|
1933
|
-
alignItems: "center",
|
|
1934
|
-
gap: "0.5rem",
|
|
1935
|
-
padding: "0.5rem 0.75rem",
|
|
1936
|
-
background: isActive ? "#1f2937" : "white",
|
|
1937
|
-
color: isActive ? "white" : "#374151",
|
|
1938
|
-
border: `1px solid ${isActive ? "#1f2937" : "#e5e7eb"}`,
|
|
1939
|
-
borderRadius: "4px",
|
|
1940
|
-
cursor: "pointer",
|
|
1941
|
-
fontSize: "14px"
|
|
1942
|
-
});
|
|
1943
|
-
return /* @__PURE__ */ jsxs7("div", { style: controlsStyle, children: [
|
|
1944
|
-
/* @__PURE__ */ jsx8(
|
|
1945
|
-
"button",
|
|
1946
|
-
{
|
|
1947
|
-
style: updateButtonStyle,
|
|
1948
|
-
onClick: onUpdate,
|
|
1949
|
-
disabled: isLoading,
|
|
1950
|
-
children: isLoading ? "Updating..." : "Update Preview"
|
|
1951
|
-
}
|
|
1952
|
-
),
|
|
1953
|
-
/* @__PURE__ */ jsxs7("div", { style: deviceSelectorStyle, children: [
|
|
1954
|
-
/* @__PURE__ */ jsxs7(
|
|
1955
|
-
"button",
|
|
1956
|
-
{
|
|
1957
|
-
style: deviceButtonStyle(device === "desktop"),
|
|
1958
|
-
onClick: () => onDeviceChange("desktop"),
|
|
1959
|
-
"aria-label": "Desktop view",
|
|
1960
|
-
children: [
|
|
1961
|
-
/* @__PURE__ */ jsxs7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1962
|
-
/* @__PURE__ */ jsx8("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }),
|
|
1963
|
-
/* @__PURE__ */ jsx8("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
|
|
1964
|
-
/* @__PURE__ */ jsx8("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
|
|
1965
|
-
] }),
|
|
1966
|
-
"Desktop"
|
|
1967
|
-
]
|
|
1968
|
-
}
|
|
1969
|
-
),
|
|
1970
|
-
/* @__PURE__ */ jsxs7(
|
|
1971
|
-
"button",
|
|
1972
|
-
{
|
|
1973
|
-
style: deviceButtonStyle(device === "mobile"),
|
|
1974
|
-
onClick: () => onDeviceChange("mobile"),
|
|
1975
|
-
"aria-label": "Mobile view",
|
|
1976
|
-
children: [
|
|
1977
|
-
/* @__PURE__ */ jsxs7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1978
|
-
/* @__PURE__ */ jsx8("rect", { x: "5", y: "2", width: "14", height: "20", rx: "2", ry: "2" }),
|
|
1979
|
-
/* @__PURE__ */ jsx8("line", { x1: "12", y1: "18", x2: "12", y2: "18" })
|
|
1980
|
-
] }),
|
|
1981
|
-
"Mobile"
|
|
1982
|
-
]
|
|
1983
|
-
}
|
|
1984
|
-
)
|
|
1985
|
-
] })
|
|
1986
|
-
] });
|
|
1987
|
-
};
|
|
1988
|
-
|
|
1989
|
-
// src/components/Broadcasts/BroadcastInlinePreview.tsx
|
|
1990
|
-
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1991
|
-
var BroadcastInlinePreview = () => {
|
|
1992
|
-
const [device, setDevice] = useState8("desktop");
|
|
1993
|
-
const [isLoading, setIsLoading] = useState8(false);
|
|
1994
|
-
const [showPreview, setShowPreview] = useState8(false);
|
|
1995
|
-
const [previewHtml, setPreviewHtml] = useState8(null);
|
|
1996
|
-
const [error, setError] = useState8(null);
|
|
1240
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1241
|
+
var EmailPreviewField = () => {
|
|
1242
|
+
const [previewMode, setPreviewMode] = useState4("desktop");
|
|
1243
|
+
const [isValid, setIsValid] = useState4(true);
|
|
1244
|
+
const [validationSummary, setValidationSummary] = useState4("");
|
|
1245
|
+
const pluginConfig = usePluginConfigOptional();
|
|
1997
1246
|
const fields = useFormFields3(([fields2]) => ({
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
1247
|
+
content: fields2["contentSection.content"],
|
|
1248
|
+
subject: fields2["subject"],
|
|
1249
|
+
preheader: fields2["contentSection.preheader"],
|
|
1250
|
+
channel: fields2.channel
|
|
2001
1251
|
}));
|
|
2002
|
-
const
|
|
2003
|
-
|
|
2004
|
-
|
|
1252
|
+
const handleValidation = (result) => {
|
|
1253
|
+
setIsValid(result.valid);
|
|
1254
|
+
const errorCount = result.errors.length;
|
|
1255
|
+
const warningCount = result.warnings.length;
|
|
1256
|
+
if (errorCount > 0) {
|
|
1257
|
+
setValidationSummary(`${errorCount} error${errorCount !== 1 ? "s" : ""}, ${warningCount} warning${warningCount !== 1 ? "s" : ""}`);
|
|
1258
|
+
} else if (warningCount > 0) {
|
|
1259
|
+
setValidationSummary(`${warningCount} warning${warningCount !== 1 ? "s" : ""}`);
|
|
1260
|
+
} else {
|
|
1261
|
+
setValidationSummary("");
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
const handleTestEmail = async () => {
|
|
1265
|
+
const pathParts = window.location.pathname.split("/");
|
|
1266
|
+
const broadcastId = pathParts[pathParts.length - 1];
|
|
1267
|
+
if (!broadcastId || broadcastId === "create") {
|
|
1268
|
+
alert("Please save the broadcast before sending a test email");
|
|
2005
1269
|
return;
|
|
2006
1270
|
}
|
|
2007
|
-
setIsLoading(true);
|
|
2008
|
-
setError(null);
|
|
2009
1271
|
try {
|
|
2010
|
-
const response = await fetch(
|
|
1272
|
+
const response = await fetch(`/api/broadcasts/${broadcastId}/test`, {
|
|
2011
1273
|
method: "POST",
|
|
2012
1274
|
headers: {
|
|
2013
1275
|
"Content-Type": "application/json"
|
|
2014
|
-
}
|
|
2015
|
-
body: JSON.stringify({
|
|
2016
|
-
content: fields.content,
|
|
2017
|
-
preheader: fields.preheader,
|
|
2018
|
-
subject: fields.subject
|
|
2019
|
-
})
|
|
1276
|
+
}
|
|
2020
1277
|
});
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
throw new Error(data.error || "Failed to
|
|
1278
|
+
if (!response.ok) {
|
|
1279
|
+
const data = await response.json();
|
|
1280
|
+
throw new Error(data.error || "Failed to send test email");
|
|
2024
1281
|
}
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
setError(err);
|
|
2029
|
-
console.error("Failed to update preview:", err);
|
|
2030
|
-
} finally {
|
|
2031
|
-
setIsLoading(false);
|
|
1282
|
+
alert("Test email sent successfully! Check your inbox.");
|
|
1283
|
+
} catch (error) {
|
|
1284
|
+
alert(error instanceof Error ? error.message : "Failed to send test email");
|
|
2032
1285
|
}
|
|
2033
|
-
}
|
|
2034
|
-
|
|
1286
|
+
};
|
|
1287
|
+
return /* @__PURE__ */ jsxs5("div", { style: {
|
|
1288
|
+
marginTop: "24px",
|
|
2035
1289
|
border: "1px solid #e5e7eb",
|
|
2036
1290
|
borderRadius: "8px",
|
|
2037
|
-
overflow: "hidden",
|
|
2038
|
-
height: "100%",
|
|
2039
|
-
display: "flex",
|
|
2040
|
-
flexDirection: "column"
|
|
2041
|
-
};
|
|
2042
|
-
const headerStyle = {
|
|
2043
|
-
display: "flex",
|
|
2044
|
-
alignItems: "center",
|
|
2045
|
-
justifyContent: "space-between",
|
|
2046
|
-
padding: "1rem",
|
|
2047
|
-
background: "#f9fafb",
|
|
2048
|
-
borderBottom: "1px solid #e5e7eb"
|
|
2049
|
-
};
|
|
2050
|
-
const titleStyle = {
|
|
2051
|
-
fontSize: "16px",
|
|
2052
|
-
fontWeight: 600,
|
|
2053
|
-
color: "#1f2937",
|
|
2054
|
-
margin: 0
|
|
2055
|
-
};
|
|
2056
|
-
const previewContainerStyle = {
|
|
2057
|
-
flex: 1,
|
|
2058
|
-
display: "flex",
|
|
2059
|
-
flexDirection: "column",
|
|
2060
|
-
background: "#f3f4f6",
|
|
2061
1291
|
overflow: "hidden"
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
1292
|
+
}, children: [
|
|
1293
|
+
/* @__PURE__ */ jsxs5("div", { style: {
|
|
1294
|
+
display: "flex",
|
|
1295
|
+
alignItems: "center",
|
|
1296
|
+
justifyContent: "space-between",
|
|
1297
|
+
padding: "12px 16px",
|
|
1298
|
+
borderBottom: "1px solid #e5e7eb",
|
|
1299
|
+
backgroundColor: "#f9fafb"
|
|
1300
|
+
}, children: [
|
|
1301
|
+
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", alignItems: "center", gap: "16px" }, children: [
|
|
1302
|
+
/* @__PURE__ */ jsx7("h3", { style: { margin: 0, fontSize: "16px", fontWeight: 600 }, children: "Email Preview" }),
|
|
1303
|
+
/* @__PURE__ */ jsxs5("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
1304
|
+
/* @__PURE__ */ jsx7(
|
|
1305
|
+
"button",
|
|
1306
|
+
{
|
|
1307
|
+
type: "button",
|
|
1308
|
+
onClick: () => setPreviewMode("desktop"),
|
|
1309
|
+
style: {
|
|
1310
|
+
padding: "6px 12px",
|
|
1311
|
+
backgroundColor: previewMode === "desktop" ? "#6366f1" : "#e5e7eb",
|
|
1312
|
+
color: previewMode === "desktop" ? "white" : "#374151",
|
|
1313
|
+
border: "none",
|
|
1314
|
+
borderRadius: "4px 0 0 4px",
|
|
1315
|
+
fontSize: "14px",
|
|
1316
|
+
cursor: "pointer"
|
|
1317
|
+
},
|
|
1318
|
+
children: "Desktop"
|
|
1319
|
+
}
|
|
1320
|
+
),
|
|
1321
|
+
/* @__PURE__ */ jsx7(
|
|
1322
|
+
"button",
|
|
1323
|
+
{
|
|
1324
|
+
type: "button",
|
|
1325
|
+
onClick: () => setPreviewMode("mobile"),
|
|
1326
|
+
style: {
|
|
1327
|
+
padding: "6px 12px",
|
|
1328
|
+
backgroundColor: previewMode === "mobile" ? "#6366f1" : "#e5e7eb",
|
|
1329
|
+
color: previewMode === "mobile" ? "white" : "#374151",
|
|
1330
|
+
border: "none",
|
|
1331
|
+
borderRadius: "0 4px 4px 0",
|
|
1332
|
+
fontSize: "14px",
|
|
1333
|
+
cursor: "pointer"
|
|
1334
|
+
},
|
|
1335
|
+
children: "Mobile"
|
|
1336
|
+
}
|
|
1337
|
+
)
|
|
1338
|
+
] }),
|
|
1339
|
+
validationSummary && /* @__PURE__ */ jsx7("div", { style: {
|
|
1340
|
+
padding: "6px 12px",
|
|
1341
|
+
backgroundColor: isValid ? "#fef3c7" : "#fee2e2",
|
|
1342
|
+
color: isValid ? "#92400e" : "#991b1b",
|
|
1343
|
+
borderRadius: "4px",
|
|
1344
|
+
fontSize: "13px"
|
|
1345
|
+
}, children: validationSummary })
|
|
1346
|
+
] }),
|
|
1347
|
+
/* @__PURE__ */ jsx7(
|
|
2093
1348
|
"button",
|
|
2094
1349
|
{
|
|
2095
|
-
|
|
1350
|
+
type: "button",
|
|
1351
|
+
onClick: handleTestEmail,
|
|
2096
1352
|
style: {
|
|
2097
|
-
padding: "
|
|
2098
|
-
|
|
1353
|
+
padding: "6px 12px",
|
|
1354
|
+
backgroundColor: "#10b981",
|
|
2099
1355
|
color: "white",
|
|
2100
1356
|
border: "none",
|
|
2101
1357
|
borderRadius: "4px",
|
|
1358
|
+
fontSize: "14px",
|
|
2102
1359
|
cursor: "pointer"
|
|
2103
1360
|
},
|
|
2104
|
-
children: "
|
|
2105
|
-
}
|
|
2106
|
-
)
|
|
2107
|
-
] }) : previewHtml ? /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
2108
|
-
/* @__PURE__ */ jsx9(
|
|
2109
|
-
PreviewControls,
|
|
2110
|
-
{
|
|
2111
|
-
onUpdate: updatePreview,
|
|
2112
|
-
device,
|
|
2113
|
-
onDeviceChange: setDevice,
|
|
2114
|
-
isLoading
|
|
2115
|
-
}
|
|
2116
|
-
),
|
|
2117
|
-
/* @__PURE__ */ jsx9(
|
|
2118
|
-
"div",
|
|
2119
|
-
{
|
|
2120
|
-
style: {
|
|
2121
|
-
flex: 1,
|
|
2122
|
-
padding: device === "mobile" ? "1rem" : "2rem",
|
|
2123
|
-
display: "flex",
|
|
2124
|
-
justifyContent: "center",
|
|
2125
|
-
overflow: "auto"
|
|
2126
|
-
},
|
|
2127
|
-
children: /* @__PURE__ */ jsx9(
|
|
2128
|
-
"div",
|
|
2129
|
-
{
|
|
2130
|
-
style: {
|
|
2131
|
-
width: device === "mobile" ? "375px" : "600px",
|
|
2132
|
-
maxWidth: "100%",
|
|
2133
|
-
background: "white",
|
|
2134
|
-
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
2135
|
-
borderRadius: "8px",
|
|
2136
|
-
overflow: "hidden"
|
|
2137
|
-
},
|
|
2138
|
-
children: /* @__PURE__ */ jsx9(
|
|
2139
|
-
"iframe",
|
|
2140
|
-
{
|
|
2141
|
-
srcDoc: previewHtml,
|
|
2142
|
-
style: {
|
|
2143
|
-
width: "100%",
|
|
2144
|
-
height: "100%",
|
|
2145
|
-
minHeight: "600px",
|
|
2146
|
-
border: "none"
|
|
2147
|
-
},
|
|
2148
|
-
title: "Email Preview"
|
|
2149
|
-
}
|
|
2150
|
-
)
|
|
2151
|
-
}
|
|
2152
|
-
)
|
|
1361
|
+
children: "Send Test Email"
|
|
2153
1362
|
}
|
|
2154
1363
|
)
|
|
2155
|
-
] })
|
|
1364
|
+
] }),
|
|
1365
|
+
/* @__PURE__ */ jsx7("div", { style: { height: "600px" }, children: /* @__PURE__ */ jsx7(
|
|
1366
|
+
EmailPreview,
|
|
1367
|
+
{
|
|
1368
|
+
content: fields.content?.value || null,
|
|
1369
|
+
subject: fields.subject?.value || "Email Subject",
|
|
1370
|
+
preheader: fields.preheader?.value,
|
|
1371
|
+
mode: previewMode,
|
|
1372
|
+
onValidation: handleValidation,
|
|
1373
|
+
pluginConfig: pluginConfig || void 0
|
|
1374
|
+
}
|
|
1375
|
+
) })
|
|
2156
1376
|
] });
|
|
2157
1377
|
};
|
|
2158
1378
|
|
|
2159
1379
|
// src/components/Broadcasts/BroadcastPreviewField.tsx
|
|
2160
|
-
import { jsx as
|
|
1380
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
2161
1381
|
var BroadcastPreviewField = () => {
|
|
2162
|
-
return /* @__PURE__ */
|
|
1382
|
+
return /* @__PURE__ */ jsx8("div", { style: {
|
|
2163
1383
|
padding: "1rem",
|
|
2164
1384
|
background: "#f9fafb",
|
|
2165
1385
|
borderRadius: "4px",
|
|
@@ -2168,251 +1388,405 @@ var BroadcastPreviewField = () => {
|
|
|
2168
1388
|
}, children: "Email preview is available inline below the content editor." });
|
|
2169
1389
|
};
|
|
2170
1390
|
|
|
2171
|
-
// src/
|
|
2172
|
-
import {
|
|
2173
|
-
import {
|
|
2174
|
-
|
|
2175
|
-
var
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
}
|
|
2198
|
-
}, [template, data, onRender]);
|
|
2199
|
-
useEffect5(() => {
|
|
2200
|
-
renderEmail();
|
|
2201
|
-
}, [renderEmail]);
|
|
2202
|
-
useEffect5(() => {
|
|
2203
|
-
if (iframeRef.current && renderedHtml) {
|
|
2204
|
-
const iframe = iframeRef.current;
|
|
2205
|
-
const doc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
2206
|
-
if (doc) {
|
|
2207
|
-
doc.open();
|
|
2208
|
-
doc.write(renderedHtml);
|
|
2209
|
-
doc.close();
|
|
1391
|
+
// src/contexts/ClientContext.tsx
|
|
1392
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
1393
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
1394
|
+
var PluginConfigContext2 = createContext2(null);
|
|
1395
|
+
var PluginConfigProvider = ({ config, children }) => {
|
|
1396
|
+
return /* @__PURE__ */ jsx9(PluginConfigContext2.Provider, { value: config, children });
|
|
1397
|
+
};
|
|
1398
|
+
var usePluginConfig = () => {
|
|
1399
|
+
const context = useContext2(PluginConfigContext2);
|
|
1400
|
+
if (!context) {
|
|
1401
|
+
throw new Error("usePluginConfig must be used within a PluginConfigProvider");
|
|
1402
|
+
}
|
|
1403
|
+
return context;
|
|
1404
|
+
};
|
|
1405
|
+
var usePluginConfigOptional2 = () => {
|
|
1406
|
+
return useContext2(PluginConfigContext2);
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
// src/fields/broadcastInlinePreview.ts
|
|
1410
|
+
var createBroadcastInlinePreviewField = () => {
|
|
1411
|
+
return {
|
|
1412
|
+
name: "broadcastInlinePreview",
|
|
1413
|
+
type: "ui",
|
|
1414
|
+
admin: {
|
|
1415
|
+
components: {
|
|
1416
|
+
Field: "payload-plugin-newsletter/components#BroadcastInlinePreview"
|
|
2210
1417
|
}
|
|
2211
1418
|
}
|
|
2212
|
-
}, [renderedHtml]);
|
|
2213
|
-
const containerStyle = {
|
|
2214
|
-
width: "100%",
|
|
2215
|
-
height: "100%",
|
|
2216
|
-
display: "flex",
|
|
2217
|
-
alignItems: "flex-start",
|
|
2218
|
-
justifyContent: "center",
|
|
2219
|
-
overflow: "auto",
|
|
2220
|
-
padding: "2rem",
|
|
2221
|
-
boxSizing: "border-box"
|
|
2222
|
-
};
|
|
2223
|
-
const iframeStyle = {
|
|
2224
|
-
width: device === "mobile" ? "375px" : "600px",
|
|
2225
|
-
height: "100%",
|
|
2226
|
-
minHeight: "600px",
|
|
2227
|
-
background: "white",
|
|
2228
|
-
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
2229
|
-
borderRadius: device === "mobile" ? "20px" : "8px",
|
|
2230
|
-
border: "none",
|
|
2231
|
-
display: "block"
|
|
2232
|
-
};
|
|
2233
|
-
const errorStyle = {
|
|
2234
|
-
background: "white",
|
|
2235
|
-
border: "1px solid #ef4444",
|
|
2236
|
-
borderRadius: "4px",
|
|
2237
|
-
padding: "2rem",
|
|
2238
|
-
maxWidth: "500px"
|
|
2239
1419
|
};
|
|
2240
|
-
if (error) {
|
|
2241
|
-
return /* @__PURE__ */ jsxs9("div", { style: errorStyle, children: [
|
|
2242
|
-
/* @__PURE__ */ jsx11("h3", { style: { color: "#ef4444", margin: "0 0 1rem" }, children: "Template Render Error" }),
|
|
2243
|
-
/* @__PURE__ */ jsx11("pre", { style: {
|
|
2244
|
-
background: "#f9fafb",
|
|
2245
|
-
padding: "1rem",
|
|
2246
|
-
borderRadius: "4px",
|
|
2247
|
-
overflowX: "auto",
|
|
2248
|
-
fontSize: "12px",
|
|
2249
|
-
color: "#374151",
|
|
2250
|
-
margin: 0
|
|
2251
|
-
}, children: error.message })
|
|
2252
|
-
] });
|
|
2253
|
-
}
|
|
2254
|
-
return /* @__PURE__ */ jsx11("div", { style: containerStyle, children: /* @__PURE__ */ jsx11(
|
|
2255
|
-
"iframe",
|
|
2256
|
-
{
|
|
2257
|
-
ref: iframeRef,
|
|
2258
|
-
style: iframeStyle,
|
|
2259
|
-
sandbox: "allow-same-origin",
|
|
2260
|
-
title: "Email Preview"
|
|
2261
|
-
}
|
|
2262
|
-
) });
|
|
2263
1420
|
};
|
|
2264
1421
|
|
|
2265
|
-
// src/
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
},
|
|
2274
|
-
["scheduled" /* SCHEDULED */]: {
|
|
2275
|
-
label: "Scheduled",
|
|
2276
|
-
color: "#2563EB",
|
|
2277
|
-
// blue
|
|
2278
|
-
backgroundColor: "#DBEAFE"
|
|
2279
|
-
},
|
|
2280
|
-
["sending" /* SENDING */]: {
|
|
2281
|
-
label: "Sending",
|
|
2282
|
-
color: "#D97706",
|
|
2283
|
-
// yellow/orange
|
|
2284
|
-
backgroundColor: "#FEF3C7"
|
|
2285
|
-
},
|
|
2286
|
-
["sent" /* SENT */]: {
|
|
2287
|
-
label: "Sent",
|
|
2288
|
-
color: "#059669",
|
|
2289
|
-
// green
|
|
2290
|
-
backgroundColor: "#D1FAE5"
|
|
2291
|
-
},
|
|
2292
|
-
["failed" /* FAILED */]: {
|
|
2293
|
-
label: "Failed",
|
|
2294
|
-
color: "#DC2626",
|
|
2295
|
-
// red
|
|
2296
|
-
backgroundColor: "#FEE2E2"
|
|
2297
|
-
},
|
|
2298
|
-
["paused" /* PAUSED */]: {
|
|
2299
|
-
label: "Paused",
|
|
2300
|
-
color: "#9333EA",
|
|
2301
|
-
// purple
|
|
2302
|
-
backgroundColor: "#EDE9FE"
|
|
2303
|
-
},
|
|
2304
|
-
["canceled" /* CANCELED */]: {
|
|
2305
|
-
label: "Canceled",
|
|
2306
|
-
color: "#6B7280",
|
|
2307
|
-
// gray
|
|
2308
|
-
backgroundColor: "#F3F4F6"
|
|
2309
|
-
}
|
|
2310
|
-
};
|
|
2311
|
-
var StatusBadge = ({ cellData }) => {
|
|
2312
|
-
const status = cellData;
|
|
2313
|
-
const config = statusConfig[status] || statusConfig["draft" /* DRAFT */];
|
|
2314
|
-
return /* @__PURE__ */ jsx12(
|
|
2315
|
-
"span",
|
|
2316
|
-
{
|
|
2317
|
-
style: {
|
|
2318
|
-
display: "inline-flex",
|
|
2319
|
-
alignItems: "center",
|
|
2320
|
-
padding: "2px 10px",
|
|
2321
|
-
borderRadius: "12px",
|
|
2322
|
-
fontSize: "12px",
|
|
2323
|
-
fontWeight: "500",
|
|
2324
|
-
color: config.color,
|
|
2325
|
-
backgroundColor: config.backgroundColor
|
|
1422
|
+
// src/fields/broadcastPreview.ts
|
|
1423
|
+
var createBroadcastPreviewField = () => {
|
|
1424
|
+
return {
|
|
1425
|
+
name: "broadcastPreview",
|
|
1426
|
+
type: "ui",
|
|
1427
|
+
admin: {
|
|
1428
|
+
components: {
|
|
1429
|
+
Field: "payload-plugin-newsletter/components#BroadcastPreviewField"
|
|
2326
1430
|
},
|
|
2327
|
-
|
|
1431
|
+
position: "sidebar"
|
|
2328
1432
|
}
|
|
2329
|
-
|
|
2330
|
-
};
|
|
2331
|
-
|
|
2332
|
-
// src/components/Broadcasts/EmptyField.tsx
|
|
2333
|
-
var EmptyField = () => {
|
|
2334
|
-
return null;
|
|
1433
|
+
};
|
|
2335
1434
|
};
|
|
2336
1435
|
|
|
2337
|
-
// src/
|
|
1436
|
+
// src/fields/emailContent.ts
|
|
2338
1437
|
import {
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
1438
|
+
BoldFeature,
|
|
1439
|
+
ItalicFeature,
|
|
1440
|
+
UnderlineFeature,
|
|
1441
|
+
StrikethroughFeature,
|
|
1442
|
+
LinkFeature,
|
|
1443
|
+
OrderedListFeature,
|
|
1444
|
+
UnorderedListFeature,
|
|
1445
|
+
HeadingFeature,
|
|
1446
|
+
ParagraphFeature,
|
|
1447
|
+
AlignFeature,
|
|
1448
|
+
BlockquoteFeature,
|
|
1449
|
+
BlocksFeature,
|
|
1450
|
+
UploadFeature,
|
|
1451
|
+
FixedToolbarFeature,
|
|
1452
|
+
InlineToolbarFeature,
|
|
1453
|
+
lexicalEditor
|
|
1454
|
+
} from "@payloadcms/richtext-lexical";
|
|
1455
|
+
|
|
1456
|
+
// src/utils/blockValidation.ts
|
|
1457
|
+
var EMAIL_INCOMPATIBLE_TYPES = [
|
|
1458
|
+
"chart",
|
|
1459
|
+
"dataTable",
|
|
1460
|
+
"interactive",
|
|
1461
|
+
"streamable",
|
|
1462
|
+
"video",
|
|
1463
|
+
"iframe",
|
|
1464
|
+
"form",
|
|
1465
|
+
"carousel",
|
|
1466
|
+
"tabs",
|
|
1467
|
+
"accordion",
|
|
1468
|
+
"map"
|
|
1469
|
+
];
|
|
1470
|
+
var validateEmailBlocks = (blocks) => {
|
|
1471
|
+
blocks.forEach((block) => {
|
|
1472
|
+
if (EMAIL_INCOMPATIBLE_TYPES.includes(block.slug)) {
|
|
1473
|
+
console.warn(`\u26A0\uFE0F Block "${block.slug}" may not be email-compatible. Consider creating an email-specific version.`);
|
|
1474
|
+
}
|
|
1475
|
+
const hasComplexFields = block.fields?.some((field) => {
|
|
1476
|
+
const complexTypes = ["code", "json", "richText", "blocks", "array"];
|
|
1477
|
+
return complexTypes.includes(field.type);
|
|
1478
|
+
});
|
|
1479
|
+
if (hasComplexFields) {
|
|
1480
|
+
console.warn(`\u26A0\uFE0F Block "${block.slug}" contains complex field types that may not render consistently in email clients.`);
|
|
1481
|
+
}
|
|
1482
|
+
});
|
|
2381
1483
|
};
|
|
2382
|
-
var
|
|
2383
|
-
|
|
2384
|
-
|
|
1484
|
+
var createEmailSafeBlocks = (customBlocks = []) => {
|
|
1485
|
+
validateEmailBlocks(customBlocks);
|
|
1486
|
+
const baseBlocks = [
|
|
1487
|
+
{
|
|
1488
|
+
slug: "button",
|
|
1489
|
+
fields: [
|
|
1490
|
+
{
|
|
1491
|
+
name: "text",
|
|
1492
|
+
type: "text",
|
|
1493
|
+
label: "Button Text",
|
|
1494
|
+
required: true
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
name: "url",
|
|
1498
|
+
type: "text",
|
|
1499
|
+
label: "Button URL",
|
|
1500
|
+
required: true,
|
|
1501
|
+
admin: {
|
|
1502
|
+
description: "Enter the full URL (including https://)"
|
|
1503
|
+
}
|
|
1504
|
+
},
|
|
1505
|
+
{
|
|
1506
|
+
name: "style",
|
|
1507
|
+
type: "select",
|
|
1508
|
+
label: "Button Style",
|
|
1509
|
+
defaultValue: "primary",
|
|
1510
|
+
options: [
|
|
1511
|
+
{ label: "Primary", value: "primary" },
|
|
1512
|
+
{ label: "Secondary", value: "secondary" },
|
|
1513
|
+
{ label: "Outline", value: "outline" }
|
|
1514
|
+
]
|
|
1515
|
+
}
|
|
1516
|
+
],
|
|
1517
|
+
interfaceName: "EmailButton",
|
|
1518
|
+
labels: {
|
|
1519
|
+
singular: "Button",
|
|
1520
|
+
plural: "Buttons"
|
|
1521
|
+
}
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
slug: "divider",
|
|
1525
|
+
fields: [
|
|
1526
|
+
{
|
|
1527
|
+
name: "style",
|
|
1528
|
+
type: "select",
|
|
1529
|
+
label: "Divider Style",
|
|
1530
|
+
defaultValue: "solid",
|
|
1531
|
+
options: [
|
|
1532
|
+
{ label: "Solid", value: "solid" },
|
|
1533
|
+
{ label: "Dashed", value: "dashed" },
|
|
1534
|
+
{ label: "Dotted", value: "dotted" }
|
|
1535
|
+
]
|
|
1536
|
+
}
|
|
1537
|
+
],
|
|
1538
|
+
interfaceName: "EmailDivider",
|
|
1539
|
+
labels: {
|
|
1540
|
+
singular: "Divider",
|
|
1541
|
+
plural: "Dividers"
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
];
|
|
1545
|
+
return [
|
|
1546
|
+
...baseBlocks,
|
|
1547
|
+
...customBlocks
|
|
1548
|
+
];
|
|
2385
1549
|
};
|
|
2386
|
-
|
|
2387
|
-
|
|
1550
|
+
|
|
1551
|
+
// src/fields/emailContent.ts
|
|
1552
|
+
var createEmailSafeFeatures = (additionalBlocks) => {
|
|
1553
|
+
const baseBlocks = [
|
|
1554
|
+
{
|
|
1555
|
+
slug: "button",
|
|
1556
|
+
fields: [
|
|
1557
|
+
{
|
|
1558
|
+
name: "text",
|
|
1559
|
+
type: "text",
|
|
1560
|
+
label: "Button Text",
|
|
1561
|
+
required: true
|
|
1562
|
+
},
|
|
1563
|
+
{
|
|
1564
|
+
name: "url",
|
|
1565
|
+
type: "text",
|
|
1566
|
+
label: "Button URL",
|
|
1567
|
+
required: true,
|
|
1568
|
+
admin: {
|
|
1569
|
+
description: "Enter the full URL (including https://)"
|
|
1570
|
+
}
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
name: "style",
|
|
1574
|
+
type: "select",
|
|
1575
|
+
label: "Button Style",
|
|
1576
|
+
defaultValue: "primary",
|
|
1577
|
+
options: [
|
|
1578
|
+
{ label: "Primary", value: "primary" },
|
|
1579
|
+
{ label: "Secondary", value: "secondary" },
|
|
1580
|
+
{ label: "Outline", value: "outline" }
|
|
1581
|
+
]
|
|
1582
|
+
}
|
|
1583
|
+
],
|
|
1584
|
+
interfaceName: "EmailButton",
|
|
1585
|
+
labels: {
|
|
1586
|
+
singular: "Button",
|
|
1587
|
+
plural: "Buttons"
|
|
1588
|
+
}
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
slug: "divider",
|
|
1592
|
+
fields: [
|
|
1593
|
+
{
|
|
1594
|
+
name: "style",
|
|
1595
|
+
type: "select",
|
|
1596
|
+
label: "Divider Style",
|
|
1597
|
+
defaultValue: "solid",
|
|
1598
|
+
options: [
|
|
1599
|
+
{ label: "Solid", value: "solid" },
|
|
1600
|
+
{ label: "Dashed", value: "dashed" },
|
|
1601
|
+
{ label: "Dotted", value: "dotted" }
|
|
1602
|
+
]
|
|
1603
|
+
}
|
|
1604
|
+
],
|
|
1605
|
+
interfaceName: "EmailDivider",
|
|
1606
|
+
labels: {
|
|
1607
|
+
singular: "Divider",
|
|
1608
|
+
plural: "Dividers"
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
];
|
|
1612
|
+
const allBlocks = [
|
|
1613
|
+
...baseBlocks,
|
|
1614
|
+
...additionalBlocks || []
|
|
1615
|
+
];
|
|
1616
|
+
return [
|
|
1617
|
+
// Toolbars
|
|
1618
|
+
FixedToolbarFeature(),
|
|
1619
|
+
// Fixed toolbar at the top
|
|
1620
|
+
InlineToolbarFeature(),
|
|
1621
|
+
// Floating toolbar when text is selected
|
|
1622
|
+
// Basic text formatting
|
|
1623
|
+
BoldFeature(),
|
|
1624
|
+
ItalicFeature(),
|
|
1625
|
+
UnderlineFeature(),
|
|
1626
|
+
StrikethroughFeature(),
|
|
1627
|
+
// Links with enhanced configuration
|
|
1628
|
+
LinkFeature({
|
|
1629
|
+
fields: [
|
|
1630
|
+
{
|
|
1631
|
+
name: "url",
|
|
1632
|
+
type: "text",
|
|
1633
|
+
required: true,
|
|
1634
|
+
admin: {
|
|
1635
|
+
description: "Enter the full URL (including https://)"
|
|
1636
|
+
}
|
|
1637
|
+
},
|
|
1638
|
+
{
|
|
1639
|
+
name: "newTab",
|
|
1640
|
+
type: "checkbox",
|
|
1641
|
+
label: "Open in new tab",
|
|
1642
|
+
defaultValue: false
|
|
1643
|
+
}
|
|
1644
|
+
]
|
|
1645
|
+
}),
|
|
1646
|
+
// Lists
|
|
1647
|
+
OrderedListFeature(),
|
|
1648
|
+
UnorderedListFeature(),
|
|
1649
|
+
// Headings - limited to h1, h2, h3 for email compatibility
|
|
1650
|
+
HeadingFeature({
|
|
1651
|
+
enabledHeadingSizes: ["h1", "h2", "h3"]
|
|
1652
|
+
}),
|
|
1653
|
+
// Basic paragraph and alignment
|
|
1654
|
+
ParagraphFeature(),
|
|
1655
|
+
AlignFeature(),
|
|
1656
|
+
// Blockquotes
|
|
1657
|
+
BlockquoteFeature(),
|
|
1658
|
+
// Upload feature for images
|
|
1659
|
+
UploadFeature({
|
|
1660
|
+
collections: {
|
|
1661
|
+
media: {
|
|
1662
|
+
fields: [
|
|
1663
|
+
{
|
|
1664
|
+
name: "caption",
|
|
1665
|
+
type: "text",
|
|
1666
|
+
admin: {
|
|
1667
|
+
description: "Optional caption for the image"
|
|
1668
|
+
}
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
name: "altText",
|
|
1672
|
+
type: "text",
|
|
1673
|
+
label: "Alt Text",
|
|
1674
|
+
required: true,
|
|
1675
|
+
admin: {
|
|
1676
|
+
description: "Alternative text for accessibility and when image cannot be displayed"
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
]
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
}),
|
|
1683
|
+
// Custom blocks for email-specific content
|
|
1684
|
+
BlocksFeature({
|
|
1685
|
+
blocks: allBlocks
|
|
1686
|
+
})
|
|
1687
|
+
];
|
|
2388
1688
|
};
|
|
2389
|
-
var
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
1689
|
+
var createEmailLexicalEditor = (customBlocks = []) => {
|
|
1690
|
+
const emailSafeBlocks = createEmailSafeBlocks(customBlocks);
|
|
1691
|
+
return lexicalEditor({
|
|
1692
|
+
features: [
|
|
1693
|
+
// Toolbars
|
|
1694
|
+
FixedToolbarFeature(),
|
|
1695
|
+
InlineToolbarFeature(),
|
|
1696
|
+
// Basic text formatting
|
|
1697
|
+
BoldFeature(),
|
|
1698
|
+
ItalicFeature(),
|
|
1699
|
+
UnderlineFeature(),
|
|
1700
|
+
StrikethroughFeature(),
|
|
1701
|
+
// Links with enhanced configuration
|
|
1702
|
+
LinkFeature({
|
|
1703
|
+
fields: [
|
|
1704
|
+
{
|
|
1705
|
+
name: "url",
|
|
1706
|
+
type: "text",
|
|
1707
|
+
required: true,
|
|
1708
|
+
admin: {
|
|
1709
|
+
description: "Enter the full URL (including https://)"
|
|
1710
|
+
}
|
|
1711
|
+
},
|
|
1712
|
+
{
|
|
1713
|
+
name: "newTab",
|
|
1714
|
+
type: "checkbox",
|
|
1715
|
+
label: "Open in new tab",
|
|
1716
|
+
defaultValue: false
|
|
1717
|
+
}
|
|
1718
|
+
]
|
|
1719
|
+
}),
|
|
1720
|
+
// Lists
|
|
1721
|
+
OrderedListFeature(),
|
|
1722
|
+
UnorderedListFeature(),
|
|
1723
|
+
// Headings - limited to h1, h2, h3 for email compatibility
|
|
1724
|
+
HeadingFeature({
|
|
1725
|
+
enabledHeadingSizes: ["h1", "h2", "h3"]
|
|
1726
|
+
}),
|
|
1727
|
+
// Basic paragraph and alignment
|
|
1728
|
+
ParagraphFeature(),
|
|
1729
|
+
AlignFeature(),
|
|
1730
|
+
// Blockquotes
|
|
1731
|
+
BlockquoteFeature(),
|
|
1732
|
+
// Upload feature for images
|
|
1733
|
+
UploadFeature({
|
|
1734
|
+
collections: {
|
|
1735
|
+
media: {
|
|
1736
|
+
fields: [
|
|
1737
|
+
{
|
|
1738
|
+
name: "caption",
|
|
1739
|
+
type: "text",
|
|
1740
|
+
admin: {
|
|
1741
|
+
description: "Optional caption for the image"
|
|
1742
|
+
}
|
|
1743
|
+
},
|
|
1744
|
+
{
|
|
1745
|
+
name: "altText",
|
|
1746
|
+
type: "text",
|
|
1747
|
+
label: "Alt Text",
|
|
1748
|
+
required: true,
|
|
1749
|
+
admin: {
|
|
1750
|
+
description: "Alternative text for accessibility and when image cannot be displayed"
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
]
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
}),
|
|
1757
|
+
// Email-safe blocks (processed server-side)
|
|
1758
|
+
BlocksFeature({
|
|
1759
|
+
blocks: emailSafeBlocks
|
|
1760
|
+
})
|
|
1761
|
+
]
|
|
1762
|
+
});
|
|
2394
1763
|
};
|
|
2395
|
-
var
|
|
2396
|
-
|
|
2397
|
-
|
|
1764
|
+
var emailSafeFeatures = createEmailSafeFeatures();
|
|
1765
|
+
var createEmailContentField = (overrides) => {
|
|
1766
|
+
const editor = overrides?.editor || createEmailLexicalEditor(overrides?.additionalBlocks);
|
|
1767
|
+
return {
|
|
1768
|
+
name: "content",
|
|
1769
|
+
type: "richText",
|
|
1770
|
+
required: true,
|
|
1771
|
+
editor,
|
|
1772
|
+
admin: {
|
|
1773
|
+
description: "Email content with limited formatting for compatibility",
|
|
1774
|
+
...overrides?.admin
|
|
1775
|
+
},
|
|
1776
|
+
...overrides
|
|
1777
|
+
};
|
|
2398
1778
|
};
|
|
2399
1779
|
export {
|
|
2400
1780
|
BroadcastEditor,
|
|
2401
1781
|
BroadcastInlinePreview,
|
|
2402
1782
|
BroadcastPreviewField,
|
|
2403
|
-
DefaultBroadcastTemplate,
|
|
2404
1783
|
EmailPreview,
|
|
2405
1784
|
EmailPreviewField,
|
|
2406
|
-
|
|
2407
|
-
EmptyField,
|
|
2408
|
-
MagicLinkVerify,
|
|
2409
|
-
NewsletterForm,
|
|
2410
|
-
PreferencesForm,
|
|
2411
|
-
PreviewControls,
|
|
1785
|
+
PluginConfigProvider,
|
|
2412
1786
|
StatusBadge,
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
1787
|
+
createBroadcastInlinePreviewField,
|
|
1788
|
+
createBroadcastPreviewField,
|
|
1789
|
+
createEmailContentField,
|
|
1790
|
+
usePluginConfig,
|
|
1791
|
+
usePluginConfigOptional2 as usePluginConfigOptional
|
|
2417
1792
|
};
|
|
2418
|
-
//# sourceMappingURL=components.js.map
|