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.
@@ -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/NewsletterForm.tsx
4
- import { useState } from "react";
8
+ // src/components/Broadcasts/PreviewControls.tsx
5
9
  import { jsx, jsxs } from "react/jsx-runtime";
6
- var defaultStyles = {
7
- form: {
10
+ var PreviewControls = ({
11
+ onUpdate,
12
+ device,
13
+ onDeviceChange,
14
+ isLoading = false
15
+ }) => {
16
+ const controlsStyle = {
8
17
  display: "flex",
9
- flexDirection: "column",
10
- gap: "1rem",
11
- maxWidth: "400px",
12
- margin: "0 auto"
13
- },
14
- inputGroup: {
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
- label: {
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
- checkboxInput: {
63
- width: "1rem",
64
- height: "1rem"
65
- },
66
- checkboxLabel: {
67
- fontSize: "0.875rem",
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
- const [loading, setLoading] = useState(false);
101
- const [error, setError] = useState(null);
102
- const [success, setSuccess] = useState(false);
103
- const styles = {
104
- form: { ...defaultStyles.form, ...customStyles.form },
105
- inputGroup: { ...defaultStyles.inputGroup, ...customStyles.inputGroup },
106
- label: { ...defaultStyles.label, ...customStyles.label },
107
- input: { ...defaultStyles.input, ...customStyles.input },
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
- } finally {
157
- setLoading(false);
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
- id: "email",
170
- type: "email",
171
- value: email,
172
- onChange: (e) => setEmail(e.target.value),
173
- placeholder: placeholders.email,
174
- required: true,
175
- disabled: loading,
176
- style: {
177
- ...styles.input,
178
- ...loading && { opacity: 0.5 }
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
- showName && /* @__PURE__ */ jsxs("div", { style: styles.inputGroup, children: [
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
- id: "name",
189
- type: "text",
190
- value: name,
191
- onChange: (e) => setName(e.target.value),
192
- placeholder: placeholders.name,
193
- disabled: loading,
194
- style: {
195
- ...styles.input,
196
- ...loading && { opacity: 0.5 }
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/PreferencesForm.tsx
253
- import { useState as useState2, useEffect } from "react";
254
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
255
- var defaultStyles2 = {
256
- container: {
257
- maxWidth: "600px",
258
- margin: "0 auto",
259
- padding: "2rem"
260
- },
261
- heading: {
262
- fontSize: "1.5rem",
263
- fontWeight: "600",
264
- marginBottom: "1.5rem",
265
- color: "#111827"
266
- },
267
- form: {
268
- display: "flex",
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(apiEndpoint, {
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
- name: subscriber.name,
459
- locale: subscriber.locale,
460
- emailPreferences: subscriber.emailPreferences
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 save preferences");
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
- const errorMessage = err instanceof Error ? err.message : "An error occurred";
474
- setError(errorMessage);
475
- if (onError) {
476
- onError(new Error(errorMessage));
477
- }
136
+ setError(err);
137
+ console.error("Failed to update preview:", err);
478
138
  } finally {
479
- setLoading(false);
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 handleUnsubscribe = async () => {
483
- if (!window.confirm(labels.unsubscribeConfirm)) {
484
- return;
485
- }
486
- setLoading(true);
487
- setError(null);
488
- try {
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
- if (loadingData) {
516
- return /* @__PURE__ */ jsx2("div", { className, style: styles.container, children: /* @__PURE__ */ jsx2("p", { style: styles.info, children: "Loading preferences..." }) });
517
- }
518
- if (subscriber.subscriptionStatus === "unsubscribed") {
519
- return /* @__PURE__ */ jsxs2("div", { className, style: styles.container, children: [
520
- /* @__PURE__ */ jsx2("h2", { style: styles.heading, children: "Unsubscribed" }),
521
- /* @__PURE__ */ jsx2("p", { style: styles.info, children: "You have been unsubscribed from all emails. To resubscribe, please sign up again." })
522
- ] });
523
- }
524
- return /* @__PURE__ */ jsxs2("div", { className, style: styles.container, children: [
525
- /* @__PURE__ */ jsx2("h2", { style: styles.heading, children: labels.title }),
526
- /* @__PURE__ */ jsxs2("form", { onSubmit: handleSave, style: styles.form, children: [
527
- /* @__PURE__ */ jsxs2("div", { style: styles.section, children: [
528
- /* @__PURE__ */ jsx2("h3", { style: styles.sectionTitle, children: labels.personalInfo }),
529
- /* @__PURE__ */ jsxs2("div", { style: styles.inputGroup, children: [
530
- /* @__PURE__ */ jsx2("label", { htmlFor: "name", style: styles.label, children: labels.name }),
531
- /* @__PURE__ */ jsx2(
532
- "input",
533
- {
534
- id: "name",
535
- type: "text",
536
- value: subscriber.name || "",
537
- onChange: (e) => setSubscriber({ ...subscriber, name: e.target.value }),
538
- disabled: loading,
539
- style: styles.input
540
- }
541
- )
542
- ] }),
543
- locales.length > 1 && /* @__PURE__ */ jsxs2("div", { style: styles.inputGroup, children: [
544
- /* @__PURE__ */ jsx2("label", { htmlFor: "locale", style: styles.label, children: labels.language }),
545
- /* @__PURE__ */ jsx2(
546
- "select",
547
- {
548
- id: "locale",
549
- value: subscriber.locale || locales[0],
550
- onChange: (e) => setSubscriber({ ...subscriber, locale: e.target.value }),
551
- disabled: loading,
552
- style: styles.select,
553
- children: locales.map((locale) => /* @__PURE__ */ jsx2("option", { value: locale, children: locale.toUpperCase() }, locale))
554
- }
555
- )
556
- ] })
557
- ] }),
558
- /* @__PURE__ */ jsxs2("div", { style: styles.section, children: [
559
- /* @__PURE__ */ jsx2("h3", { style: styles.sectionTitle, children: labels.emailPreferences }),
560
- /* @__PURE__ */ jsxs2("div", { style: styles.checkbox, children: [
561
- /* @__PURE__ */ jsx2(
562
- "input",
563
- {
564
- id: "pref-newsletter",
565
- type: "checkbox",
566
- checked: subscriber.emailPreferences?.newsletter ?? true,
567
- onChange: (e) => setSubscriber({
568
- ...subscriber,
569
- emailPreferences: {
570
- ...subscriber.emailPreferences,
571
- newsletter: e.target.checked
572
- }
573
- }),
574
- disabled: loading,
575
- style: styles.checkboxInput
576
- }
577
- ),
578
- /* @__PURE__ */ jsx2("label", { htmlFor: "pref-newsletter", style: styles.checkboxLabel, children: labels.newsletter })
579
- ] }),
580
- /* @__PURE__ */ jsxs2("div", { style: styles.checkbox, children: [
581
- /* @__PURE__ */ jsx2(
582
- "input",
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
- id: "pref-announcements",
585
- type: "checkbox",
586
- checked: subscriber.emailPreferences?.announcements ?? true,
587
- onChange: (e) => setSubscriber({
588
- ...subscriber,
589
- emailPreferences: {
590
- ...subscriber.emailPreferences,
591
- announcements: e.target.checked
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
- /* @__PURE__ */ jsx2("label", { htmlFor: "pref-announcements", style: styles.checkboxLabel, children: labels.announcements })
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/MagicLinkVerify.tsx
640
- import { useState as useState3, useEffect as useEffect2 } from "react";
641
- import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
642
- var defaultStyles3 = {
643
- container: {
644
- maxWidth: "400px",
645
- margin: "4rem auto",
646
- padding: "2rem",
647
- textAlign: "center"
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
- heading: {
650
- fontSize: "1.5rem",
651
- fontWeight: "600",
652
- marginBottom: "1rem",
653
- color: "#111827"
288
+ ["sent" /* SENT */]: {
289
+ label: "Sent",
290
+ color: "#059669",
291
+ // green
292
+ backgroundColor: "#D1FAE5"
654
293
  },
655
- message: {
656
- fontSize: "1rem",
657
- color: "#6b7280",
658
- marginBottom: "1.5rem"
294
+ ["failed" /* FAILED */]: {
295
+ label: "Failed",
296
+ color: "#DC2626",
297
+ // red
298
+ backgroundColor: "#FEE2E2"
659
299
  },
660
- error: {
661
- fontSize: "1rem",
662
- color: "#ef4444",
663
- marginBottom: "1.5rem"
300
+ ["paused" /* PAUSED */]: {
301
+ label: "Paused",
302
+ color: "#9333EA",
303
+ // purple
304
+ backgroundColor: "#EDE9FE"
664
305
  },
665
- button: {
666
- padding: "0.75rem 1.5rem",
667
- fontSize: "1rem",
668
- fontWeight: "500",
669
- color: "#ffffff",
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 MagicLinkVerify = ({
678
- token: propToken,
679
- onSuccess,
680
- onError,
681
- apiEndpoint = "/api/newsletter/verify-magic-link",
682
- className,
683
- styles: customStyles = {},
684
- labels = {
685
- verifying: "Verifying your magic link...",
686
- success: "Successfully verified! Redirecting...",
687
- error: "Failed to verify magic link",
688
- expired: "This magic link has expired. Please request a new one.",
689
- invalid: "This magic link is invalid. Please request a new one.",
690
- redirecting: "Redirecting to your preferences...",
691
- tryAgain: "Try Again"
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 useState5, useEffect as useEffect4, useRef } from "react";
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 jsxs4 } from "react/jsx-runtime";
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] = useState5("");
1455
- const [loading, setLoading] = useState5(false);
1456
- const [validationResult, setValidationResult] = useState5(null);
937
+ const [html, setHtml] = useState2("");
938
+ const [loading, setLoading] = useState2(false);
939
+ const [validationResult, setValidationResult] = useState2(null);
1457
940
  const iframeRef = useRef(null);
1458
- useEffect4(() => {
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
- useEffect4(() => {
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__ */ jsxs4("div", { style: { height: "100%", display: "flex", flexDirection: "column" }, children: [
1505
- validationResult && (validationResult.errors.length > 0 || validationResult.warnings.length > 0) && /* @__PURE__ */ jsxs4("div", { style: { padding: "16px", borderBottom: "1px solid #e5e7eb" }, children: [
1506
- validationResult.errors.length > 0 && /* @__PURE__ */ jsxs4("div", { style: { marginBottom: "12px" }, children: [
1507
- /* @__PURE__ */ jsxs4("h4", { style: { color: "#dc2626", margin: "0 0 8px 0", fontSize: "14px" }, children: [
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__ */ jsxs4("div", { children: [
1515
- /* @__PURE__ */ jsxs4("h4", { style: { color: "#d97706", margin: "0 0 8px 0", fontSize: "14px" }, children: [
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__ */ jsxs4("div", { style: {
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__ */ jsxs4("span", { children: [
1043
+ /* @__PURE__ */ jsxs3("span", { children: [
1561
1044
  "Size: ",
1562
1045
  Math.round(validationResult.stats.sizeInBytes / 1024),
1563
1046
  "KB"
1564
1047
  ] }),
1565
- /* @__PURE__ */ jsxs4("span", { children: [
1048
+ /* @__PURE__ */ jsxs3("span", { children: [
1566
1049
  "Links: ",
1567
1050
  validationResult.stats.linkCount
1568
1051
  ] }),
1569
- /* @__PURE__ */ jsxs4("span", { children: [
1052
+ /* @__PURE__ */ jsxs3("span", { children: [
1570
1053
  "Images: ",
1571
1054
  validationResult.stats.imageCount
1572
1055
  ] }),
1573
- /* @__PURE__ */ jsxs4("span", { children: [
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 useState7, useCallback as useCallback2 } from "react";
1080
+ import { useState as useState3, useCallback as useCallback2 } from "react";
1740
1081
  import { useField, useFormFields as useFormFields2 } from "@payloadcms/ui";
1741
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
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] = useState7(true);
1745
- const [previewMode, setPreviewMode] = useState7("desktop");
1746
- const [isValid, setIsValid] = useState7(true);
1747
- const [validationSummary, setValidationSummary] = useState7("");
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__ */ jsxs6("div", { style: { height: "600px", display: "flex", flexDirection: "column" }, children: [
1788
- /* @__PURE__ */ jsxs6("div", { style: {
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__ */ jsxs6("div", { style: { display: "flex", alignItems: "center", gap: "16px" }, children: [
1797
- /* @__PURE__ */ jsx7(
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__ */ jsxs6("div", { style: { display: "flex", gap: "8px" }, children: [
1815
- /* @__PURE__ */ jsx7(
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__ */ jsx7(
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__ */ jsx7("div", { style: {
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__ */ jsx7(
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__ */ jsxs6("div", { style: { flex: 1, display: "flex", overflow: "hidden" }, children: [
1877
- /* @__PURE__ */ jsx7("div", { style: {
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__ */ jsx7("div", { style: { padding: "16px" }, children: /* @__PURE__ */ jsx7("div", { className: "rich-text-lexical" }) }) }),
1882
- showPreview && /* @__PURE__ */ jsx7("div", { style: { flex: "0 0 50%", overflow: "hidden" }, children: /* @__PURE__ */ jsx7(
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/BroadcastInlinePreview.tsx
1897
- import { useState as useState8, useCallback as useCallback3 } from "react";
1237
+ // src/components/Broadcasts/EmailPreviewField.tsx
1238
+ import { useState as useState4 } from "react";
1898
1239
  import { useFormFields as useFormFields3 } from "@payloadcms/ui";
1899
-
1900
- // src/components/Broadcasts/PreviewControls.tsx
1901
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1902
- var PreviewControls = ({
1903
- onUpdate,
1904
- device,
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
- subject: fields2["subject"]?.value,
1999
- preheader: fields2["contentSection.preheader"]?.value,
2000
- content: fields2["contentSection.content"]?.value
1247
+ content: fields2["contentSection.content"],
1248
+ subject: fields2["subject"],
1249
+ preheader: fields2["contentSection.preheader"],
1250
+ channel: fields2.channel
2001
1251
  }));
2002
- const updatePreview = useCallback3(async () => {
2003
- if (!fields.content) {
2004
- setError(new Error("Please add some content before previewing"));
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("/api/broadcasts/preview", {
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
- const data = await response.json();
2022
- if (!response.ok || !data.success) {
2023
- throw new Error(data.error || "Failed to generate preview");
1278
+ if (!response.ok) {
1279
+ const data = await response.json();
1280
+ throw new Error(data.error || "Failed to send test email");
2024
1281
  }
2025
- setPreviewHtml(data.preview.html);
2026
- setShowPreview(true);
2027
- } catch (err) {
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
- }, [fields]);
2034
- const containerStyle = {
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
- const errorStyle = {
2064
- padding: "2rem",
2065
- textAlign: "center"
2066
- };
2067
- const toggleButtonStyle = {
2068
- padding: "0.5rem 1rem",
2069
- background: showPreview ? "#ef4444" : "#3b82f6",
2070
- color: "white",
2071
- border: "none",
2072
- borderRadius: "4px",
2073
- cursor: "pointer",
2074
- fontSize: "14px",
2075
- fontWeight: 500
2076
- };
2077
- return /* @__PURE__ */ jsxs8("div", { style: containerStyle, children: [
2078
- /* @__PURE__ */ jsxs8("div", { style: headerStyle, children: [
2079
- /* @__PURE__ */ jsx9("h3", { style: titleStyle, children: "Email Preview" }),
2080
- /* @__PURE__ */ jsx9(
2081
- "button",
2082
- {
2083
- onClick: () => showPreview ? setShowPreview(false) : updatePreview(),
2084
- style: toggleButtonStyle,
2085
- disabled: isLoading,
2086
- children: isLoading ? "Loading..." : showPreview ? "Hide Preview" : "Show Preview"
2087
- }
2088
- )
2089
- ] }),
2090
- showPreview && /* @__PURE__ */ jsx9("div", { style: previewContainerStyle, children: error ? /* @__PURE__ */ jsxs8("div", { style: errorStyle, children: [
2091
- /* @__PURE__ */ jsx9("p", { style: { color: "#ef4444", margin: "0 0 1rem" }, children: error.message }),
2092
- /* @__PURE__ */ jsx9(
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
- onClick: updatePreview,
1350
+ type: "button",
1351
+ onClick: handleTestEmail,
2096
1352
  style: {
2097
- padding: "0.5rem 1rem",
2098
- background: "#3b82f6",
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: "Retry"
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
- ] }) : null })
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 jsx10 } from "react/jsx-runtime";
1380
+ import { jsx as jsx8 } from "react/jsx-runtime";
2161
1381
  var BroadcastPreviewField = () => {
2162
- return /* @__PURE__ */ jsx10("div", { style: {
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/components/Broadcasts/EmailRenderer.tsx
2172
- import { useEffect as useEffect5, useState as useState9, useCallback as useCallback4, useRef as useRef2 } from "react";
2173
- import { render } from "@react-email/render";
2174
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2175
- var EmailRenderer = ({
2176
- template,
2177
- data,
2178
- device = "desktop",
2179
- onRender
2180
- }) => {
2181
- const [renderedHtml, setRenderedHtml] = useState9("");
2182
- const [error, setError] = useState9(null);
2183
- const iframeRef = useRef2(null);
2184
- const renderEmail = useCallback4(async () => {
2185
- try {
2186
- const TemplateComponent = template;
2187
- const element = /* @__PURE__ */ jsx11(TemplateComponent, { ...data });
2188
- const html = await render(element, {
2189
- pretty: true
2190
- });
2191
- setRenderedHtml(html);
2192
- onRender?.(html);
2193
- setError(null);
2194
- } catch (err) {
2195
- setError(err);
2196
- console.error("Failed to render email template:", err);
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/components/Broadcasts/StatusBadge.tsx
2266
- import { jsx as jsx12 } from "react/jsx-runtime";
2267
- var statusConfig = {
2268
- ["draft" /* DRAFT */]: {
2269
- label: "Draft",
2270
- color: "#6B7280",
2271
- // gray
2272
- backgroundColor: "#F3F4F6"
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
- children: config.label
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/email-templates/DefaultBroadcastTemplate.tsx
1436
+ // src/fields/emailContent.ts
2338
1437
  import {
2339
- Body,
2340
- Container,
2341
- Head,
2342
- Hr,
2343
- Html,
2344
- Link,
2345
- Preview,
2346
- Section,
2347
- Text
2348
- } from "@react-email/components";
2349
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
2350
- var DefaultBroadcastTemplate = ({
2351
- subject,
2352
- preheader,
2353
- content
2354
- }) => {
2355
- return /* @__PURE__ */ jsxs10(Html, { children: [
2356
- /* @__PURE__ */ jsx13(Head, {}),
2357
- /* @__PURE__ */ jsx13(Preview, { children: preheader || subject }),
2358
- /* @__PURE__ */ jsx13(Body, { style: main, children: /* @__PURE__ */ jsxs10(Container, { style: container, children: [
2359
- /* @__PURE__ */ jsx13(Section, { style: contentSection, children: /* @__PURE__ */ jsx13("div", { dangerouslySetInnerHTML: { __html: content } }) }),
2360
- /* @__PURE__ */ jsx13(Hr, { style: divider }),
2361
- /* @__PURE__ */ jsxs10(Section, { style: footer, children: [
2362
- /* @__PURE__ */ jsx13(Text, { style: footerText, children: "You're receiving this email because you subscribed to our newsletter." }),
2363
- /* @__PURE__ */ jsx13(Text, { style: footerText, children: /* @__PURE__ */ jsx13(Link, { href: "{{unsubscribe_url}}", style: footerLink, children: "Unsubscribe" }) })
2364
- ] })
2365
- ] }) })
2366
- ] });
2367
- };
2368
- var main = {
2369
- backgroundColor: "#ffffff",
2370
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
2371
- };
2372
- var container = {
2373
- margin: "0 auto",
2374
- padding: "40px 20px",
2375
- maxWidth: "600px"
2376
- };
2377
- var contentSection = {
2378
- fontSize: "16px",
2379
- lineHeight: "1.6",
2380
- color: "#374151"
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 divider = {
2383
- borderColor: "#e5e7eb",
2384
- margin: "40px 0 20px"
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
- var footer = {
2387
- textAlign: "center"
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 footerText = {
2390
- fontSize: "14px",
2391
- lineHeight: "1.5",
2392
- color: "#6b7280",
2393
- margin: "0 0 10px"
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 footerLink = {
2396
- color: "#6b7280",
2397
- textDecoration: "underline"
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
- EmailRenderer,
2407
- EmptyField,
2408
- MagicLinkVerify,
2409
- NewsletterForm,
2410
- PreferencesForm,
2411
- PreviewControls,
1785
+ PluginConfigProvider,
2412
1786
  StatusBadge,
2413
- createMagicLinkVerify,
2414
- createNewsletterForm,
2415
- createPreferencesForm,
2416
- useNewsletterAuth
1787
+ createBroadcastInlinePreviewField,
1788
+ createBroadcastPreviewField,
1789
+ createEmailContentField,
1790
+ usePluginConfig,
1791
+ usePluginConfigOptional2 as usePluginConfigOptional
2417
1792
  };
2418
- //# sourceMappingURL=components.js.map