@gatewaze/admin-embed 0.1.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.
Files changed (96) hide show
  1. package/README.md +42 -0
  2. package/dist/AiSkillsPicker-dbFhcanE.js +373 -0
  3. package/dist/ContentAccessPage-D0HRqPFc.js +264 -0
  4. package/dist/DataTable-fe6yRVpF.js +1984 -0
  5. package/dist/DetailPageHeader-D_v7924k.js +69 -0
  6. package/dist/EditionEmail-CyhC8232.js +8382 -0
  7. package/dist/GuideContent-DBXKCu7r.js +7580 -0
  8. package/dist/HostMediaTab-BsIBEQ1v.js +440 -0
  9. package/dist/InboxPage-C8ivCKdx.js +1112 -0
  10. package/dist/NewsletterCanvasEditor--B06apn3.js +11453 -0
  11. package/dist/NewsletterSetupWizard-BqV6-fa5.js +347 -0
  12. package/dist/NewsletterSignup-DRVZIpOs.js +224 -0
  13. package/dist/Page-D3u8IZ2a.js +14 -0
  14. package/dist/Toaster-Cde0i6IA.js +18 -0
  15. package/dist/Tooltip-CqxUlW1d.js +746 -0
  16. package/dist/_collectionSlug_-B3UN6M-Q.js +308 -0
  17. package/dist/_collection_-Qz4k_Qjl.js +139 -0
  18. package/dist/_edition_-DQXwkI_-.js +301 -0
  19. package/dist/_id_-CtT7rT9f.js +257 -0
  20. package/dist/_id_-CzScE4Qn.js +1197 -0
  21. package/dist/_virtual_gatewaze-modules-BeloWlOa.js +991 -0
  22. package/dist/admin-B0Mmrh_O.js +1239 -0
  23. package/dist/admin-CcfoK6vD.js +17 -0
  24. package/dist/admin-embed.js +21844 -0
  25. package/dist/admin.css +2 -0
  26. package/dist/block-editor-vXBShAue.js +226 -0
  27. package/dist/brand-DklYwIeA.js +11 -0
  28. package/dist/brick-editor-CmBitMMK.js +225 -0
  29. package/dist/broadcastService-CBqXNt_N.js +190 -0
  30. package/dist/classnames-uWIYaD6z.js +44 -0
  31. package/dist/contentAccessService-Cs7tdAo-.js +59 -0
  32. package/dist/context-jzuubYRz.js +5 -0
  33. package/dist/createSafeContext-P1pK0sAN.js +17 -0
  34. package/dist/detail-B8SVFJJr.js +26285 -0
  35. package/dist/detail-uFBxRbLF.js +2966 -0
  36. package/dist/dist-DTrOExw8.js +38806 -0
  37. package/dist/edition-slug-CARO24Bs.js +7 -0
  38. package/dist/export-edition-html-C_hdXQu5.js +18893 -0
  39. package/dist/floating-ui.dom-Cyv879E9.js +987 -0
  40. package/dist/hooks-C377EXJG.js +2974 -0
  41. package/dist/img/mlops-logo.png +0 -0
  42. package/dist/img/mlops-logo2.png +0 -0
  43. package/dist/index.d.ts +105 -0
  44. package/dist/jsx-runtime-CjozyJt-.js +180 -0
  45. package/dist/lib-CylJmhlJ.js +828 -0
  46. package/dist/list-C0cz0aQz.js +451 -0
  47. package/dist/list-CIVgIGsU.js +166 -0
  48. package/dist/logo/mlops-alt.png +0 -0
  49. package/dist/logo/mlops-logo.png +0 -0
  50. package/dist/new-r4KWpqa6.js +80 -0
  51. package/dist/outline-DwDYhYcF.js +6538 -0
  52. package/dist/pages-Ersfxcz7.js +216 -0
  53. package/dist/preview/12627f.jpg +0 -0
  54. package/dist/preview/af009d.jpg +0 -0
  55. package/dist/public-api-LD11kMxh.js +238 -0
  56. package/dist/react-DB2tPNit.js +933 -0
  57. package/dist/react-dom-giQNVXng.js +267 -0
  58. package/dist/registry-4XrV9iNG.js +7 -0
  59. package/dist/render-BtUWfMUt.js +59634 -0
  60. package/dist/resolvePeopleByEmail-hivX2l07.js +828 -0
  61. package/dist/runtime-config.js +10 -0
  62. package/dist/sends-BkPO6PG2.js +182 -0
  63. package/dist/server.browser-Pj3QUa7k.js +15227 -0
  64. package/dist/shim-BCerG8nb.js +6681 -0
  65. package/dist/sonnerHostBridge-CXuCMM3R.js +665 -0
  66. package/dist/src-BWDAOzZO.js +799 -0
  67. package/dist/starter-templates-CFs-QUdF.js +3077 -0
  68. package/dist/storage-VDSvnkvR.js +39 -0
  69. package/dist/templateParser-BQ2IsJ6c.js +49 -0
  70. package/dist/templates-rjQjWsRr.js +253 -0
  71. package/dist/theme/gatewaze/android-icon-144x144.png +0 -0
  72. package/dist/theme/gatewaze/android-icon-192x192.png +0 -0
  73. package/dist/theme/gatewaze/android-icon-36x36.png +0 -0
  74. package/dist/theme/gatewaze/android-icon-48x48.png +0 -0
  75. package/dist/theme/gatewaze/android-icon-72x72.png +0 -0
  76. package/dist/theme/gatewaze/android-icon-96x96.png +0 -0
  77. package/dist/theme/gatewaze/favicon-144x144.png +0 -0
  78. package/dist/theme/gatewaze/favicon-16x16.png +0 -0
  79. package/dist/theme/gatewaze/favicon-192x192.png +0 -0
  80. package/dist/theme/gatewaze/favicon-32x32.png +0 -0
  81. package/dist/theme/gatewaze/favicon-96x96.png +0 -0
  82. package/dist/theme/gatewaze/favicon.ico +0 -0
  83. package/dist/theme/gatewaze/gatewaze-icon-512.png +0 -0
  84. package/dist/theme/gatewaze/gatewaze-logo-black.svg +24 -0
  85. package/dist/theme/gatewaze/gatewaze-logo-white.svg +20 -0
  86. package/dist/theme/gatewaze/gatewaze-poweredby-black.svg +25 -0
  87. package/dist/theme/gatewaze/gatewaze-poweredby-white.svg +25 -0
  88. package/dist/theme/gatewaze/logo_black.svg +24 -0
  89. package/dist/theme/gatewaze/logo_white.svg +20 -0
  90. package/dist/theme-D6odw5nx.js +586 -0
  91. package/dist/ui-DRIo9Krs.js +9747 -0
  92. package/dist/upload-DMNfZ6FX.js +505 -0
  93. package/dist/useModuleFeature-DgsFIUpv.js +8 -0
  94. package/dist/utils-BcVvIjaY.js +36 -0
  95. package/dist/with-selector-B8eSdVx_.js +100 -0
  96. package/package.json +33 -0
@@ -0,0 +1,451 @@
1
+ import { c as e, t } from "./react-DB2tPNit.js";
2
+ import { t as n } from "./jsx-runtime-CjozyJt-.js";
3
+ import { D as r, O as i, f as a } from "./ui-DRIo9Krs.js";
4
+ import { a as o } from "./hooks-C377EXJG.js";
5
+ import { n as s } from "./sonnerHostBridge-CXuCMM3R.js";
6
+ import { t as c } from "./outline-DwDYhYcF.js";
7
+ import { t as l } from "./Page-D3u8IZ2a.js";
8
+ import { l as u, n as d, r as f, s as p } from "./broadcastService-CBqXNt_N.js";
9
+ import { n as m, t as h } from "./DataTable-fe6yRVpF.js";
10
+ //#region ../../../gatewaze-modules/modules/broadcasts/admin/components/BroadcastsTable.tsx
11
+ var g = /* @__PURE__ */ e(t()), _ = m(), v = c(), y = n(), b = {
12
+ draft: "gray",
13
+ scheduled: "blue",
14
+ sending: "amber",
15
+ sent: "green",
16
+ cancelling: "amber",
17
+ cancelled: "gray",
18
+ failed: "red",
19
+ paused: "amber"
20
+ };
21
+ function x(e) {
22
+ return e.toLocaleString();
23
+ }
24
+ function S(e, t) {
25
+ return t > 0 ? `${(e / t * 100).toFixed(1)}%` : "—";
26
+ }
27
+ function C(e) {
28
+ return new Date(e).toLocaleDateString("en-US", {
29
+ year: "numeric",
30
+ month: "short",
31
+ day: "numeric"
32
+ });
33
+ }
34
+ var w = () => /* @__PURE__ */ (0, y.jsx)("div", {
35
+ className: "flex justify-end",
36
+ children: /* @__PURE__ */ (0, y.jsx)("div", { className: "animate-spin rounded-full h-3.5 w-3.5 border-b-2 border-[var(--gray-8)]" })
37
+ }), T = () => /* @__PURE__ */ (0, y.jsx)("div", {
38
+ className: "flex justify-end text-sm text-[var(--gray-a8)]",
39
+ children: "—"
40
+ }), E = (e) => () => /* @__PURE__ */ (0, y.jsx)("div", {
41
+ className: "grow text-right",
42
+ children: e
43
+ }), D = ({ pctText: e, count: t, dimPct: n }) => /* @__PURE__ */ (0, y.jsxs)("div", {
44
+ className: "flex items-center justify-end text-sm whitespace-nowrap",
45
+ children: [/* @__PURE__ */ (0, y.jsx)("span", {
46
+ className: `font-bold ${n ? "text-[var(--gray-10)]" : "text-[var(--gray-12)]"}`,
47
+ children: e
48
+ }), /* @__PURE__ */ (0, y.jsx)("span", {
49
+ className: "w-10 text-right text-[11px] text-[var(--gray-12)]",
50
+ children: t
51
+ })]
52
+ });
53
+ function O({ engagement: e }) {
54
+ let t = e;
55
+ if (!t) return /* @__PURE__ */ (0, y.jsx)("div", {
56
+ className: "px-6 py-4 text-sm text-[var(--gray-a8)]",
57
+ children: "Loading engagement…"
58
+ });
59
+ if (t.sent === 0) return /* @__PURE__ */ (0, y.jsx)("div", {
60
+ className: "px-6 py-4 text-sm text-[var(--gray-a8)]",
61
+ children: "No send/engagement data recorded for this broadcast."
62
+ });
63
+ let n = ({ label: e, value: t, sub: n }) => /* @__PURE__ */ (0, y.jsxs)("div", {
64
+ className: "flex flex-col",
65
+ children: [
66
+ /* @__PURE__ */ (0, y.jsx)("span", {
67
+ className: "text-xs text-[var(--gray-10)]",
68
+ children: e
69
+ }),
70
+ /* @__PURE__ */ (0, y.jsx)("span", {
71
+ className: "text-lg font-semibold text-[var(--gray-12)]",
72
+ children: t
73
+ }),
74
+ n && /* @__PURE__ */ (0, y.jsx)("span", {
75
+ className: "text-xs text-[var(--gray-10)]",
76
+ children: n
77
+ })
78
+ ]
79
+ }), r = t.human_source === "signals-v1", i = r ? "signals-v1 (ours, per-event detection)" : "estimate (calibrated from the editions we have scored)";
80
+ return /* @__PURE__ */ (0, y.jsx)("div", {
81
+ className: "bg-[var(--gray-a2)] px-6 py-4 border-t border-[var(--gray-a4)]",
82
+ children: /* @__PURE__ */ (0, y.jsxs)("div", {
83
+ className: "rounded-lg border border-[var(--gray-a4)] bg-[var(--color-panel-solid)] p-4",
84
+ children: [
85
+ /* @__PURE__ */ (0, y.jsxs)("div", {
86
+ className: "grid grid-cols-3 sm:grid-cols-5 gap-4",
87
+ children: [
88
+ /* @__PURE__ */ (0, y.jsx)(n, {
89
+ label: "Sent",
90
+ value: x(t.sent)
91
+ }),
92
+ /* @__PURE__ */ (0, y.jsx)(n, {
93
+ label: "Delivered",
94
+ value: x(t.delivered),
95
+ sub: S(t.delivered, t.sent) + " of sent"
96
+ }),
97
+ /* @__PURE__ */ (0, y.jsx)(n, {
98
+ label: "Bounced",
99
+ value: x(t.bounced),
100
+ sub: S(t.bounced, t.sent)
101
+ }),
102
+ /* @__PURE__ */ (0, y.jsx)(n, {
103
+ label: "Opens (raw)",
104
+ value: x(t.unique_opens),
105
+ sub: S(t.unique_opens, t.delivered) + " open rate"
106
+ }),
107
+ /* @__PURE__ */ (0, y.jsx)(n, {
108
+ label: "Clicks (raw)",
109
+ value: x(t.unique_clicks),
110
+ sub: S(t.unique_clicks, t.delivered) + " CTR"
111
+ })
112
+ ]
113
+ }),
114
+ /* @__PURE__ */ (0, y.jsxs)("div", {
115
+ className: "mt-4 pt-4 border-t border-[var(--gray-a4)]",
116
+ children: [/* @__PURE__ */ (0, y.jsxs)("div", {
117
+ className: "text-xs font-medium text-[var(--gray-11)] mb-3",
118
+ children: ["Human engagement · ", i]
119
+ }), /* @__PURE__ */ (0, y.jsxs)("div", {
120
+ className: "grid grid-cols-2 sm:grid-cols-4 gap-4",
121
+ children: [
122
+ /* @__PURE__ */ (0, y.jsx)(n, {
123
+ label: "Human clicks",
124
+ value: t.human_clicks == null ? "—" : (r ? "" : "~") + x(t.human_clicks),
125
+ sub: t.human_clicks == null ? void 0 : S(t.human_clicks, t.delivered) + " human CTR"
126
+ }),
127
+ /* @__PURE__ */ (0, y.jsx)(n, {
128
+ label: "Machine clicks",
129
+ value: t.machine_clicks == null ? "—" : x(t.machine_clicks),
130
+ sub: "scanners / bots"
131
+ }),
132
+ /* @__PURE__ */ (0, y.jsx)(n, {
133
+ label: "Human opens (est.)",
134
+ value: t.human_opens == null ? "—" : "~" + x(t.human_opens),
135
+ sub: t.human_opens == null ? void 0 : S(t.human_opens, t.delivered) + " of delivered"
136
+ }),
137
+ /* @__PURE__ */ (0, y.jsx)(n, {
138
+ label: "Machine opens",
139
+ value: t.machine_opens == null ? "—" : x(t.machine_opens),
140
+ sub: "incl. Apple MPP"
141
+ })
142
+ ]
143
+ })]
144
+ }),
145
+ /* @__PURE__ */ (0, y.jsxs)("div", {
146
+ className: "mt-4 pt-4 border-t border-[var(--gray-a4)]",
147
+ children: [
148
+ /* @__PURE__ */ (0, y.jsx)("div", {
149
+ className: "text-xs font-medium text-[var(--gray-11)] mb-3",
150
+ children: "List churn · why the sent count moves send-to-send"
151
+ }),
152
+ /* @__PURE__ */ (0, y.jsxs)("div", {
153
+ className: "grid grid-cols-2 sm:grid-cols-3 gap-4",
154
+ children: [
155
+ /* @__PURE__ */ (0, y.jsx)(n, {
156
+ label: "Unsubscribed",
157
+ value: x(t.unsubscribed),
158
+ sub: S(t.unsubscribed, t.sent) + " · opt-out"
159
+ }),
160
+ /* @__PURE__ */ (0, y.jsx)(n, {
161
+ label: "Suppressed (bounces)",
162
+ value: x(t.suppressed),
163
+ sub: "removed after repeated bounces"
164
+ }),
165
+ /* @__PURE__ */ (0, y.jsx)(n, {
166
+ label: "Total removed",
167
+ value: x(t.unsubscribed + t.suppressed),
168
+ sub: S(t.unsubscribed + t.suppressed, t.sent) + " of sent"
169
+ })
170
+ ]
171
+ }),
172
+ /* @__PURE__ */ (0, y.jsxs)("p", {
173
+ className: "mt-3 text-xs text-[var(--gray-a8)]",
174
+ children: [
175
+ "This send bounced ",
176
+ x(t.bounced),
177
+ " (",
178
+ S(t.bounced, t.sent),
179
+ ") — a delivery stat, not churn. Bounces are retried; a recipient is only removed after bouncing on several consecutive sends."
180
+ ]
181
+ })
182
+ ]
183
+ })
184
+ ]
185
+ })
186
+ });
187
+ }
188
+ var k = (0, _.createColumnHelper)();
189
+ function A({ broadcasts: e, onDeleted: t }) {
190
+ let n = o(), [a, c] = (0, g.useState)([]), [l, u] = (0, g.useState)({}), [m, A] = (0, g.useState)(null), [j, M] = (0, g.useState)(!1);
191
+ (0, g.useEffect)(() => {
192
+ let t = e.map((e) => {
193
+ let { status: t, latest: n } = f(e), r = n?.completed_at || n?.started_at || n?.scheduled_at || e.created_at, i = (e.sends || []).reduce((e, t) => e + (t.sent_count || 0), 0);
194
+ return {
195
+ id: e.id,
196
+ name: e.name,
197
+ subject: e.subject,
198
+ date: r,
199
+ status: t,
200
+ sentCount: i
201
+ };
202
+ });
203
+ c(t);
204
+ let n = t.map((e) => e.id);
205
+ for (let e = 0; e < n.length; e += 10) {
206
+ let t = n.slice(e, e + 10);
207
+ d(t).then((e) => {
208
+ let t = new Map(e.map((e) => [e.broadcast_id, e]));
209
+ c((e) => e.map((e) => t.has(e.id) ? {
210
+ ...e,
211
+ engagement: t.get(e.id)
212
+ } : e));
213
+ }).catch((e) => console.error("broadcast engagement load failed:", e));
214
+ }
215
+ }, [e]);
216
+ let N = async () => {
217
+ if (m) {
218
+ M(!0);
219
+ try {
220
+ await p(m.id), c((e) => e.filter((e) => e.id !== m.id)), s.success("Broadcast deleted"), A(null), t?.();
221
+ } catch (e) {
222
+ s.error(e instanceof Error ? e.message : "Failed to delete broadcast");
223
+ } finally {
224
+ M(!1);
225
+ }
226
+ }
227
+ }, P = (0, g.useMemo)(() => [
228
+ k.display({
229
+ id: "expander",
230
+ size: 44,
231
+ cell: ({ row: e }) => /* @__PURE__ */ (0, y.jsx)("button", {
232
+ onClick: (t) => {
233
+ t.stopPropagation(), e.toggleExpanded();
234
+ },
235
+ className: "p-1 text-[var(--gray-9)] hover:text-[var(--gray-12)]",
236
+ title: e.getIsExpanded() ? "Collapse" : "Expand stats",
237
+ children: e.getIsExpanded() ? /* @__PURE__ */ (0, y.jsx)(v.ChevronDownIcon, { className: "w-4 h-4" }) : /* @__PURE__ */ (0, y.jsx)(v.ChevronRightIcon, { className: "w-4 h-4" })
238
+ })
239
+ }),
240
+ k.accessor("date", {
241
+ header: "Date",
242
+ size: 130,
243
+ cell: (e) => /* @__PURE__ */ (0, y.jsx)("span", {
244
+ className: "text-sm text-[var(--gray-12)] whitespace-nowrap",
245
+ children: C(e.getValue())
246
+ })
247
+ }),
248
+ k.accessor("name", {
249
+ header: "Name",
250
+ size: 160,
251
+ cell: (e) => /* @__PURE__ */ (0, y.jsx)("span", {
252
+ className: "text-sm text-[var(--gray-12)] truncate max-w-xs block",
253
+ children: e.getValue()
254
+ })
255
+ }),
256
+ k.accessor("subject", {
257
+ header: "Subject",
258
+ cell: (e) => {
259
+ let t = e.getValue();
260
+ return /* @__PURE__ */ (0, y.jsx)("span", {
261
+ className: "text-sm text-[var(--gray-12)] truncate max-w-md block",
262
+ children: t || /* @__PURE__ */ (0, y.jsx)("span", {
263
+ className: "italic text-[var(--gray-9)]",
264
+ children: "No subject"
265
+ })
266
+ });
267
+ }
268
+ }),
269
+ k.accessor("status", {
270
+ header: "Status",
271
+ size: 110,
272
+ cell: (e) => {
273
+ let t = e.getValue();
274
+ return /* @__PURE__ */ (0, y.jsx)(i, {
275
+ color: b[t],
276
+ children: t.charAt(0).toUpperCase() + t.slice(1)
277
+ });
278
+ }
279
+ }),
280
+ k.accessor((e) => e.engagement?.sent ?? -1, {
281
+ id: "sent",
282
+ header: E("Sent"),
283
+ size: 90,
284
+ cell: (e) => {
285
+ let t = e.row.original.engagement;
286
+ return t === void 0 ? /* @__PURE__ */ (0, y.jsx)(w, {}) : !t || t.sent === 0 ? /* @__PURE__ */ (0, y.jsx)(T, {}) : /* @__PURE__ */ (0, y.jsx)("div", {
287
+ className: "text-sm text-right font-medium text-[var(--gray-12)]",
288
+ children: x(t.sent)
289
+ });
290
+ }
291
+ }),
292
+ k.accessor((e) => e.engagement?.human_opens ?? -1, {
293
+ id: "human_opens",
294
+ header: E("Opens (human)"),
295
+ size: 130,
296
+ cell: (e) => {
297
+ let t = e.row.original.engagement;
298
+ return t === void 0 ? /* @__PURE__ */ (0, y.jsx)(w, {}) : !t || t.sent === 0 || t.human_opens == null ? /* @__PURE__ */ (0, y.jsx)(T, {}) : /* @__PURE__ */ (0, y.jsx)(D, {
299
+ pctText: "~" + S(t.human_opens, t.delivered),
300
+ count: x(t.human_opens),
301
+ dimPct: !0
302
+ });
303
+ }
304
+ }),
305
+ k.accessor((e) => e.engagement?.human_clicks ?? -1, {
306
+ id: "human_clicks",
307
+ header: E("Clicks (human)"),
308
+ size: 130,
309
+ cell: (e) => {
310
+ let t = e.row.original.engagement;
311
+ if (t === void 0) return /* @__PURE__ */ (0, y.jsx)(w, {});
312
+ if (!t || t.sent === 0 || t.human_clicks == null) return /* @__PURE__ */ (0, y.jsx)(T, {});
313
+ let n = t.human_source === "signals-v1";
314
+ return /* @__PURE__ */ (0, y.jsx)(D, {
315
+ pctText: (n ? "" : "~") + S(t.human_clicks, t.delivered),
316
+ count: x(t.human_clicks)
317
+ });
318
+ }
319
+ }),
320
+ k.display({
321
+ id: "actions",
322
+ size: 44,
323
+ cell: ({ row: e }) => /* @__PURE__ */ (0, y.jsx)("div", {
324
+ className: "flex justify-end",
325
+ children: /* @__PURE__ */ (0, y.jsx)("button", {
326
+ onClick: (t) => {
327
+ t.stopPropagation(), A(e.original);
328
+ },
329
+ className: "p-1 text-[var(--gray-9)] hover:text-[var(--red-9)]",
330
+ title: "Delete broadcast",
331
+ children: /* @__PURE__ */ (0, y.jsx)(v.TrashIcon, { className: "w-4 h-4" })
332
+ })
333
+ })
334
+ })
335
+ ], []), F = (0, _.useReactTable)({
336
+ data: a,
337
+ columns: P,
338
+ getRowId: (e) => e.id,
339
+ state: { expanded: l },
340
+ onExpandedChange: u,
341
+ getCoreRowModel: (0, _.getCoreRowModel)(),
342
+ getExpandedRowModel: (0, _.getExpandedRowModel)()
343
+ }), I = !!m && (m.sentCount > 0 || m.status === "sent" || m.status === "sending" || m.status === "cancelling" || m.status === "paused");
344
+ return /* @__PURE__ */ (0, y.jsxs)(y.Fragment, { children: [/* @__PURE__ */ (0, y.jsx)(h, {
345
+ table: F,
346
+ onRowDoubleClick: (e) => n(`/broadcasts/${e.id}`),
347
+ renderSubComponent: (e) => /* @__PURE__ */ (0, y.jsx)(O, { engagement: e.original.engagement })
348
+ }), m && /* @__PURE__ */ (0, y.jsxs)("div", {
349
+ className: "fixed inset-0 z-50 flex items-center justify-center p-4",
350
+ role: "dialog",
351
+ "aria-modal": "true",
352
+ children: [/* @__PURE__ */ (0, y.jsx)("div", {
353
+ className: "absolute inset-0 bg-black/40",
354
+ onClick: () => !j && A(null)
355
+ }), /* @__PURE__ */ (0, y.jsxs)("div", {
356
+ className: "relative z-10 w-full max-w-md rounded-xl bg-[var(--color-surface)] border border-[var(--gray-a5)] shadow-xl p-5",
357
+ children: [
358
+ /* @__PURE__ */ (0, y.jsx)("h2", {
359
+ className: "text-base font-semibold text-[var(--gray-12)]",
360
+ children: "Delete broadcast?"
361
+ }),
362
+ /* @__PURE__ */ (0, y.jsxs)("p", {
363
+ className: "mt-2 text-sm text-[var(--gray-11)]",
364
+ children: [/* @__PURE__ */ (0, y.jsx)("span", {
365
+ className: "font-medium text-[var(--gray-12)]",
366
+ children: m.subject || m.name || "This broadcast"
367
+ }), " will be permanently deleted."]
368
+ }),
369
+ I ? /* @__PURE__ */ (0, y.jsxs)("div", {
370
+ className: "mt-3 rounded-md border border-[var(--red-a6)] bg-[var(--red-a2)] px-3 py-2 text-xs text-[var(--red-11)]",
371
+ children: [
372
+ "This broadcast has already been sent",
373
+ m.sentCount > 0 ? ` to ${m.sentCount.toLocaleString()} recipient${m.sentCount === 1 ? "" : "s"}` : "",
374
+ ". Deleting it also removes its send history, replies, and engagement data. This cannot be undone."
375
+ ]
376
+ }) : /* @__PURE__ */ (0, y.jsx)("p", {
377
+ className: "mt-1 text-xs text-[var(--gray-9)]",
378
+ children: "This cannot be undone."
379
+ }),
380
+ /* @__PURE__ */ (0, y.jsxs)("div", {
381
+ className: "mt-4 flex items-center justify-end gap-2",
382
+ children: [/* @__PURE__ */ (0, y.jsx)(r, {
383
+ variant: "outlined",
384
+ onClick: () => A(null),
385
+ disabled: j,
386
+ children: "Cancel"
387
+ }), /* @__PURE__ */ (0, y.jsx)(r, {
388
+ variant: "solid",
389
+ color: "red",
390
+ onClick: N,
391
+ disabled: j,
392
+ children: j ? "Deleting…" : "Delete"
393
+ })]
394
+ })
395
+ ]
396
+ })]
397
+ })] });
398
+ }
399
+ //#endregion
400
+ //#region ../../../gatewaze-modules/modules/broadcasts/admin/pages/list.tsx
401
+ function j() {
402
+ let e = o(), [t, n] = (0, g.useState)([]), [i, c] = (0, g.useState)(!0), d = (0, g.useCallback)(async () => {
403
+ try {
404
+ n(await u());
405
+ } catch (e) {
406
+ console.error("Error loading broadcasts:", e), s.error("Failed to load broadcasts");
407
+ } finally {
408
+ c(!1);
409
+ }
410
+ }, []);
411
+ return (0, g.useEffect)(() => {
412
+ d();
413
+ }, [d]), /* @__PURE__ */ (0, y.jsx)(l, {
414
+ title: "Broadcasts",
415
+ children: /* @__PURE__ */ (0, y.jsx)(a, {
416
+ title: "Broadcasts",
417
+ actions: /* @__PURE__ */ (0, y.jsxs)(r, {
418
+ variant: "solid",
419
+ onClick: () => e("/broadcasts/new"),
420
+ children: [/* @__PURE__ */ (0, y.jsx)(v.PlusIcon, { className: "h-4 w-4 mr-1" }), " New Broadcast"]
421
+ }),
422
+ children: i ? /* @__PURE__ */ (0, y.jsx)("div", {
423
+ className: "flex justify-center py-16",
424
+ children: /* @__PURE__ */ (0, y.jsx)("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--accent-9)]" })
425
+ }) : t.length === 0 ? /* @__PURE__ */ (0, y.jsxs)("div", {
426
+ className: "text-center py-16",
427
+ children: [
428
+ /* @__PURE__ */ (0, y.jsx)(v.PaperAirplaneIcon, { className: "h-16 w-16 text-[var(--gray-8)] mx-auto mb-4" }),
429
+ /* @__PURE__ */ (0, y.jsx)("h2", {
430
+ className: "text-xl font-semibold text-[var(--gray-12)] mb-2",
431
+ children: "No broadcasts yet"
432
+ }),
433
+ /* @__PURE__ */ (0, y.jsx)("p", {
434
+ className: "text-[var(--gray-11)] mb-6 max-w-md mx-auto",
435
+ children: "Send a single email to a segment of your audience, scheduled and timezone-aware. Build the audience with plain language using the AI copilot."
436
+ }),
437
+ /* @__PURE__ */ (0, y.jsxs)(r, {
438
+ variant: "solid",
439
+ onClick: () => e("/broadcasts/new"),
440
+ children: [/* @__PURE__ */ (0, y.jsx)(v.PlusIcon, { className: "h-4 w-4 mr-1" }), " Create Your First Broadcast"]
441
+ })
442
+ ]
443
+ }) : /* @__PURE__ */ (0, y.jsx)(A, {
444
+ broadcasts: t,
445
+ onDeleted: d
446
+ })
447
+ })
448
+ });
449
+ }
450
+ //#endregion
451
+ export { j as default };
@@ -0,0 +1,166 @@
1
+ import { c as e, t } from "./react-DB2tPNit.js";
2
+ import { d as n } from "./shim-BCerG8nb.js";
3
+ import { t as r } from "./jsx-runtime-CjozyJt-.js";
4
+ import { D as i, E as a, O as o, f as s } from "./ui-DRIo9Krs.js";
5
+ import { a as c } from "./hooks-C377EXJG.js";
6
+ import { n as l } from "./sonnerHostBridge-CXuCMM3R.js";
7
+ import { t as u } from "./outline-DwDYhYcF.js";
8
+ import { t as d } from "./Page-D3u8IZ2a.js";
9
+ import f from "./NewsletterSetupWizard-BqV6-fa5.js";
10
+ //#region ../../../gatewaze-modules/modules/newsletters/admin/pages/list.tsx
11
+ var p = /* @__PURE__ */ e(t()), m = u(), h = r();
12
+ function g() {
13
+ let e = c(), [t, r] = (0, p.useState)([]), [u, g] = (0, p.useState)(!0), [_, v] = (0, p.useState)(!1), y = (0, p.useCallback)(async () => {
14
+ try {
15
+ let { data: e, error: t } = await n.from("newsletters_template_collections").select("*").order("name");
16
+ if (t) throw t;
17
+ let i = await Promise.all((e || []).map(async (e) => {
18
+ let { count: t } = await n.from("newsletters_editions").select("id", {
19
+ count: "exact",
20
+ head: !0
21
+ }).eq("collection_id", e.id), r = 0;
22
+ if (e.list_id) try {
23
+ let { count: t } = await n.from("list_subscriptions").select("id", {
24
+ count: "exact",
25
+ head: !0
26
+ }).eq("list_id", e.list_id).eq("subscribed", !0);
27
+ r = t || 0;
28
+ } catch {}
29
+ let i = null, { data: a } = await n.from("newsletter_sends").select("completed_at").eq("status", "sent").order("completed_at", { ascending: !1 }).limit(1);
30
+ return a?.[0] && (i = a[0].completed_at), {
31
+ ...e,
32
+ edition_count: t || 0,
33
+ subscriber_count: r,
34
+ last_send_date: i
35
+ };
36
+ }));
37
+ r(i);
38
+ } catch (e) {
39
+ console.error("Error loading newsletters:", e), l.error("Failed to load newsletters");
40
+ } finally {
41
+ g(!1);
42
+ }
43
+ }, []);
44
+ return (0, p.useEffect)(() => {
45
+ y();
46
+ }, [y]), /* @__PURE__ */ (0, h.jsxs)(d, {
47
+ title: "Newsletters",
48
+ children: [/* @__PURE__ */ (0, h.jsx)(s, {
49
+ title: "Newsletters",
50
+ actions: /* @__PURE__ */ (0, h.jsxs)(i, {
51
+ variant: "solid",
52
+ onClick: () => v(!0),
53
+ children: [/* @__PURE__ */ (0, h.jsx)(m.PlusIcon, { className: "h-4 w-4 mr-1" }), " Create Newsletter"]
54
+ }),
55
+ children: u ? /* @__PURE__ */ (0, h.jsx)("div", {
56
+ className: "flex justify-center py-16",
57
+ children: /* @__PURE__ */ (0, h.jsx)("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-[var(--accent-9)]" })
58
+ }) : t.length === 0 ? /* @__PURE__ */ (0, h.jsxs)("div", {
59
+ className: "text-center py-16",
60
+ children: [
61
+ /* @__PURE__ */ (0, h.jsx)(m.EnvelopeIcon, { className: "h-16 w-16 text-[var(--gray-8)] mx-auto mb-4" }),
62
+ /* @__PURE__ */ (0, h.jsx)("h2", {
63
+ className: "text-xl font-semibold text-[var(--gray-12)] mb-2",
64
+ children: "No newsletters yet"
65
+ }),
66
+ /* @__PURE__ */ (0, h.jsx)("p", {
67
+ className: "text-[var(--gray-11)] mb-6 max-w-md mx-auto",
68
+ children: "Create your first newsletter to start building and sending email campaigns to your subscribers."
69
+ }),
70
+ /* @__PURE__ */ (0, h.jsxs)(i, {
71
+ variant: "solid",
72
+ onClick: () => v(!0),
73
+ children: [/* @__PURE__ */ (0, h.jsx)(m.PlusIcon, { className: "h-4 w-4 mr-1" }), " Create Your First Newsletter"]
74
+ })
75
+ ]
76
+ }) : /* @__PURE__ */ (0, h.jsx)("div", {
77
+ className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
78
+ children: t.map((t) => /* @__PURE__ */ (0, h.jsxs)(a, {
79
+ className: "p-5 cursor-pointer hover:shadow-md transition-shadow border-l-4",
80
+ style: { borderLeftColor: t.accent_color || "var(--accent-9)" },
81
+ onClick: () => e(`/newsletters/${t.slug}`),
82
+ children: [
83
+ /* @__PURE__ */ (0, h.jsxs)("div", {
84
+ className: "flex items-start justify-between mb-3",
85
+ children: [/* @__PURE__ */ (0, h.jsxs)("div", { children: [/* @__PURE__ */ (0, h.jsx)("h3", {
86
+ className: "font-semibold text-[var(--gray-12)] text-lg",
87
+ children: t.name
88
+ }), t.description && /* @__PURE__ */ (0, h.jsx)("p", {
89
+ className: "text-sm text-[var(--gray-9)] mt-0.5 line-clamp-1",
90
+ children: t.description
91
+ })] }), !t.setup_complete && /* @__PURE__ */ (0, h.jsx)(o, {
92
+ variant: "soft",
93
+ color: "orange",
94
+ size: "1",
95
+ children: "Setup needed"
96
+ })]
97
+ }),
98
+ /* @__PURE__ */ (0, h.jsxs)("div", {
99
+ className: "flex items-center gap-3 flex-wrap mb-3",
100
+ children: [t.content_category && /* @__PURE__ */ (0, h.jsx)(o, {
101
+ variant: "soft",
102
+ color: "blue",
103
+ size: "1",
104
+ children: t.content_category
105
+ }), t.from_email && /* @__PURE__ */ (0, h.jsx)("span", {
106
+ className: "text-xs text-[var(--gray-9)]",
107
+ children: t.from_email
108
+ })]
109
+ }),
110
+ /* @__PURE__ */ (0, h.jsxs)("div", {
111
+ className: "grid grid-cols-3 gap-3 pt-3 border-t border-[var(--gray-a4)]",
112
+ children: [
113
+ /* @__PURE__ */ (0, h.jsxs)("div", {
114
+ className: "text-center",
115
+ children: [/* @__PURE__ */ (0, h.jsxs)("div", {
116
+ className: "flex items-center justify-center gap-1 text-[var(--gray-9)]",
117
+ children: [/* @__PURE__ */ (0, h.jsx)(m.DocumentTextIcon, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, h.jsx)("span", {
118
+ className: "text-sm font-medium text-[var(--gray-12)]",
119
+ children: t.edition_count
120
+ })]
121
+ }), /* @__PURE__ */ (0, h.jsx)("p", {
122
+ className: "text-[10px] text-[var(--gray-9)]",
123
+ children: "Editions"
124
+ })]
125
+ }),
126
+ /* @__PURE__ */ (0, h.jsxs)("div", {
127
+ className: "text-center",
128
+ children: [/* @__PURE__ */ (0, h.jsxs)("div", {
129
+ className: "flex items-center justify-center gap-1 text-[var(--gray-9)]",
130
+ children: [/* @__PURE__ */ (0, h.jsx)(m.UsersIcon, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, h.jsx)("span", {
131
+ className: "text-sm font-medium text-[var(--gray-12)]",
132
+ children: t.subscriber_count
133
+ })]
134
+ }), /* @__PURE__ */ (0, h.jsx)("p", {
135
+ className: "text-[10px] text-[var(--gray-9)]",
136
+ children: "Subscribers"
137
+ })]
138
+ }),
139
+ /* @__PURE__ */ (0, h.jsxs)("div", {
140
+ className: "text-center",
141
+ children: [/* @__PURE__ */ (0, h.jsxs)("div", {
142
+ className: "flex items-center justify-center gap-1 text-[var(--gray-9)]",
143
+ children: [/* @__PURE__ */ (0, h.jsx)(m.ChartBarIcon, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, h.jsx)("span", {
144
+ className: "text-sm font-medium text-[var(--gray-12)]",
145
+ children: "—"
146
+ })]
147
+ }), /* @__PURE__ */ (0, h.jsx)("p", {
148
+ className: "text-[10px] text-[var(--gray-9)]",
149
+ children: "Open rate"
150
+ })]
151
+ })
152
+ ]
153
+ })
154
+ ]
155
+ }, t.id))
156
+ })
157
+ }), /* @__PURE__ */ (0, h.jsx)(f, {
158
+ isOpen: _,
159
+ onClose: () => {
160
+ v(!1), y();
161
+ }
162
+ })]
163
+ });
164
+ }
165
+ //#endregion
166
+ export { g as default };
Binary file
Binary file