payload-plugin-newsletter 0.20.4 → 0.20.6
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 +35 -0
- package/dist/admin.d.ts +25 -0
- package/dist/admin.js +83 -139
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
## [0.20.6] - 2025-08-01
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
- **Preview Content Path** - Fixed preview component to correctly access nested content fields
|
|
5
|
+
- Changed from trying multiple access patterns to using the correct flattened field name
|
|
6
|
+
- Content is now accessed via `fields?.['contentSection.content']` using dot notation
|
|
7
|
+
- Removed debug logging and simplified content access logic
|
|
8
|
+
- Preview now properly finds content in the nested `contentSection.content` field structure
|
|
9
|
+
|
|
10
|
+
### Technical Changes
|
|
11
|
+
- Updated field access pattern to match Payload's flattened field naming convention
|
|
12
|
+
- Simplified content value retrieval by using the correct dot notation path
|
|
13
|
+
- Removed unnecessary fallback patterns that were trying incorrect field paths
|
|
14
|
+
|
|
15
|
+
## [0.20.5] - 2025-08-01
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Manual Preview Button** - Replaced automatic preview with manual "Generate Preview" button
|
|
19
|
+
- Fixed content access issue where preview couldn't find content due to field group separation
|
|
20
|
+
- Changed from `data.content` to `fields?.contentSection?.content` using `useFormFields` hook
|
|
21
|
+
- Removed automatic hot-reloading in favor of user-controlled preview generation
|
|
22
|
+
- Added "Hide Preview" and "Refresh Preview" buttons for better control
|
|
23
|
+
- Preview now correctly accesses content from nested field groups
|
|
24
|
+
|
|
25
|
+
### Enhanced
|
|
26
|
+
- **Better Error Handling** - Clear error messages when no content is available
|
|
27
|
+
- **Improved UX** - Manual preview button prevents excessive API calls during content editing
|
|
28
|
+
- **Proper Form Data Access** - Uses Payload's `useFormFields` hook to access all form fields across groups
|
|
29
|
+
|
|
30
|
+
### Technical Changes
|
|
31
|
+
- Component now implements `UIFieldClientComponent` interface from Payload
|
|
32
|
+
- Removed automatic `useEffect` triggers and debouncing
|
|
33
|
+
- Fixed field path from `data.content` to `fields?.contentSection?.content`
|
|
34
|
+
- Maintains 600px iframe height for consistent preview display
|
|
35
|
+
|
|
1
36
|
## [0.20.4] - 2025-07-31
|
|
2
37
|
|
|
3
38
|
### Added
|
package/dist/admin.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { UIFieldClientComponent } from 'payload';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
declare const BroadcastInlinePreview: UIFieldClientComponent;
|
|
5
|
+
interface BroadcastInlinePreviewProps {
|
|
6
|
+
data?: any;
|
|
7
|
+
field?: any;
|
|
8
|
+
path?: string;
|
|
9
|
+
schemaPath?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface StatusBadgeProps {
|
|
13
|
+
cellData?: string;
|
|
14
|
+
rowData?: any;
|
|
15
|
+
}
|
|
16
|
+
declare const StatusBadge: React.FC<StatusBadgeProps>;
|
|
17
|
+
|
|
18
|
+
interface EmailPreviewProps {
|
|
19
|
+
content?: any;
|
|
20
|
+
subject?: string;
|
|
21
|
+
preheader?: string;
|
|
22
|
+
}
|
|
23
|
+
declare const EmailPreview: React.FC<EmailPreviewProps>;
|
|
24
|
+
|
|
25
|
+
export { BroadcastInlinePreview, type BroadcastInlinePreviewProps, EmailPreview, type EmailPreviewProps, StatusBadge, type StatusBadgeProps };
|
package/dist/admin.js
CHANGED
|
@@ -2,153 +2,97 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
|
|
4
4
|
// src/admin/components/BroadcastInlinePreview.tsx
|
|
5
|
-
import { useState,
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
path: _path,
|
|
11
|
-
schemaPath: _schemaPath,
|
|
12
|
-
..._props
|
|
13
|
-
}) => {
|
|
14
|
-
const [previewHtml, setPreviewHtml] = useState("");
|
|
5
|
+
import { useState, useCallback } from "react";
|
|
6
|
+
import { useFormFields } from "@payloadcms/ui";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var BroadcastInlinePreview = () => {
|
|
9
|
+
const [preview, setPreview] = useState("");
|
|
15
10
|
const [loading, setLoading] = useState(false);
|
|
11
|
+
const [showPreview, setShowPreview] = useState(false);
|
|
16
12
|
const [error, setError] = useState(null);
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (!data?.content || !data.content.root?.children?.length) {
|
|
21
|
-
setPreviewHtml("");
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
13
|
+
const fields = useFormFields(([fields2]) => fields2);
|
|
14
|
+
const generatePreview = useCallback(async () => {
|
|
15
|
+
try {
|
|
24
16
|
setLoading(true);
|
|
25
17
|
setError(null);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"Content-Type": "application/json"
|
|
31
|
-
},
|
|
32
|
-
credentials: "same-origin",
|
|
33
|
-
// Include cookies for auth
|
|
34
|
-
body: JSON.stringify({
|
|
35
|
-
content: data.content,
|
|
36
|
-
subject: data.subject || "",
|
|
37
|
-
preheader: data.preheader || ""
|
|
38
|
-
})
|
|
39
|
-
});
|
|
40
|
-
if (!response.ok) {
|
|
41
|
-
const errorData = await response.json().catch(() => ({}));
|
|
42
|
-
throw new Error(errorData.error || `Failed to fetch preview: ${response.status}`);
|
|
43
|
-
}
|
|
44
|
-
const result = await response.json();
|
|
45
|
-
if (result.success && result.html) {
|
|
46
|
-
setPreviewHtml(result.html);
|
|
47
|
-
} else {
|
|
48
|
-
throw new Error(result.error || "No preview HTML returned");
|
|
49
|
-
}
|
|
50
|
-
} catch (err) {
|
|
51
|
-
console.error("Preview fetch error:", err);
|
|
52
|
-
setError(err instanceof Error ? err.message : "Failed to load preview");
|
|
53
|
-
} finally {
|
|
18
|
+
const contentField = fields?.["contentSection.content"];
|
|
19
|
+
const contentValue = contentField?.value;
|
|
20
|
+
if (!contentValue) {
|
|
21
|
+
setError("No content available to preview");
|
|
54
22
|
setLoading(false);
|
|
23
|
+
return;
|
|
55
24
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const resizeIframe = () => {
|
|
64
|
-
try {
|
|
65
|
-
const body = iframe.contentDocument?.body;
|
|
66
|
-
if (body) {
|
|
67
|
-
iframe.style.height = `${body.scrollHeight + 40}px`;
|
|
68
|
-
}
|
|
69
|
-
} catch {
|
|
70
|
-
iframe.style.height = "600px";
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
iframe.onload = resizeIframe;
|
|
74
|
-
const contentWindow = iframe.contentWindow;
|
|
75
|
-
if (contentWindow) {
|
|
76
|
-
contentWindow.addEventListener("resize", resizeIframe);
|
|
77
|
-
return () => contentWindow.removeEventListener("resize", resizeIframe);
|
|
25
|
+
const response = await fetch("/api/broadcasts/preview", {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: { "Content-Type": "application/json" },
|
|
28
|
+
body: JSON.stringify({ content: contentValue })
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new Error(`Preview failed: ${response.statusText}`);
|
|
78
32
|
}
|
|
33
|
+
const data = await response.json();
|
|
34
|
+
setPreview(data.html || "");
|
|
35
|
+
setShowPreview(true);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error("Preview generation error:", err);
|
|
38
|
+
setError(err instanceof Error ? err.message : "Failed to generate preview");
|
|
39
|
+
} finally {
|
|
40
|
+
setLoading(false);
|
|
79
41
|
}
|
|
80
|
-
}, [
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
ref: iframeRef,
|
|
135
|
-
srcDoc: previewHtml,
|
|
136
|
-
style: {
|
|
137
|
-
width: "100%",
|
|
138
|
-
minHeight: "400px",
|
|
139
|
-
border: "none",
|
|
140
|
-
display: "block"
|
|
141
|
-
},
|
|
142
|
-
title: "Email Preview",
|
|
143
|
-
sandbox: "allow-same-origin"
|
|
144
|
-
}
|
|
145
|
-
) }),
|
|
146
|
-
/* @__PURE__ */ jsx("div", { style: {
|
|
147
|
-
marginTop: "0.5rem",
|
|
148
|
-
fontSize: "0.75rem",
|
|
149
|
-
color: "#666",
|
|
150
|
-
textAlign: "center"
|
|
151
|
-
}, children: "This preview shows how your email will appear when sent" })
|
|
42
|
+
}, [fields]);
|
|
43
|
+
return /* @__PURE__ */ jsxs("div", { className: "field-type", children: [
|
|
44
|
+
/* @__PURE__ */ jsx("div", { className: "field-label", children: "Email Preview" }),
|
|
45
|
+
!showPreview ? /* @__PURE__ */ jsxs("div", { className: "preview-controls", children: [
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
"button",
|
|
48
|
+
{
|
|
49
|
+
type: "button",
|
|
50
|
+
onClick: generatePreview,
|
|
51
|
+
disabled: loading,
|
|
52
|
+
className: "btn btn--style-primary btn--icon-style-without-border btn--size-small",
|
|
53
|
+
style: { marginBottom: "1rem" },
|
|
54
|
+
children: loading ? "Generating Preview..." : "Generate Preview"
|
|
55
|
+
}
|
|
56
|
+
),
|
|
57
|
+
error && /* @__PURE__ */ jsx("div", { className: "error-message", style: { color: "#dc2626", marginTop: "0.5rem" }, children: error })
|
|
58
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
59
|
+
/* @__PURE__ */ jsxs("div", { className: "preview-controls", style: { marginBottom: "1rem" }, children: [
|
|
60
|
+
/* @__PURE__ */ jsx(
|
|
61
|
+
"button",
|
|
62
|
+
{
|
|
63
|
+
type: "button",
|
|
64
|
+
onClick: () => setShowPreview(false),
|
|
65
|
+
className: "btn btn--style-secondary btn--icon-style-without-border btn--size-small",
|
|
66
|
+
style: { marginRight: "0.5rem" },
|
|
67
|
+
children: "Hide Preview"
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
"button",
|
|
72
|
+
{
|
|
73
|
+
type: "button",
|
|
74
|
+
onClick: generatePreview,
|
|
75
|
+
disabled: loading,
|
|
76
|
+
className: "btn btn--style-primary btn--icon-style-without-border btn--size-small",
|
|
77
|
+
children: loading ? "Regenerating..." : "Refresh Preview"
|
|
78
|
+
}
|
|
79
|
+
)
|
|
80
|
+
] }),
|
|
81
|
+
/* @__PURE__ */ jsx("div", { className: "email-preview-container", children: /* @__PURE__ */ jsx(
|
|
82
|
+
"iframe",
|
|
83
|
+
{
|
|
84
|
+
srcDoc: preview,
|
|
85
|
+
style: {
|
|
86
|
+
width: "100%",
|
|
87
|
+
height: "600px",
|
|
88
|
+
border: "1px solid #e5e7eb",
|
|
89
|
+
borderRadius: "0.375rem",
|
|
90
|
+
backgroundColor: "white"
|
|
91
|
+
},
|
|
92
|
+
title: "Email Preview"
|
|
93
|
+
}
|
|
94
|
+
) })
|
|
95
|
+
] })
|
|
152
96
|
] });
|
|
153
97
|
};
|
|
154
98
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payload-plugin-newsletter",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.6",
|
|
4
4
|
"description": "Complete newsletter management plugin for Payload CMS with subscriber management, magic link authentication, and email service integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|