payload-plugin-newsletter 0.12.2 → 0.13.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 +21 -0
- package/dist/components.cjs +529 -12
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.cts +8 -2
- package/dist/components.d.ts +8 -2
- package/dist/components.js +526 -12
- package/dist/components.js.map +1 -1
- package/dist/index.cjs +63 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +63 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/components.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ export { MagicLinkVerify, MagicLinkVerifyProps, NewsletterForm, PreferencesForm,
|
|
|
2
2
|
export { PreferencesFormProps, SignupFormProps, Subscriber } from './types.cjs';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { SerializedEditorState } from 'lexical';
|
|
5
|
-
import { RichTextField } from 'payload';
|
|
5
|
+
import { RichTextField, DefaultCellComponentProps } from 'payload';
|
|
6
6
|
|
|
7
7
|
interface EmailPreviewProps {
|
|
8
8
|
content: SerializedEditorState | null;
|
|
@@ -50,6 +50,12 @@ interface EmailRendererProps {
|
|
|
50
50
|
}
|
|
51
51
|
declare const EmailRenderer: React.FC<EmailRendererProps>;
|
|
52
52
|
|
|
53
|
+
declare const StatusBadge: React.FC<DefaultCellComponentProps>;
|
|
54
|
+
|
|
55
|
+
declare const ActionsCell: React.FC<DefaultCellComponentProps>;
|
|
56
|
+
|
|
57
|
+
declare const EmptyField: React.FC;
|
|
58
|
+
|
|
53
59
|
interface BroadcastTemplateProps {
|
|
54
60
|
subject: string;
|
|
55
61
|
preheader?: string;
|
|
@@ -57,4 +63,4 @@ interface BroadcastTemplateProps {
|
|
|
57
63
|
}
|
|
58
64
|
declare const DefaultBroadcastTemplate: React.FC<BroadcastTemplateProps>;
|
|
59
65
|
|
|
60
|
-
export { BroadcastEditor, BroadcastInlinePreview, BroadcastPreviewField, type BroadcastTemplateProps, DefaultBroadcastTemplate, EmailPreview, EmailPreviewField, EmailRenderer, PreviewControls };
|
|
66
|
+
export { ActionsCell, BroadcastEditor, BroadcastInlinePreview, BroadcastPreviewField, type BroadcastTemplateProps, DefaultBroadcastTemplate, EmailPreview, EmailPreviewField, EmailRenderer, EmptyField, PreviewControls, StatusBadge };
|
package/dist/components.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { MagicLinkVerify, MagicLinkVerifyProps, NewsletterForm, PreferencesForm,
|
|
|
2
2
|
export { PreferencesFormProps, SignupFormProps, Subscriber } from './types.js';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { SerializedEditorState } from 'lexical';
|
|
5
|
-
import { RichTextField } from 'payload';
|
|
5
|
+
import { RichTextField, DefaultCellComponentProps } from 'payload';
|
|
6
6
|
|
|
7
7
|
interface EmailPreviewProps {
|
|
8
8
|
content: SerializedEditorState | null;
|
|
@@ -50,6 +50,12 @@ interface EmailRendererProps {
|
|
|
50
50
|
}
|
|
51
51
|
declare const EmailRenderer: React.FC<EmailRendererProps>;
|
|
52
52
|
|
|
53
|
+
declare const StatusBadge: React.FC<DefaultCellComponentProps>;
|
|
54
|
+
|
|
55
|
+
declare const ActionsCell: React.FC<DefaultCellComponentProps>;
|
|
56
|
+
|
|
57
|
+
declare const EmptyField: React.FC;
|
|
58
|
+
|
|
53
59
|
interface BroadcastTemplateProps {
|
|
54
60
|
subject: string;
|
|
55
61
|
preheader?: string;
|
|
@@ -57,4 +63,4 @@ interface BroadcastTemplateProps {
|
|
|
57
63
|
}
|
|
58
64
|
declare const DefaultBroadcastTemplate: React.FC<BroadcastTemplateProps>;
|
|
59
65
|
|
|
60
|
-
export { BroadcastEditor, BroadcastInlinePreview, BroadcastPreviewField, type BroadcastTemplateProps, DefaultBroadcastTemplate, EmailPreview, EmailPreviewField, EmailRenderer, PreviewControls };
|
|
66
|
+
export { ActionsCell, BroadcastEditor, BroadcastInlinePreview, BroadcastPreviewField, type BroadcastTemplateProps, DefaultBroadcastTemplate, EmailPreview, EmailPreviewField, EmailRenderer, EmptyField, PreviewControls, StatusBadge };
|
package/dist/components.js
CHANGED
|
@@ -1394,9 +1394,9 @@ var EmailPreviewField = () => {
|
|
|
1394
1394
|
const [isValid, setIsValid] = useState6(true);
|
|
1395
1395
|
const [validationSummary, setValidationSummary] = useState6("");
|
|
1396
1396
|
const fields = useFormFields(([fields2]) => ({
|
|
1397
|
-
content: fields2.content,
|
|
1398
|
-
subject: fields2.subject,
|
|
1399
|
-
preheader: fields2.preheader,
|
|
1397
|
+
content: fields2["contentSection.content"],
|
|
1398
|
+
subject: fields2["contentSection.subject"],
|
|
1399
|
+
preheader: fields2["contentSection.preheader"],
|
|
1400
1400
|
channel: fields2.channel
|
|
1401
1401
|
}));
|
|
1402
1402
|
const handleValidation = (result) => {
|
|
@@ -1536,8 +1536,8 @@ var BroadcastEditor = (props) => {
|
|
|
1536
1536
|
const [isValid, setIsValid] = useState7(true);
|
|
1537
1537
|
const [validationSummary, setValidationSummary] = useState7("");
|
|
1538
1538
|
const fields = useFormFields2(([fields2]) => ({
|
|
1539
|
-
subject: fields2.subject,
|
|
1540
|
-
preheader: fields2.preheader
|
|
1539
|
+
subject: fields2["contentSection.subject"],
|
|
1540
|
+
preheader: fields2["contentSection.preheader"]
|
|
1541
1541
|
}));
|
|
1542
1542
|
const handleValidation = useCallback2((result) => {
|
|
1543
1543
|
setIsValid(result.valid);
|
|
@@ -1989,9 +1989,9 @@ var BroadcastInlinePreview = () => {
|
|
|
1989
1989
|
const [previewData, setPreviewData] = useState9(null);
|
|
1990
1990
|
const [error, setError] = useState9(null);
|
|
1991
1991
|
const fields = useFormFields3(([fields2]) => ({
|
|
1992
|
-
subject: fields2.subject?.value,
|
|
1993
|
-
preheader: fields2.preheader?.value,
|
|
1994
|
-
content: fields2.content?.value
|
|
1992
|
+
subject: fields2["contentSection.subject"]?.value,
|
|
1993
|
+
preheader: fields2["contentSection.preheader"]?.value,
|
|
1994
|
+
content: fields2["contentSection.content"]?.value
|
|
1995
1995
|
}));
|
|
1996
1996
|
const updatePreview = useCallback4(async () => {
|
|
1997
1997
|
if (!fields.content) {
|
|
@@ -2022,10 +2022,12 @@ var BroadcastInlinePreview = () => {
|
|
|
2022
2022
|
}
|
|
2023
2023
|
}, [fields]);
|
|
2024
2024
|
const containerStyle = {
|
|
2025
|
-
marginTop: "2rem",
|
|
2026
2025
|
border: "1px solid #e5e7eb",
|
|
2027
2026
|
borderRadius: "8px",
|
|
2028
|
-
overflow: "hidden"
|
|
2027
|
+
overflow: "hidden",
|
|
2028
|
+
height: "100%",
|
|
2029
|
+
display: "flex",
|
|
2030
|
+
flexDirection: "column"
|
|
2029
2031
|
};
|
|
2030
2032
|
const headerStyle = {
|
|
2031
2033
|
display: "flex",
|
|
@@ -2042,10 +2044,11 @@ var BroadcastInlinePreview = () => {
|
|
|
2042
2044
|
margin: 0
|
|
2043
2045
|
};
|
|
2044
2046
|
const previewContainerStyle = {
|
|
2045
|
-
|
|
2047
|
+
flex: 1,
|
|
2046
2048
|
display: "flex",
|
|
2047
2049
|
flexDirection: "column",
|
|
2048
|
-
background: "#f3f4f6"
|
|
2050
|
+
background: "#f3f4f6",
|
|
2051
|
+
minHeight: "600px"
|
|
2049
2052
|
};
|
|
2050
2053
|
const errorStyle = {
|
|
2051
2054
|
padding: "2rem",
|
|
@@ -2124,7 +2127,516 @@ var BroadcastPreviewField = () => {
|
|
|
2124
2127
|
color: "#6b7280"
|
|
2125
2128
|
}, children: "Email preview is available inline below the content editor." });
|
|
2126
2129
|
};
|
|
2130
|
+
|
|
2131
|
+
// src/components/Broadcasts/StatusBadge.tsx
|
|
2132
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
2133
|
+
var statusConfig = {
|
|
2134
|
+
["draft" /* DRAFT */]: {
|
|
2135
|
+
label: "Draft",
|
|
2136
|
+
color: "#6B7280",
|
|
2137
|
+
// gray
|
|
2138
|
+
backgroundColor: "#F3F4F6"
|
|
2139
|
+
},
|
|
2140
|
+
["scheduled" /* SCHEDULED */]: {
|
|
2141
|
+
label: "Scheduled",
|
|
2142
|
+
color: "#2563EB",
|
|
2143
|
+
// blue
|
|
2144
|
+
backgroundColor: "#DBEAFE"
|
|
2145
|
+
},
|
|
2146
|
+
["sending" /* SENDING */]: {
|
|
2147
|
+
label: "Sending",
|
|
2148
|
+
color: "#D97706",
|
|
2149
|
+
// yellow/orange
|
|
2150
|
+
backgroundColor: "#FEF3C7"
|
|
2151
|
+
},
|
|
2152
|
+
["sent" /* SENT */]: {
|
|
2153
|
+
label: "Sent",
|
|
2154
|
+
color: "#059669",
|
|
2155
|
+
// green
|
|
2156
|
+
backgroundColor: "#D1FAE5"
|
|
2157
|
+
},
|
|
2158
|
+
["failed" /* FAILED */]: {
|
|
2159
|
+
label: "Failed",
|
|
2160
|
+
color: "#DC2626",
|
|
2161
|
+
// red
|
|
2162
|
+
backgroundColor: "#FEE2E2"
|
|
2163
|
+
},
|
|
2164
|
+
["paused" /* PAUSED */]: {
|
|
2165
|
+
label: "Paused",
|
|
2166
|
+
color: "#9333EA",
|
|
2167
|
+
// purple
|
|
2168
|
+
backgroundColor: "#EDE9FE"
|
|
2169
|
+
},
|
|
2170
|
+
["canceled" /* CANCELED */]: {
|
|
2171
|
+
label: "Canceled",
|
|
2172
|
+
color: "#6B7280",
|
|
2173
|
+
// gray
|
|
2174
|
+
backgroundColor: "#F3F4F6"
|
|
2175
|
+
}
|
|
2176
|
+
};
|
|
2177
|
+
var StatusBadge = ({ cellData }) => {
|
|
2178
|
+
const status = cellData;
|
|
2179
|
+
const config = statusConfig[status] || statusConfig["draft" /* DRAFT */];
|
|
2180
|
+
return /* @__PURE__ */ jsx12(
|
|
2181
|
+
"span",
|
|
2182
|
+
{
|
|
2183
|
+
style: {
|
|
2184
|
+
display: "inline-flex",
|
|
2185
|
+
alignItems: "center",
|
|
2186
|
+
padding: "2px 10px",
|
|
2187
|
+
borderRadius: "12px",
|
|
2188
|
+
fontSize: "12px",
|
|
2189
|
+
fontWeight: "500",
|
|
2190
|
+
color: config.color,
|
|
2191
|
+
backgroundColor: config.backgroundColor
|
|
2192
|
+
},
|
|
2193
|
+
children: config.label
|
|
2194
|
+
}
|
|
2195
|
+
);
|
|
2196
|
+
};
|
|
2197
|
+
|
|
2198
|
+
// src/components/Broadcasts/ActionsCell.tsx
|
|
2199
|
+
import { useState as useState11 } from "react";
|
|
2200
|
+
|
|
2201
|
+
// src/components/Broadcasts/SendBroadcastModal.tsx
|
|
2202
|
+
import { useState as useState10, useEffect as useEffect6 } from "react";
|
|
2203
|
+
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2204
|
+
var SendBroadcastModal = ({
|
|
2205
|
+
broadcast,
|
|
2206
|
+
onClose,
|
|
2207
|
+
onSuccess
|
|
2208
|
+
}) => {
|
|
2209
|
+
const [loading, setLoading] = useState10(false);
|
|
2210
|
+
const [error, setError] = useState10(null);
|
|
2211
|
+
const [selectedAudiences, setSelectedAudiences] = useState10([]);
|
|
2212
|
+
const [audiences, setAudiences] = useState10([]);
|
|
2213
|
+
const [providerCapabilities, setProviderCapabilities] = useState10(null);
|
|
2214
|
+
const [sendMode, setSendMode] = useState10("now");
|
|
2215
|
+
const [scheduledDate, setScheduledDate] = useState10("");
|
|
2216
|
+
const [scheduledTime, setScheduledTime] = useState10("");
|
|
2217
|
+
useEffect6(() => {
|
|
2218
|
+
const fetchData = async () => {
|
|
2219
|
+
try {
|
|
2220
|
+
setAudiences([
|
|
2221
|
+
{ id: "all", name: "All Subscribers", subscriberCount: 1e3 },
|
|
2222
|
+
{ id: "active", name: "Active Subscribers", subscriberCount: 850 }
|
|
2223
|
+
]);
|
|
2224
|
+
if (broadcast.channel?.providerType === "broadcast") {
|
|
2225
|
+
setProviderCapabilities({ supportsScheduling: true });
|
|
2226
|
+
} else {
|
|
2227
|
+
setProviderCapabilities({ supportsScheduling: false });
|
|
2228
|
+
}
|
|
2229
|
+
} catch (err) {
|
|
2230
|
+
console.error("Failed to fetch modal data:", err);
|
|
2231
|
+
}
|
|
2232
|
+
};
|
|
2233
|
+
fetchData();
|
|
2234
|
+
}, [broadcast.channel]);
|
|
2235
|
+
const handleSubmit = async (e) => {
|
|
2236
|
+
e.preventDefault();
|
|
2237
|
+
setError(null);
|
|
2238
|
+
setLoading(true);
|
|
2239
|
+
try {
|
|
2240
|
+
if (sendMode === "now") {
|
|
2241
|
+
const response = await fetch(`/api/broadcasts/${broadcast.id}/send`, {
|
|
2242
|
+
method: "POST",
|
|
2243
|
+
headers: {
|
|
2244
|
+
"Content-Type": "application/json"
|
|
2245
|
+
},
|
|
2246
|
+
body: JSON.stringify({
|
|
2247
|
+
audienceIds: selectedAudiences.length > 0 ? selectedAudiences : void 0
|
|
2248
|
+
})
|
|
2249
|
+
});
|
|
2250
|
+
if (!response.ok) {
|
|
2251
|
+
const data = await response.json();
|
|
2252
|
+
throw new Error(data.error || "Failed to send broadcast");
|
|
2253
|
+
}
|
|
2254
|
+
alert(`Broadcast "${broadcast.name}" has been sent successfully`);
|
|
2255
|
+
} else {
|
|
2256
|
+
if (!scheduledDate || !scheduledTime) {
|
|
2257
|
+
throw new Error("Please select both date and time for scheduling");
|
|
2258
|
+
}
|
|
2259
|
+
const scheduledAt = (/* @__PURE__ */ new Date(`${scheduledDate}T${scheduledTime}`)).toISOString();
|
|
2260
|
+
const response = await fetch(`/api/broadcasts/${broadcast.id}/schedule`, {
|
|
2261
|
+
method: "POST",
|
|
2262
|
+
headers: {
|
|
2263
|
+
"Content-Type": "application/json"
|
|
2264
|
+
},
|
|
2265
|
+
body: JSON.stringify({
|
|
2266
|
+
scheduledAt,
|
|
2267
|
+
audienceIds: selectedAudiences.length > 0 ? selectedAudiences : void 0
|
|
2268
|
+
})
|
|
2269
|
+
});
|
|
2270
|
+
if (!response.ok) {
|
|
2271
|
+
const data = await response.json();
|
|
2272
|
+
throw new Error(data.error || "Failed to schedule broadcast");
|
|
2273
|
+
}
|
|
2274
|
+
alert(`Broadcast "${broadcast.name}" has been scheduled successfully`);
|
|
2275
|
+
}
|
|
2276
|
+
onSuccess();
|
|
2277
|
+
} catch (err) {
|
|
2278
|
+
setError(err instanceof Error ? err.message : "An error occurred");
|
|
2279
|
+
} finally {
|
|
2280
|
+
setLoading(false);
|
|
2281
|
+
}
|
|
2282
|
+
};
|
|
2283
|
+
const handleAudienceToggle = (audienceId) => {
|
|
2284
|
+
setSelectedAudiences(
|
|
2285
|
+
(prev) => prev.includes(audienceId) ? prev.filter((id) => id !== audienceId) : [...prev, audienceId]
|
|
2286
|
+
);
|
|
2287
|
+
};
|
|
2288
|
+
const now = /* @__PURE__ */ new Date();
|
|
2289
|
+
const minDate = now.toISOString().split("T")[0];
|
|
2290
|
+
const minTime = now.toTimeString().slice(0, 5);
|
|
2291
|
+
return /* @__PURE__ */ jsx13("div", { style: {
|
|
2292
|
+
position: "fixed",
|
|
2293
|
+
top: 0,
|
|
2294
|
+
left: 0,
|
|
2295
|
+
right: 0,
|
|
2296
|
+
bottom: 0,
|
|
2297
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
2298
|
+
display: "flex",
|
|
2299
|
+
alignItems: "center",
|
|
2300
|
+
justifyContent: "center",
|
|
2301
|
+
zIndex: 9999
|
|
2302
|
+
}, children: /* @__PURE__ */ jsxs11("div", { style: {
|
|
2303
|
+
backgroundColor: "white",
|
|
2304
|
+
borderRadius: "8px",
|
|
2305
|
+
padding: "32px",
|
|
2306
|
+
maxWidth: "500px",
|
|
2307
|
+
width: "90%",
|
|
2308
|
+
maxHeight: "90vh",
|
|
2309
|
+
overflowY: "auto"
|
|
2310
|
+
}, children: [
|
|
2311
|
+
/* @__PURE__ */ jsxs11("h2", { style: { marginTop: 0, marginBottom: "24px" }, children: [
|
|
2312
|
+
"Send Broadcast: ",
|
|
2313
|
+
broadcast.name
|
|
2314
|
+
] }),
|
|
2315
|
+
/* @__PURE__ */ jsxs11("form", { onSubmit: handleSubmit, children: [
|
|
2316
|
+
/* @__PURE__ */ jsxs11("div", { style: { marginBottom: "24px" }, children: [
|
|
2317
|
+
/* @__PURE__ */ jsx13("label", { style: { fontWeight: "bold", display: "block", marginBottom: "8px" }, children: "When to send:" }),
|
|
2318
|
+
/* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: "16px" }, children: [
|
|
2319
|
+
/* @__PURE__ */ jsxs11("label", { style: { display: "flex", alignItems: "center", cursor: "pointer" }, children: [
|
|
2320
|
+
/* @__PURE__ */ jsx13(
|
|
2321
|
+
"input",
|
|
2322
|
+
{
|
|
2323
|
+
type: "radio",
|
|
2324
|
+
value: "now",
|
|
2325
|
+
checked: sendMode === "now",
|
|
2326
|
+
onChange: (e) => setSendMode(e.target.value),
|
|
2327
|
+
style: { marginRight: "8px" }
|
|
2328
|
+
}
|
|
2329
|
+
),
|
|
2330
|
+
"Send Now"
|
|
2331
|
+
] }),
|
|
2332
|
+
providerCapabilities?.supportsScheduling && /* @__PURE__ */ jsxs11("label", { style: { display: "flex", alignItems: "center", cursor: "pointer" }, children: [
|
|
2333
|
+
/* @__PURE__ */ jsx13(
|
|
2334
|
+
"input",
|
|
2335
|
+
{
|
|
2336
|
+
type: "radio",
|
|
2337
|
+
value: "schedule",
|
|
2338
|
+
checked: sendMode === "schedule",
|
|
2339
|
+
onChange: (e) => setSendMode(e.target.value),
|
|
2340
|
+
style: { marginRight: "8px" }
|
|
2341
|
+
}
|
|
2342
|
+
),
|
|
2343
|
+
"Schedule for Later"
|
|
2344
|
+
] })
|
|
2345
|
+
] })
|
|
2346
|
+
] }),
|
|
2347
|
+
sendMode === "schedule" && /* @__PURE__ */ jsxs11("div", { style: { marginBottom: "24px" }, children: [
|
|
2348
|
+
/* @__PURE__ */ jsx13("label", { style: { fontWeight: "bold", display: "block", marginBottom: "8px" }, children: "Schedule Date & Time:" }),
|
|
2349
|
+
/* @__PURE__ */ jsxs11("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
2350
|
+
/* @__PURE__ */ jsx13(
|
|
2351
|
+
"input",
|
|
2352
|
+
{
|
|
2353
|
+
type: "date",
|
|
2354
|
+
value: scheduledDate,
|
|
2355
|
+
onChange: (e) => setScheduledDate(e.target.value),
|
|
2356
|
+
min: minDate,
|
|
2357
|
+
required: sendMode === "schedule",
|
|
2358
|
+
style: {
|
|
2359
|
+
padding: "8px 12px",
|
|
2360
|
+
border: "1px solid #D1D5DB",
|
|
2361
|
+
borderRadius: "4px",
|
|
2362
|
+
flex: 1
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
),
|
|
2366
|
+
/* @__PURE__ */ jsx13(
|
|
2367
|
+
"input",
|
|
2368
|
+
{
|
|
2369
|
+
type: "time",
|
|
2370
|
+
value: scheduledTime,
|
|
2371
|
+
onChange: (e) => setScheduledTime(e.target.value),
|
|
2372
|
+
min: scheduledDate === minDate ? minTime : void 0,
|
|
2373
|
+
required: sendMode === "schedule",
|
|
2374
|
+
style: {
|
|
2375
|
+
padding: "8px 12px",
|
|
2376
|
+
border: "1px solid #D1D5DB",
|
|
2377
|
+
borderRadius: "4px",
|
|
2378
|
+
flex: 1
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
)
|
|
2382
|
+
] })
|
|
2383
|
+
] }),
|
|
2384
|
+
audiences.length > 0 && /* @__PURE__ */ jsxs11("div", { style: { marginBottom: "24px" }, children: [
|
|
2385
|
+
/* @__PURE__ */ jsx13("label", { style: { fontWeight: "bold", display: "block", marginBottom: "8px" }, children: "Target Audiences (optional):" }),
|
|
2386
|
+
/* @__PURE__ */ jsx13("div", { style: {
|
|
2387
|
+
border: "1px solid #D1D5DB",
|
|
2388
|
+
borderRadius: "4px",
|
|
2389
|
+
maxHeight: "200px",
|
|
2390
|
+
overflowY: "auto"
|
|
2391
|
+
}, children: audiences.map((audience) => /* @__PURE__ */ jsxs11(
|
|
2392
|
+
"label",
|
|
2393
|
+
{
|
|
2394
|
+
style: {
|
|
2395
|
+
display: "flex",
|
|
2396
|
+
alignItems: "center",
|
|
2397
|
+
padding: "12px",
|
|
2398
|
+
borderBottom: "1px solid #E5E7EB",
|
|
2399
|
+
cursor: "pointer",
|
|
2400
|
+
backgroundColor: selectedAudiences.includes(audience.id) ? "#F3F4F6" : "transparent"
|
|
2401
|
+
},
|
|
2402
|
+
children: [
|
|
2403
|
+
/* @__PURE__ */ jsx13(
|
|
2404
|
+
"input",
|
|
2405
|
+
{
|
|
2406
|
+
type: "checkbox",
|
|
2407
|
+
checked: selectedAudiences.includes(audience.id),
|
|
2408
|
+
onChange: () => handleAudienceToggle(audience.id),
|
|
2409
|
+
style: { marginRight: "12px" }
|
|
2410
|
+
}
|
|
2411
|
+
),
|
|
2412
|
+
/* @__PURE__ */ jsxs11("div", { style: { flex: 1 }, children: [
|
|
2413
|
+
/* @__PURE__ */ jsx13("div", { style: { fontWeight: 500 }, children: audience.name }),
|
|
2414
|
+
/* @__PURE__ */ jsxs11("div", { style: { fontSize: "14px", color: "#6B7280" }, children: [
|
|
2415
|
+
audience.subscriberCount.toLocaleString(),
|
|
2416
|
+
" subscribers"
|
|
2417
|
+
] })
|
|
2418
|
+
] })
|
|
2419
|
+
]
|
|
2420
|
+
},
|
|
2421
|
+
audience.id
|
|
2422
|
+
)) }),
|
|
2423
|
+
selectedAudiences.length === 0 && /* @__PURE__ */ jsx13("p", { style: { fontSize: "14px", color: "#6B7280", marginTop: "8px" }, children: "If no audiences are selected, the broadcast will be sent to all subscribers." })
|
|
2424
|
+
] }),
|
|
2425
|
+
/* @__PURE__ */ jsxs11("div", { style: {
|
|
2426
|
+
backgroundColor: "#F3F4F6",
|
|
2427
|
+
padding: "16px",
|
|
2428
|
+
borderRadius: "4px",
|
|
2429
|
+
marginBottom: "24px"
|
|
2430
|
+
}, children: [
|
|
2431
|
+
/* @__PURE__ */ jsx13("h4", { style: { marginTop: 0, marginBottom: "8px" }, children: "Summary" }),
|
|
2432
|
+
/* @__PURE__ */ jsxs11("p", { style: { margin: 0, fontSize: "14px" }, children: [
|
|
2433
|
+
/* @__PURE__ */ jsx13("strong", { children: "Subject:" }),
|
|
2434
|
+
" ",
|
|
2435
|
+
broadcast.subject,
|
|
2436
|
+
/* @__PURE__ */ jsx13("br", {}),
|
|
2437
|
+
/* @__PURE__ */ jsx13("strong", { children: "Channel:" }),
|
|
2438
|
+
" ",
|
|
2439
|
+
broadcast.channel?.name || "Unknown",
|
|
2440
|
+
/* @__PURE__ */ jsx13("br", {}),
|
|
2441
|
+
/* @__PURE__ */ jsx13("strong", { children: "Provider:" }),
|
|
2442
|
+
" ",
|
|
2443
|
+
broadcast.channel?.providerType || "Unknown",
|
|
2444
|
+
/* @__PURE__ */ jsx13("br", {}),
|
|
2445
|
+
/* @__PURE__ */ jsx13("strong", { children: "When:" }),
|
|
2446
|
+
" ",
|
|
2447
|
+
sendMode === "now" ? "Immediately" : `${scheduledDate} at ${scheduledTime}`,
|
|
2448
|
+
/* @__PURE__ */ jsx13("br", {}),
|
|
2449
|
+
selectedAudiences.length > 0 && /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
2450
|
+
/* @__PURE__ */ jsx13("strong", { children: "Audiences:" }),
|
|
2451
|
+
" ",
|
|
2452
|
+
selectedAudiences.length,
|
|
2453
|
+
" selected"
|
|
2454
|
+
] })
|
|
2455
|
+
] })
|
|
2456
|
+
] }),
|
|
2457
|
+
error && /* @__PURE__ */ jsx13("div", { style: {
|
|
2458
|
+
backgroundColor: "#FEE2E2",
|
|
2459
|
+
border: "1px solid #FCA5A5",
|
|
2460
|
+
color: "#DC2626",
|
|
2461
|
+
padding: "12px",
|
|
2462
|
+
borderRadius: "4px",
|
|
2463
|
+
marginBottom: "24px"
|
|
2464
|
+
}, children: error }),
|
|
2465
|
+
/* @__PURE__ */ jsxs11("div", { style: { display: "flex", justifyContent: "flex-end", gap: "12px" }, children: [
|
|
2466
|
+
/* @__PURE__ */ jsx13(
|
|
2467
|
+
"button",
|
|
2468
|
+
{
|
|
2469
|
+
type: "button",
|
|
2470
|
+
onClick: onClose,
|
|
2471
|
+
disabled: loading,
|
|
2472
|
+
style: {
|
|
2473
|
+
padding: "8px 24px",
|
|
2474
|
+
backgroundColor: "#E5E7EB",
|
|
2475
|
+
color: "#1F2937",
|
|
2476
|
+
border: "none",
|
|
2477
|
+
borderRadius: "4px",
|
|
2478
|
+
fontSize: "16px",
|
|
2479
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
2480
|
+
opacity: loading ? 0.6 : 1
|
|
2481
|
+
},
|
|
2482
|
+
children: "Cancel"
|
|
2483
|
+
}
|
|
2484
|
+
),
|
|
2485
|
+
/* @__PURE__ */ jsx13(
|
|
2486
|
+
"button",
|
|
2487
|
+
{
|
|
2488
|
+
type: "submit",
|
|
2489
|
+
disabled: loading,
|
|
2490
|
+
style: {
|
|
2491
|
+
padding: "8px 24px",
|
|
2492
|
+
backgroundColor: "#2563EB",
|
|
2493
|
+
color: "white",
|
|
2494
|
+
border: "none",
|
|
2495
|
+
borderRadius: "4px",
|
|
2496
|
+
fontSize: "16px",
|
|
2497
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
2498
|
+
opacity: loading ? 0.6 : 1
|
|
2499
|
+
},
|
|
2500
|
+
children: loading ? "Processing..." : sendMode === "now" ? "Send Now" : "Schedule"
|
|
2501
|
+
}
|
|
2502
|
+
)
|
|
2503
|
+
] })
|
|
2504
|
+
] })
|
|
2505
|
+
] }) });
|
|
2506
|
+
};
|
|
2507
|
+
|
|
2508
|
+
// src/components/Broadcasts/ActionsCell.tsx
|
|
2509
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2510
|
+
var ActionsCell = ({ rowData }) => {
|
|
2511
|
+
const [loading, setLoading] = useState11(false);
|
|
2512
|
+
const [showSendModal, setShowSendModal] = useState11(false);
|
|
2513
|
+
const broadcast = rowData;
|
|
2514
|
+
const handleSend = () => {
|
|
2515
|
+
if (!broadcast.providerId) {
|
|
2516
|
+
alert("This broadcast has not been synced with the provider yet");
|
|
2517
|
+
return;
|
|
2518
|
+
}
|
|
2519
|
+
setShowSendModal(true);
|
|
2520
|
+
};
|
|
2521
|
+
const handleSchedule = () => {
|
|
2522
|
+
if (!broadcast.providerId) {
|
|
2523
|
+
alert("This broadcast has not been synced with the provider yet");
|
|
2524
|
+
return;
|
|
2525
|
+
}
|
|
2526
|
+
setShowSendModal(true);
|
|
2527
|
+
};
|
|
2528
|
+
const handleDuplicate = async () => {
|
|
2529
|
+
try {
|
|
2530
|
+
setLoading(true);
|
|
2531
|
+
const response = await fetch(`/api/broadcasts/${broadcast.id}`);
|
|
2532
|
+
const data = await response.json();
|
|
2533
|
+
delete data.id;
|
|
2534
|
+
delete data.createdAt;
|
|
2535
|
+
delete data.updatedAt;
|
|
2536
|
+
delete data.providerId;
|
|
2537
|
+
delete data.sentAt;
|
|
2538
|
+
delete data.scheduledAt;
|
|
2539
|
+
delete data.analytics;
|
|
2540
|
+
data.name = `${data.name} (Copy)`;
|
|
2541
|
+
data.status = "draft" /* DRAFT */;
|
|
2542
|
+
const createResponse = await fetch("/api/broadcasts", {
|
|
2543
|
+
method: "POST",
|
|
2544
|
+
headers: {
|
|
2545
|
+
"Content-Type": "application/json"
|
|
2546
|
+
},
|
|
2547
|
+
body: JSON.stringify(data)
|
|
2548
|
+
});
|
|
2549
|
+
if (!createResponse.ok) {
|
|
2550
|
+
throw new Error("Failed to duplicate broadcast");
|
|
2551
|
+
}
|
|
2552
|
+
alert("Broadcast duplicated successfully");
|
|
2553
|
+
window.location.reload();
|
|
2554
|
+
} catch (error) {
|
|
2555
|
+
alert(error instanceof Error ? error.message : "Failed to duplicate broadcast");
|
|
2556
|
+
} finally {
|
|
2557
|
+
setLoading(false);
|
|
2558
|
+
}
|
|
2559
|
+
};
|
|
2560
|
+
const canSend = broadcast.status === "draft" /* DRAFT */;
|
|
2561
|
+
const canSchedule = broadcast.status === "draft" /* DRAFT */;
|
|
2562
|
+
const canDuplicate = true;
|
|
2563
|
+
return /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
2564
|
+
/* @__PURE__ */ jsxs12("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
|
|
2565
|
+
canSend && /* @__PURE__ */ jsx14(
|
|
2566
|
+
"button",
|
|
2567
|
+
{
|
|
2568
|
+
onClick: handleSend,
|
|
2569
|
+
disabled: loading,
|
|
2570
|
+
style: {
|
|
2571
|
+
padding: "4px 12px",
|
|
2572
|
+
backgroundColor: "#2563EB",
|
|
2573
|
+
color: "white",
|
|
2574
|
+
border: "none",
|
|
2575
|
+
borderRadius: "4px",
|
|
2576
|
+
fontSize: "12px",
|
|
2577
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
2578
|
+
opacity: loading ? 0.6 : 1
|
|
2579
|
+
},
|
|
2580
|
+
children: "Send"
|
|
2581
|
+
}
|
|
2582
|
+
),
|
|
2583
|
+
canSchedule && /* @__PURE__ */ jsx14(
|
|
2584
|
+
"button",
|
|
2585
|
+
{
|
|
2586
|
+
onClick: handleSchedule,
|
|
2587
|
+
disabled: loading,
|
|
2588
|
+
style: {
|
|
2589
|
+
padding: "4px 12px",
|
|
2590
|
+
backgroundColor: "#6366F1",
|
|
2591
|
+
color: "white",
|
|
2592
|
+
border: "none",
|
|
2593
|
+
borderRadius: "4px",
|
|
2594
|
+
fontSize: "12px",
|
|
2595
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
2596
|
+
opacity: loading ? 0.6 : 1
|
|
2597
|
+
},
|
|
2598
|
+
children: "Schedule"
|
|
2599
|
+
}
|
|
2600
|
+
),
|
|
2601
|
+
canDuplicate && /* @__PURE__ */ jsx14(
|
|
2602
|
+
"button",
|
|
2603
|
+
{
|
|
2604
|
+
onClick: handleDuplicate,
|
|
2605
|
+
disabled: loading,
|
|
2606
|
+
style: {
|
|
2607
|
+
padding: "4px 12px",
|
|
2608
|
+
backgroundColor: "#6B7280",
|
|
2609
|
+
color: "white",
|
|
2610
|
+
border: "none",
|
|
2611
|
+
borderRadius: "4px",
|
|
2612
|
+
fontSize: "12px",
|
|
2613
|
+
cursor: loading ? "not-allowed" : "pointer",
|
|
2614
|
+
opacity: loading ? 0.6 : 1
|
|
2615
|
+
},
|
|
2616
|
+
children: "Duplicate"
|
|
2617
|
+
}
|
|
2618
|
+
)
|
|
2619
|
+
] }),
|
|
2620
|
+
showSendModal && /* @__PURE__ */ jsx14(
|
|
2621
|
+
SendBroadcastModal,
|
|
2622
|
+
{
|
|
2623
|
+
broadcast,
|
|
2624
|
+
onClose: () => setShowSendModal(false),
|
|
2625
|
+
onSuccess: () => {
|
|
2626
|
+
setShowSendModal(false);
|
|
2627
|
+
window.location.reload();
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
)
|
|
2631
|
+
] });
|
|
2632
|
+
};
|
|
2633
|
+
|
|
2634
|
+
// src/components/Broadcasts/EmptyField.tsx
|
|
2635
|
+
var EmptyField = () => {
|
|
2636
|
+
return null;
|
|
2637
|
+
};
|
|
2127
2638
|
export {
|
|
2639
|
+
ActionsCell,
|
|
2128
2640
|
BroadcastEditor,
|
|
2129
2641
|
BroadcastInlinePreview,
|
|
2130
2642
|
BroadcastPreviewField,
|
|
@@ -2132,10 +2644,12 @@ export {
|
|
|
2132
2644
|
EmailPreview,
|
|
2133
2645
|
EmailPreviewField,
|
|
2134
2646
|
EmailRenderer,
|
|
2647
|
+
EmptyField,
|
|
2135
2648
|
MagicLinkVerify,
|
|
2136
2649
|
NewsletterForm,
|
|
2137
2650
|
PreferencesForm,
|
|
2138
2651
|
PreviewControls,
|
|
2652
|
+
StatusBadge,
|
|
2139
2653
|
createMagicLinkVerify,
|
|
2140
2654
|
createNewsletterForm,
|
|
2141
2655
|
createPreferencesForm,
|