payload-plugin-newsletter 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -2
- package/dist/components.cjs +444 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +33 -1
- package/dist/components.d.ts +33 -1
- package/dist/components.js +449 -0
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +14 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +14 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## [0.12.0] - 2025-07-20
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- Email preview feature for broadcasts with inline preview component
|
|
5
|
+
- React Email integration for reliable email template rendering
|
|
6
|
+
- Custom email template support
|
|
7
|
+
- Desktop and mobile preview modes
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Broadcast collection now includes inline email preview below content editor
|
|
11
|
+
|
|
1
12
|
## [0.11.0] - 2025-07-20
|
|
2
13
|
|
|
3
14
|
### Added
|
|
@@ -7,12 +18,25 @@
|
|
|
7
18
|
- Image upload support with Media collection integration
|
|
8
19
|
- Custom email blocks (Button and Divider)
|
|
9
20
|
- Enhanced link feature with "open in new tab" option
|
|
21
|
+
- Email preview feature for broadcasts:
|
|
22
|
+
- Live preview with manual update button
|
|
23
|
+
- Desktop and mobile responsive views
|
|
24
|
+
- React Email template rendering
|
|
25
|
+
- Custom template support via `email-templates/broadcast-template.tsx`
|
|
26
|
+
- Inline preview below content editor
|
|
10
27
|
- Comprehensive image handling in email HTML conversion:
|
|
11
28
|
- Responsive images with proper email-safe HTML
|
|
12
29
|
- Support for captions and alt text
|
|
13
30
|
- Automatic media URL handling for different storage backends
|
|
14
|
-
-
|
|
15
|
-
-
|
|
31
|
+
- New utilities and components:
|
|
32
|
+
- `contentTransformer` for preview content processing
|
|
33
|
+
- `templateLoader` for custom template discovery
|
|
34
|
+
- `DefaultBroadcastTemplate` bundled email template
|
|
35
|
+
- `BroadcastInlinePreview` component
|
|
36
|
+
- Documentation:
|
|
37
|
+
- Media collection setup guide (`docs/guides/media-collection-setup.md`)
|
|
38
|
+
- Email preview feature guide (`docs/features/email-preview.md`)
|
|
39
|
+
- Prerequisites section in README mentioning Media collection requirement
|
|
16
40
|
|
|
17
41
|
### Changed
|
|
18
42
|
- Removed 'name' field from Broadcasts collection (now uses 'subject' as title)
|
package/dist/components.cjs
CHANGED
|
@@ -32,11 +32,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var components_exports = {};
|
|
33
33
|
__export(components_exports, {
|
|
34
34
|
BroadcastEditor: () => BroadcastEditor,
|
|
35
|
+
BroadcastInlinePreview: () => BroadcastInlinePreview,
|
|
36
|
+
BroadcastPreviewField: () => BroadcastPreviewField,
|
|
37
|
+
DefaultBroadcastTemplate: () => DefaultBroadcastTemplate,
|
|
35
38
|
EmailPreview: () => EmailPreview,
|
|
36
39
|
EmailPreviewField: () => EmailPreviewField,
|
|
40
|
+
EmailRenderer: () => EmailRenderer,
|
|
37
41
|
MagicLinkVerify: () => MagicLinkVerify,
|
|
38
42
|
NewsletterForm: () => NewsletterForm,
|
|
39
43
|
PreferencesForm: () => PreferencesForm,
|
|
44
|
+
PreviewControls: () => PreviewControls,
|
|
40
45
|
createMagicLinkVerify: () => createMagicLinkVerify,
|
|
41
46
|
createNewsletterForm: () => createNewsletterForm,
|
|
42
47
|
createPreferencesForm: () => createPreferencesForm,
|
|
@@ -1726,14 +1731,453 @@ var BroadcastEditor = (props) => {
|
|
|
1726
1731
|
] })
|
|
1727
1732
|
] });
|
|
1728
1733
|
};
|
|
1734
|
+
|
|
1735
|
+
// src/components/Broadcasts/BroadcastInlinePreview.tsx
|
|
1736
|
+
var import_react9 = require("react");
|
|
1737
|
+
var import_ui3 = require("@payloadcms/ui");
|
|
1738
|
+
|
|
1739
|
+
// src/utils/contentTransformer.ts
|
|
1740
|
+
async function transformContentForPreview(lexicalState, options = {}) {
|
|
1741
|
+
const html = await convertToEmailSafeHtml(lexicalState, {
|
|
1742
|
+
mediaUrl: options.mediaUrl
|
|
1743
|
+
});
|
|
1744
|
+
const processedHtml = processCustomBlocks(html);
|
|
1745
|
+
return processedHtml;
|
|
1746
|
+
}
|
|
1747
|
+
function processCustomBlocks(html) {
|
|
1748
|
+
return html;
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1751
|
+
// src/email-templates/DefaultBroadcastTemplate.tsx
|
|
1752
|
+
var import_components2 = require("@react-email/components");
|
|
1753
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1754
|
+
var DefaultBroadcastTemplate = ({
|
|
1755
|
+
subject,
|
|
1756
|
+
preheader,
|
|
1757
|
+
content
|
|
1758
|
+
}) => {
|
|
1759
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_components2.Html, { children: [
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Head, {}),
|
|
1761
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Preview, { children: preheader || subject }),
|
|
1762
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Body, { style: main, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_components2.Container, { style: container, children: [
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Section, { style: contentSection, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { dangerouslySetInnerHTML: { __html: content } }) }),
|
|
1764
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Hr, { style: divider }),
|
|
1765
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_components2.Section, { style: footer, children: [
|
|
1766
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Text, { style: footerText, children: "You're receiving this email because you subscribed to our newsletter." }),
|
|
1767
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Text, { style: footerText, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_components2.Link, { href: "{{unsubscribe_url}}", style: footerLink, children: "Unsubscribe" }) })
|
|
1768
|
+
] })
|
|
1769
|
+
] }) })
|
|
1770
|
+
] });
|
|
1771
|
+
};
|
|
1772
|
+
var main = {
|
|
1773
|
+
backgroundColor: "#ffffff",
|
|
1774
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
1775
|
+
};
|
|
1776
|
+
var container = {
|
|
1777
|
+
margin: "0 auto",
|
|
1778
|
+
padding: "40px 20px",
|
|
1779
|
+
maxWidth: "600px"
|
|
1780
|
+
};
|
|
1781
|
+
var contentSection = {
|
|
1782
|
+
fontSize: "16px",
|
|
1783
|
+
lineHeight: "1.6",
|
|
1784
|
+
color: "#374151"
|
|
1785
|
+
};
|
|
1786
|
+
var divider = {
|
|
1787
|
+
borderColor: "#e5e7eb",
|
|
1788
|
+
margin: "40px 0 20px"
|
|
1789
|
+
};
|
|
1790
|
+
var footer = {
|
|
1791
|
+
textAlign: "center"
|
|
1792
|
+
};
|
|
1793
|
+
var footerText = {
|
|
1794
|
+
fontSize: "14px",
|
|
1795
|
+
lineHeight: "1.5",
|
|
1796
|
+
color: "#6b7280",
|
|
1797
|
+
margin: "0 0 10px"
|
|
1798
|
+
};
|
|
1799
|
+
var footerLink = {
|
|
1800
|
+
color: "#6b7280",
|
|
1801
|
+
textDecoration: "underline"
|
|
1802
|
+
};
|
|
1803
|
+
|
|
1804
|
+
// src/utils/templateLoader.ts
|
|
1805
|
+
var TemplateLoader = class {
|
|
1806
|
+
constructor() {
|
|
1807
|
+
this.loadAttempted = false;
|
|
1808
|
+
this.defaultTemplate = DefaultBroadcastTemplate;
|
|
1809
|
+
}
|
|
1810
|
+
async loadTemplate() {
|
|
1811
|
+
if (!this.loadAttempted) {
|
|
1812
|
+
this.loadAttempted = true;
|
|
1813
|
+
await this.attemptCustomTemplateLoad();
|
|
1814
|
+
}
|
|
1815
|
+
return this.customTemplate || this.defaultTemplate;
|
|
1816
|
+
}
|
|
1817
|
+
async attemptCustomTemplateLoad() {
|
|
1818
|
+
try {
|
|
1819
|
+
const customTemplatePath = `${process.cwd()}/email-templates/broadcast-template`;
|
|
1820
|
+
const module2 = await import(
|
|
1821
|
+
/* @vite-ignore */
|
|
1822
|
+
/* webpackIgnore: true */
|
|
1823
|
+
customTemplatePath
|
|
1824
|
+
).catch(() => null);
|
|
1825
|
+
if (module2) {
|
|
1826
|
+
this.customTemplate = module2.default || module2.BroadcastTemplate;
|
|
1827
|
+
console.info("Loaded custom broadcast template");
|
|
1828
|
+
}
|
|
1829
|
+
} catch (error) {
|
|
1830
|
+
console.info("Using default broadcast template");
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
// Reset for testing
|
|
1834
|
+
reset() {
|
|
1835
|
+
this.customTemplate = void 0;
|
|
1836
|
+
this.loadAttempted = false;
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
var templateLoader = new TemplateLoader();
|
|
1840
|
+
async function loadTemplate() {
|
|
1841
|
+
return templateLoader.loadTemplate();
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
// src/components/Broadcasts/EmailRenderer.tsx
|
|
1845
|
+
var import_react8 = require("react");
|
|
1846
|
+
var import_render = require("@react-email/render");
|
|
1847
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1848
|
+
var EmailRenderer = ({
|
|
1849
|
+
template,
|
|
1850
|
+
data,
|
|
1851
|
+
device = "desktop",
|
|
1852
|
+
onRender
|
|
1853
|
+
}) => {
|
|
1854
|
+
const [renderedHtml, setRenderedHtml] = (0, import_react8.useState)("");
|
|
1855
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1856
|
+
const iframeRef = (0, import_react8.useRef)(null);
|
|
1857
|
+
const renderEmail = (0, import_react8.useCallback)(async () => {
|
|
1858
|
+
try {
|
|
1859
|
+
const TemplateComponent = template;
|
|
1860
|
+
const element = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TemplateComponent, { ...data });
|
|
1861
|
+
const html = await (0, import_render.render)(element, {
|
|
1862
|
+
pretty: true
|
|
1863
|
+
});
|
|
1864
|
+
setRenderedHtml(html);
|
|
1865
|
+
onRender?.(html);
|
|
1866
|
+
setError(null);
|
|
1867
|
+
} catch (err) {
|
|
1868
|
+
setError(err);
|
|
1869
|
+
console.error("Failed to render email template:", err);
|
|
1870
|
+
}
|
|
1871
|
+
}, [template, data, onRender]);
|
|
1872
|
+
(0, import_react8.useEffect)(() => {
|
|
1873
|
+
renderEmail();
|
|
1874
|
+
}, [renderEmail]);
|
|
1875
|
+
(0, import_react8.useEffect)(() => {
|
|
1876
|
+
if (iframeRef.current && renderedHtml) {
|
|
1877
|
+
const iframe = iframeRef.current;
|
|
1878
|
+
const doc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
1879
|
+
if (doc) {
|
|
1880
|
+
doc.open();
|
|
1881
|
+
doc.write(renderedHtml);
|
|
1882
|
+
doc.close();
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
}, [renderedHtml]);
|
|
1886
|
+
const containerStyle = {
|
|
1887
|
+
width: "100%",
|
|
1888
|
+
height: "100%",
|
|
1889
|
+
display: "flex",
|
|
1890
|
+
alignItems: "center",
|
|
1891
|
+
justifyContent: "center"
|
|
1892
|
+
};
|
|
1893
|
+
const iframeStyle = {
|
|
1894
|
+
width: device === "mobile" ? "375px" : "600px",
|
|
1895
|
+
maxWidth: "100%",
|
|
1896
|
+
height: "100%",
|
|
1897
|
+
background: "white",
|
|
1898
|
+
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
|
|
1899
|
+
borderRadius: device === "mobile" ? "20px" : "8px",
|
|
1900
|
+
border: "none",
|
|
1901
|
+
display: "block"
|
|
1902
|
+
};
|
|
1903
|
+
const errorStyle = {
|
|
1904
|
+
background: "white",
|
|
1905
|
+
border: "1px solid #ef4444",
|
|
1906
|
+
borderRadius: "4px",
|
|
1907
|
+
padding: "2rem",
|
|
1908
|
+
maxWidth: "500px"
|
|
1909
|
+
};
|
|
1910
|
+
if (error) {
|
|
1911
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: errorStyle, children: [
|
|
1912
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { style: { color: "#ef4444", margin: "0 0 1rem" }, children: "Template Render Error" }),
|
|
1913
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("pre", { style: {
|
|
1914
|
+
background: "#f9fafb",
|
|
1915
|
+
padding: "1rem",
|
|
1916
|
+
borderRadius: "4px",
|
|
1917
|
+
overflowX: "auto",
|
|
1918
|
+
fontSize: "12px",
|
|
1919
|
+
color: "#374151",
|
|
1920
|
+
margin: 0
|
|
1921
|
+
}, children: error.message })
|
|
1922
|
+
] });
|
|
1923
|
+
}
|
|
1924
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: containerStyle, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1925
|
+
"iframe",
|
|
1926
|
+
{
|
|
1927
|
+
ref: iframeRef,
|
|
1928
|
+
style: iframeStyle,
|
|
1929
|
+
sandbox: "allow-same-origin",
|
|
1930
|
+
title: "Email Preview"
|
|
1931
|
+
}
|
|
1932
|
+
) });
|
|
1933
|
+
};
|
|
1934
|
+
|
|
1935
|
+
// src/components/Broadcasts/PreviewControls.tsx
|
|
1936
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1937
|
+
var PreviewControls = ({
|
|
1938
|
+
onUpdate,
|
|
1939
|
+
device,
|
|
1940
|
+
onDeviceChange,
|
|
1941
|
+
isLoading = false
|
|
1942
|
+
}) => {
|
|
1943
|
+
const controlsStyle = {
|
|
1944
|
+
display: "flex",
|
|
1945
|
+
alignItems: "center",
|
|
1946
|
+
justifyContent: "space-between",
|
|
1947
|
+
padding: "1rem",
|
|
1948
|
+
background: "white",
|
|
1949
|
+
borderBottom: "1px solid #e5e7eb"
|
|
1950
|
+
};
|
|
1951
|
+
const updateButtonStyle = {
|
|
1952
|
+
padding: "0.5rem 1rem",
|
|
1953
|
+
background: "#10b981",
|
|
1954
|
+
color: "white",
|
|
1955
|
+
border: "none",
|
|
1956
|
+
borderRadius: "4px",
|
|
1957
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
1958
|
+
fontSize: "14px",
|
|
1959
|
+
fontWeight: 500,
|
|
1960
|
+
opacity: isLoading ? 0.6 : 1
|
|
1961
|
+
};
|
|
1962
|
+
const deviceSelectorStyle = {
|
|
1963
|
+
display: "flex",
|
|
1964
|
+
gap: "0.5rem"
|
|
1965
|
+
};
|
|
1966
|
+
const deviceButtonStyle = (isActive) => ({
|
|
1967
|
+
display: "flex",
|
|
1968
|
+
alignItems: "center",
|
|
1969
|
+
gap: "0.5rem",
|
|
1970
|
+
padding: "0.5rem 0.75rem",
|
|
1971
|
+
background: isActive ? "#1f2937" : "white",
|
|
1972
|
+
color: isActive ? "white" : "#374151",
|
|
1973
|
+
border: `1px solid ${isActive ? "#1f2937" : "#e5e7eb"}`,
|
|
1974
|
+
borderRadius: "4px",
|
|
1975
|
+
cursor: "pointer",
|
|
1976
|
+
fontSize: "14px"
|
|
1977
|
+
});
|
|
1978
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: controlsStyle, children: [
|
|
1979
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1980
|
+
"button",
|
|
1981
|
+
{
|
|
1982
|
+
style: updateButtonStyle,
|
|
1983
|
+
onClick: onUpdate,
|
|
1984
|
+
disabled: isLoading,
|
|
1985
|
+
children: isLoading ? "Updating..." : "Update Preview"
|
|
1986
|
+
}
|
|
1987
|
+
),
|
|
1988
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: deviceSelectorStyle, children: [
|
|
1989
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
1990
|
+
"button",
|
|
1991
|
+
{
|
|
1992
|
+
style: deviceButtonStyle(device === "desktop"),
|
|
1993
|
+
onClick: () => onDeviceChange("desktop"),
|
|
1994
|
+
"aria-label": "Desktop view",
|
|
1995
|
+
children: [
|
|
1996
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
1997
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }),
|
|
1998
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
|
|
1999
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
|
|
2000
|
+
] }),
|
|
2001
|
+
"Desktop"
|
|
2002
|
+
]
|
|
2003
|
+
}
|
|
2004
|
+
),
|
|
2005
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2006
|
+
"button",
|
|
2007
|
+
{
|
|
2008
|
+
style: deviceButtonStyle(device === "mobile"),
|
|
2009
|
+
onClick: () => onDeviceChange("mobile"),
|
|
2010
|
+
"aria-label": "Mobile view",
|
|
2011
|
+
children: [
|
|
2012
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
2013
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("rect", { x: "5", y: "2", width: "14", height: "20", rx: "2", ry: "2" }),
|
|
2014
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("line", { x1: "12", y1: "18", x2: "12", y2: "18" })
|
|
2015
|
+
] }),
|
|
2016
|
+
"Mobile"
|
|
2017
|
+
]
|
|
2018
|
+
}
|
|
2019
|
+
)
|
|
2020
|
+
] })
|
|
2021
|
+
] });
|
|
2022
|
+
};
|
|
2023
|
+
|
|
2024
|
+
// src/components/Broadcasts/BroadcastInlinePreview.tsx
|
|
2025
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
2026
|
+
var BroadcastInlinePreview = () => {
|
|
2027
|
+
const [device, setDevice] = (0, import_react9.useState)("desktop");
|
|
2028
|
+
const [isLoading, setIsLoading] = (0, import_react9.useState)(false);
|
|
2029
|
+
const [showPreview, setShowPreview] = (0, import_react9.useState)(false);
|
|
2030
|
+
const [previewData, setPreviewData] = (0, import_react9.useState)(null);
|
|
2031
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
2032
|
+
const fields = (0, import_ui3.useFormFields)(([fields2]) => ({
|
|
2033
|
+
subject: fields2.subject?.value,
|
|
2034
|
+
preheader: fields2.preheader?.value,
|
|
2035
|
+
content: fields2.content?.value
|
|
2036
|
+
}));
|
|
2037
|
+
const updatePreview = (0, import_react9.useCallback)(async () => {
|
|
2038
|
+
if (!fields.content) {
|
|
2039
|
+
setError(new Error("Please add some content before previewing"));
|
|
2040
|
+
return;
|
|
2041
|
+
}
|
|
2042
|
+
setIsLoading(true);
|
|
2043
|
+
setError(null);
|
|
2044
|
+
try {
|
|
2045
|
+
const htmlContent = await transformContentForPreview(fields.content, {
|
|
2046
|
+
mediaUrl: "/api/media"
|
|
2047
|
+
});
|
|
2048
|
+
const template = await loadTemplate();
|
|
2049
|
+
setPreviewData({
|
|
2050
|
+
template,
|
|
2051
|
+
data: {
|
|
2052
|
+
subject: fields.subject || "",
|
|
2053
|
+
preheader: fields.preheader || "",
|
|
2054
|
+
content: htmlContent
|
|
2055
|
+
}
|
|
2056
|
+
});
|
|
2057
|
+
setShowPreview(true);
|
|
2058
|
+
} catch (err) {
|
|
2059
|
+
setError(err);
|
|
2060
|
+
console.error("Failed to update preview:", err);
|
|
2061
|
+
} finally {
|
|
2062
|
+
setIsLoading(false);
|
|
2063
|
+
}
|
|
2064
|
+
}, [fields]);
|
|
2065
|
+
const containerStyle = {
|
|
2066
|
+
marginTop: "2rem",
|
|
2067
|
+
border: "1px solid #e5e7eb",
|
|
2068
|
+
borderRadius: "8px",
|
|
2069
|
+
overflow: "hidden"
|
|
2070
|
+
};
|
|
2071
|
+
const headerStyle = {
|
|
2072
|
+
display: "flex",
|
|
2073
|
+
alignItems: "center",
|
|
2074
|
+
justifyContent: "space-between",
|
|
2075
|
+
padding: "1rem",
|
|
2076
|
+
background: "#f9fafb",
|
|
2077
|
+
borderBottom: "1px solid #e5e7eb"
|
|
2078
|
+
};
|
|
2079
|
+
const titleStyle = {
|
|
2080
|
+
fontSize: "16px",
|
|
2081
|
+
fontWeight: 600,
|
|
2082
|
+
color: "#1f2937",
|
|
2083
|
+
margin: 0
|
|
2084
|
+
};
|
|
2085
|
+
const previewContainerStyle = {
|
|
2086
|
+
height: "600px",
|
|
2087
|
+
display: "flex",
|
|
2088
|
+
flexDirection: "column",
|
|
2089
|
+
background: "#f3f4f6"
|
|
2090
|
+
};
|
|
2091
|
+
const errorStyle = {
|
|
2092
|
+
padding: "2rem",
|
|
2093
|
+
textAlign: "center"
|
|
2094
|
+
};
|
|
2095
|
+
const toggleButtonStyle = {
|
|
2096
|
+
padding: "0.5rem 1rem",
|
|
2097
|
+
background: showPreview ? "#ef4444" : "#3b82f6",
|
|
2098
|
+
color: "white",
|
|
2099
|
+
border: "none",
|
|
2100
|
+
borderRadius: "4px",
|
|
2101
|
+
cursor: "pointer",
|
|
2102
|
+
fontSize: "14px",
|
|
2103
|
+
fontWeight: 500
|
|
2104
|
+
};
|
|
2105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: containerStyle, children: [
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: headerStyle, children: [
|
|
2107
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { style: titleStyle, children: "Email Preview" }),
|
|
2108
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2109
|
+
"button",
|
|
2110
|
+
{
|
|
2111
|
+
onClick: () => showPreview ? setShowPreview(false) : updatePreview(),
|
|
2112
|
+
style: toggleButtonStyle,
|
|
2113
|
+
disabled: isLoading,
|
|
2114
|
+
children: isLoading ? "Loading..." : showPreview ? "Hide Preview" : "Show Preview"
|
|
2115
|
+
}
|
|
2116
|
+
)
|
|
2117
|
+
] }),
|
|
2118
|
+
showPreview && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: previewContainerStyle, children: error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: errorStyle, children: [
|
|
2119
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { color: "#ef4444", margin: "0 0 1rem" }, children: error.message }),
|
|
2120
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2121
|
+
"button",
|
|
2122
|
+
{
|
|
2123
|
+
onClick: updatePreview,
|
|
2124
|
+
style: {
|
|
2125
|
+
padding: "0.5rem 1rem",
|
|
2126
|
+
background: "#3b82f6",
|
|
2127
|
+
color: "white",
|
|
2128
|
+
border: "none",
|
|
2129
|
+
borderRadius: "4px",
|
|
2130
|
+
cursor: "pointer"
|
|
2131
|
+
},
|
|
2132
|
+
children: "Retry"
|
|
2133
|
+
}
|
|
2134
|
+
)
|
|
2135
|
+
] }) : previewData ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
2136
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2137
|
+
PreviewControls,
|
|
2138
|
+
{
|
|
2139
|
+
onUpdate: updatePreview,
|
|
2140
|
+
device,
|
|
2141
|
+
onDeviceChange: setDevice,
|
|
2142
|
+
isLoading
|
|
2143
|
+
}
|
|
2144
|
+
),
|
|
2145
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "2rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2146
|
+
EmailRenderer,
|
|
2147
|
+
{
|
|
2148
|
+
template: previewData.template,
|
|
2149
|
+
data: previewData.data,
|
|
2150
|
+
device
|
|
2151
|
+
}
|
|
2152
|
+
) })
|
|
2153
|
+
] }) : null })
|
|
2154
|
+
] });
|
|
2155
|
+
};
|
|
2156
|
+
|
|
2157
|
+
// src/components/Broadcasts/BroadcastPreviewField.tsx
|
|
2158
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
2159
|
+
var BroadcastPreviewField = () => {
|
|
2160
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: {
|
|
2161
|
+
padding: "1rem",
|
|
2162
|
+
background: "#f9fafb",
|
|
2163
|
+
borderRadius: "4px",
|
|
2164
|
+
fontSize: "14px",
|
|
2165
|
+
color: "#6b7280"
|
|
2166
|
+
}, children: "Email preview is available inline below the content editor." });
|
|
2167
|
+
};
|
|
1729
2168
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1730
2169
|
0 && (module.exports = {
|
|
1731
2170
|
BroadcastEditor,
|
|
2171
|
+
BroadcastInlinePreview,
|
|
2172
|
+
BroadcastPreviewField,
|
|
2173
|
+
DefaultBroadcastTemplate,
|
|
1732
2174
|
EmailPreview,
|
|
1733
2175
|
EmailPreviewField,
|
|
2176
|
+
EmailRenderer,
|
|
1734
2177
|
MagicLinkVerify,
|
|
1735
2178
|
NewsletterForm,
|
|
1736
2179
|
PreferencesForm,
|
|
2180
|
+
PreviewControls,
|
|
1737
2181
|
createMagicLinkVerify,
|
|
1738
2182
|
createNewsletterForm,
|
|
1739
2183
|
createPreferencesForm,
|