payload-plugin-newsletter 0.20.1 → 0.20.3

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/dist/client.cjs DELETED
@@ -1,891 +0,0 @@
1
- "use strict";
2
- "use client";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
-
21
- // src/exports/client.ts
22
- var client_exports = {};
23
- __export(client_exports, {
24
- MagicLinkVerify: () => MagicLinkVerify,
25
- NewsletterForm: () => NewsletterForm,
26
- PreferencesForm: () => PreferencesForm,
27
- createMagicLinkVerify: () => createMagicLinkVerify,
28
- createNewsletterForm: () => createNewsletterForm,
29
- createPreferencesForm: () => createPreferencesForm,
30
- useNewsletterAuth: () => useNewsletterAuth
31
- });
32
- module.exports = __toCommonJS(client_exports);
33
-
34
- // src/components/NewsletterForm.tsx
35
- var import_react = require("react");
36
- var import_jsx_runtime = require("react/jsx-runtime");
37
- var defaultStyles = {
38
- form: {
39
- display: "flex",
40
- flexDirection: "column",
41
- gap: "1rem",
42
- maxWidth: "400px",
43
- margin: "0 auto"
44
- },
45
- inputGroup: {
46
- display: "flex",
47
- flexDirection: "column",
48
- gap: "0.5rem"
49
- },
50
- label: {
51
- fontSize: "0.875rem",
52
- fontWeight: "500",
53
- color: "#374151"
54
- },
55
- input: {
56
- padding: "0.5rem 0.75rem",
57
- fontSize: "1rem",
58
- border: "1px solid #e5e7eb",
59
- borderRadius: "0.375rem",
60
- outline: "none",
61
- transition: "border-color 0.2s"
62
- },
63
- button: {
64
- padding: "0.75rem 1.5rem",
65
- fontSize: "1rem",
66
- fontWeight: "500",
67
- color: "#ffffff",
68
- backgroundColor: "#3b82f6",
69
- border: "none",
70
- borderRadius: "0.375rem",
71
- cursor: "pointer",
72
- transition: "background-color 0.2s"
73
- },
74
- buttonDisabled: {
75
- opacity: 0.5,
76
- cursor: "not-allowed"
77
- },
78
- error: {
79
- fontSize: "0.875rem",
80
- color: "#ef4444",
81
- marginTop: "0.25rem"
82
- },
83
- success: {
84
- fontSize: "0.875rem",
85
- color: "#10b981",
86
- marginTop: "0.25rem"
87
- },
88
- checkbox: {
89
- display: "flex",
90
- alignItems: "center",
91
- gap: "0.5rem"
92
- },
93
- checkboxInput: {
94
- width: "1rem",
95
- height: "1rem"
96
- },
97
- checkboxLabel: {
98
- fontSize: "0.875rem",
99
- color: "#374151"
100
- }
101
- };
102
- var NewsletterForm = ({
103
- onSuccess,
104
- onError,
105
- showName = false,
106
- showPreferences = false,
107
- leadMagnet,
108
- className,
109
- styles: customStyles = {},
110
- apiEndpoint = "/api/newsletter/subscribe",
111
- buttonText = "Subscribe",
112
- loadingText = "Subscribing...",
113
- successMessage = "Successfully subscribed!",
114
- placeholders = {
115
- email: "Enter your email",
116
- name: "Enter your name"
117
- },
118
- labels = {
119
- email: "Email",
120
- name: "Name",
121
- newsletter: "Newsletter updates",
122
- announcements: "Product announcements"
123
- }
124
- }) => {
125
- const [email, setEmail] = (0, import_react.useState)("");
126
- const [name, setName] = (0, import_react.useState)("");
127
- const [preferences, setPreferences] = (0, import_react.useState)({
128
- newsletter: true,
129
- announcements: true
130
- });
131
- const [loading, setLoading] = (0, import_react.useState)(false);
132
- const [error, setError] = (0, import_react.useState)(null);
133
- const [success, setSuccess] = (0, import_react.useState)(false);
134
- const styles = {
135
- form: { ...defaultStyles.form, ...customStyles.form },
136
- inputGroup: { ...defaultStyles.inputGroup, ...customStyles.inputGroup },
137
- label: { ...defaultStyles.label, ...customStyles.label },
138
- input: { ...defaultStyles.input, ...customStyles.input },
139
- button: { ...defaultStyles.button, ...customStyles.button },
140
- buttonDisabled: { ...defaultStyles.buttonDisabled, ...customStyles.buttonDisabled },
141
- error: { ...defaultStyles.error, ...customStyles.error },
142
- success: { ...defaultStyles.success, ...customStyles.success },
143
- checkbox: { ...defaultStyles.checkbox, ...customStyles.checkbox },
144
- checkboxInput: { ...defaultStyles.checkboxInput, ...customStyles.checkboxInput },
145
- checkboxLabel: { ...defaultStyles.checkboxLabel, ...customStyles.checkboxLabel }
146
- };
147
- const handleSubmit = async (e) => {
148
- e.preventDefault();
149
- setError(null);
150
- setLoading(true);
151
- try {
152
- const payload = {
153
- email,
154
- ...showName && name && { name },
155
- ...showPreferences && { preferences },
156
- ...leadMagnet && { leadMagnet: leadMagnet.id },
157
- metadata: {
158
- signupPage: window.location.href,
159
- ...typeof window !== "undefined" && window.location.search && {
160
- utmParams: Object.fromEntries(new URLSearchParams(window.location.search))
161
- }
162
- }
163
- };
164
- const response = await fetch(apiEndpoint, {
165
- method: "POST",
166
- headers: {
167
- "Content-Type": "application/json"
168
- },
169
- body: JSON.stringify(payload)
170
- });
171
- const data = await response.json();
172
- if (!response.ok) {
173
- throw new Error(data.error || data.errors?.join(", ") || "Subscription failed");
174
- }
175
- setSuccess(true);
176
- setEmail("");
177
- setName("");
178
- if (onSuccess) {
179
- onSuccess(data.subscriber);
180
- }
181
- } catch (err) {
182
- const errorMessage = err instanceof Error ? err.message : "An error occurred";
183
- setError(errorMessage);
184
- if (onError) {
185
- onError(new Error(errorMessage));
186
- }
187
- } finally {
188
- setLoading(false);
189
- }
190
- };
191
- if (success && !showPreferences) {
192
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: styles.form, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.success, children: successMessage }) });
193
- }
194
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: handleSubmit, className, style: styles.form, children: [
195
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.inputGroup, children: [
196
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "email", style: styles.label, children: labels.email }),
197
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
198
- "input",
199
- {
200
- id: "email",
201
- type: "email",
202
- value: email,
203
- onChange: (e) => setEmail(e.target.value),
204
- placeholder: placeholders.email,
205
- required: true,
206
- disabled: loading,
207
- style: {
208
- ...styles.input,
209
- ...loading && { opacity: 0.5 }
210
- }
211
- }
212
- )
213
- ] }),
214
- showName && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.inputGroup, children: [
215
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "name", style: styles.label, children: labels.name }),
216
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
217
- "input",
218
- {
219
- id: "name",
220
- type: "text",
221
- value: name,
222
- onChange: (e) => setName(e.target.value),
223
- placeholder: placeholders.name,
224
- disabled: loading,
225
- style: {
226
- ...styles.input,
227
- ...loading && { opacity: 0.5 }
228
- }
229
- }
230
- )
231
- ] }),
232
- showPreferences && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.inputGroup, children: [
233
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { style: styles.label, children: "Email Preferences" }),
234
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.checkbox, children: [
235
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
236
- "input",
237
- {
238
- id: "newsletter",
239
- type: "checkbox",
240
- checked: preferences.newsletter,
241
- onChange: (e) => setPreferences({ ...preferences, newsletter: e.target.checked }),
242
- disabled: loading,
243
- style: styles.checkboxInput
244
- }
245
- ),
246
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "newsletter", style: styles.checkboxLabel, children: labels.newsletter })
247
- ] }),
248
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.checkbox, children: [
249
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
250
- "input",
251
- {
252
- id: "announcements",
253
- type: "checkbox",
254
- checked: preferences.announcements,
255
- onChange: (e) => setPreferences({ ...preferences, announcements: e.target.checked }),
256
- disabled: loading,
257
- style: styles.checkboxInput
258
- }
259
- ),
260
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "announcements", style: styles.checkboxLabel, children: labels.announcements })
261
- ] })
262
- ] }),
263
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
264
- "button",
265
- {
266
- type: "submit",
267
- disabled: loading,
268
- style: {
269
- ...styles.button,
270
- ...loading && styles.buttonDisabled
271
- },
272
- children: loading ? loadingText : buttonText
273
- }
274
- ),
275
- error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.error, children: error }),
276
- success && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: styles.success, children: successMessage })
277
- ] });
278
- };
279
- function createNewsletterForm(defaultProps) {
280
- return (props) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NewsletterForm, { ...defaultProps, ...props });
281
- }
282
-
283
- // src/components/PreferencesForm.tsx
284
- var import_react2 = require("react");
285
- var import_jsx_runtime2 = require("react/jsx-runtime");
286
- var defaultStyles2 = {
287
- container: {
288
- maxWidth: "600px",
289
- margin: "0 auto",
290
- padding: "2rem"
291
- },
292
- heading: {
293
- fontSize: "1.5rem",
294
- fontWeight: "600",
295
- marginBottom: "1.5rem",
296
- color: "#111827"
297
- },
298
- form: {
299
- display: "flex",
300
- flexDirection: "column",
301
- gap: "1.5rem"
302
- },
303
- section: {
304
- padding: "1.5rem",
305
- backgroundColor: "#f9fafb",
306
- borderRadius: "0.5rem",
307
- border: "1px solid #e5e7eb"
308
- },
309
- sectionTitle: {
310
- fontSize: "1.125rem",
311
- fontWeight: "500",
312
- marginBottom: "1rem",
313
- color: "#111827"
314
- },
315
- inputGroup: {
316
- display: "flex",
317
- flexDirection: "column",
318
- gap: "0.5rem"
319
- },
320
- label: {
321
- fontSize: "0.875rem",
322
- fontWeight: "500",
323
- color: "#374151"
324
- },
325
- input: {
326
- padding: "0.5rem 0.75rem",
327
- fontSize: "1rem",
328
- border: "1px solid #e5e7eb",
329
- borderRadius: "0.375rem",
330
- outline: "none",
331
- transition: "border-color 0.2s"
332
- },
333
- select: {
334
- padding: "0.5rem 0.75rem",
335
- fontSize: "1rem",
336
- border: "1px solid #e5e7eb",
337
- borderRadius: "0.375rem",
338
- outline: "none",
339
- backgroundColor: "#ffffff"
340
- },
341
- checkbox: {
342
- display: "flex",
343
- alignItems: "center",
344
- gap: "0.5rem",
345
- marginBottom: "0.5rem"
346
- },
347
- checkboxInput: {
348
- width: "1rem",
349
- height: "1rem"
350
- },
351
- checkboxLabel: {
352
- fontSize: "0.875rem",
353
- color: "#374151"
354
- },
355
- buttonGroup: {
356
- display: "flex",
357
- gap: "1rem",
358
- marginTop: "1rem"
359
- },
360
- button: {
361
- padding: "0.75rem 1.5rem",
362
- fontSize: "1rem",
363
- fontWeight: "500",
364
- borderRadius: "0.375rem",
365
- cursor: "pointer",
366
- transition: "all 0.2s",
367
- border: "none"
368
- },
369
- primaryButton: {
370
- color: "#ffffff",
371
- backgroundColor: "#3b82f6"
372
- },
373
- secondaryButton: {
374
- color: "#374151",
375
- backgroundColor: "#ffffff",
376
- border: "1px solid #e5e7eb"
377
- },
378
- dangerButton: {
379
- color: "#ffffff",
380
- backgroundColor: "#ef4444"
381
- },
382
- error: {
383
- fontSize: "0.875rem",
384
- color: "#ef4444",
385
- marginTop: "0.5rem"
386
- },
387
- success: {
388
- fontSize: "0.875rem",
389
- color: "#10b981",
390
- marginTop: "0.5rem"
391
- },
392
- info: {
393
- fontSize: "0.875rem",
394
- color: "#6b7280",
395
- marginTop: "0.5rem"
396
- }
397
- };
398
- var PreferencesForm = ({
399
- subscriber: initialSubscriber,
400
- onSuccess,
401
- onError,
402
- className,
403
- styles: customStyles = {},
404
- sessionToken,
405
- apiEndpoint = "/api/newsletter/preferences",
406
- showUnsubscribe = true,
407
- locales = ["en"],
408
- labels = {
409
- title: "Newsletter Preferences",
410
- personalInfo: "Personal Information",
411
- emailPreferences: "Email Preferences",
412
- name: "Name",
413
- language: "Preferred Language",
414
- newsletter: "Newsletter updates",
415
- announcements: "Product announcements",
416
- saveButton: "Save Preferences",
417
- unsubscribeButton: "Unsubscribe",
418
- saving: "Saving...",
419
- saved: "Preferences saved successfully!",
420
- unsubscribeConfirm: "Are you sure you want to unsubscribe? This cannot be undone."
421
- }
422
- }) => {
423
- const [subscriber, setSubscriber] = (0, import_react2.useState)(initialSubscriber || {});
424
- const [loading, setLoading] = (0, import_react2.useState)(false);
425
- const [loadingData, setLoadingData] = (0, import_react2.useState)(!initialSubscriber);
426
- const [error, setError] = (0, import_react2.useState)(null);
427
- const [success, setSuccess] = (0, import_react2.useState)(false);
428
- const styles = {
429
- container: { ...defaultStyles2.container, ...customStyles.container },
430
- heading: { ...defaultStyles2.heading, ...customStyles.heading },
431
- form: { ...defaultStyles2.form, ...customStyles.form },
432
- section: { ...defaultStyles2.section, ...customStyles.section },
433
- sectionTitle: { ...defaultStyles2.sectionTitle, ...customStyles.sectionTitle },
434
- inputGroup: { ...defaultStyles2.inputGroup, ...customStyles.inputGroup },
435
- label: { ...defaultStyles2.label, ...customStyles.label },
436
- input: { ...defaultStyles2.input, ...customStyles.input },
437
- select: { ...defaultStyles2.select, ...customStyles.select },
438
- checkbox: { ...defaultStyles2.checkbox, ...customStyles.checkbox },
439
- checkboxInput: { ...defaultStyles2.checkboxInput, ...customStyles.checkboxInput },
440
- checkboxLabel: { ...defaultStyles2.checkboxLabel, ...customStyles.checkboxLabel },
441
- buttonGroup: { ...defaultStyles2.buttonGroup, ...customStyles.buttonGroup },
442
- button: { ...defaultStyles2.button, ...customStyles.button },
443
- primaryButton: { ...defaultStyles2.primaryButton, ...customStyles.primaryButton },
444
- secondaryButton: { ...defaultStyles2.secondaryButton, ...customStyles.secondaryButton },
445
- dangerButton: { ...defaultStyles2.dangerButton, ...customStyles.dangerButton },
446
- error: { ...defaultStyles2.error, ...customStyles.error },
447
- success: { ...defaultStyles2.success, ...customStyles.success },
448
- info: { ...defaultStyles2.info, ...customStyles.info }
449
- };
450
- (0, import_react2.useEffect)(() => {
451
- if (!initialSubscriber && sessionToken) {
452
- fetchPreferences();
453
- }
454
- }, []);
455
- const fetchPreferences = async () => {
456
- try {
457
- const response = await fetch(apiEndpoint, {
458
- headers: {
459
- "Authorization": `Bearer ${sessionToken}`
460
- }
461
- });
462
- if (!response.ok) {
463
- throw new Error("Failed to load preferences");
464
- }
465
- const data = await response.json();
466
- setSubscriber(data.subscriber);
467
- } catch (err) {
468
- setError(err instanceof Error ? err.message : "Failed to load preferences");
469
- if (onError) {
470
- onError(err instanceof Error ? err : new Error("Failed to load preferences"));
471
- }
472
- } finally {
473
- setLoadingData(false);
474
- }
475
- };
476
- const handleSave = async (e) => {
477
- e.preventDefault();
478
- setError(null);
479
- setSuccess(false);
480
- setLoading(true);
481
- try {
482
- const response = await fetch(apiEndpoint, {
483
- method: "POST",
484
- headers: {
485
- "Content-Type": "application/json",
486
- "Authorization": `Bearer ${sessionToken}`
487
- },
488
- body: JSON.stringify({
489
- name: subscriber.name,
490
- locale: subscriber.locale,
491
- emailPreferences: subscriber.emailPreferences
492
- })
493
- });
494
- const data = await response.json();
495
- if (!response.ok) {
496
- throw new Error(data.error || "Failed to save preferences");
497
- }
498
- setSubscriber(data.subscriber);
499
- setSuccess(true);
500
- if (onSuccess) {
501
- onSuccess(data.subscriber);
502
- }
503
- } catch (err) {
504
- const errorMessage = err instanceof Error ? err.message : "An error occurred";
505
- setError(errorMessage);
506
- if (onError) {
507
- onError(new Error(errorMessage));
508
- }
509
- } finally {
510
- setLoading(false);
511
- }
512
- };
513
- const handleUnsubscribe = async () => {
514
- if (!window.confirm(labels.unsubscribeConfirm)) {
515
- return;
516
- }
517
- setLoading(true);
518
- setError(null);
519
- try {
520
- const response = await fetch("/api/newsletter/unsubscribe", {
521
- method: "POST",
522
- headers: {
523
- "Content-Type": "application/json",
524
- "Authorization": `Bearer ${sessionToken}`
525
- },
526
- body: JSON.stringify({
527
- email: subscriber.email
528
- })
529
- });
530
- if (!response.ok) {
531
- throw new Error("Failed to unsubscribe");
532
- }
533
- setSubscriber({ ...subscriber, subscriptionStatus: "unsubscribed" });
534
- if (onSuccess) {
535
- onSuccess({ ...subscriber, subscriptionStatus: "unsubscribed" });
536
- }
537
- } catch (err) {
538
- setError("Failed to unsubscribe. Please try again.");
539
- if (onError) {
540
- onError(err instanceof Error ? err : new Error("Failed to unsubscribe"));
541
- }
542
- } finally {
543
- setLoading(false);
544
- }
545
- };
546
- if (loadingData) {
547
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className, style: styles.container, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.info, children: "Loading preferences..." }) });
548
- }
549
- if (subscriber.subscriptionStatus === "unsubscribed") {
550
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className, style: styles.container, children: [
551
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: styles.heading, children: "Unsubscribed" }),
552
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.info, children: "You have been unsubscribed from all emails. To resubscribe, please sign up again." })
553
- ] });
554
- }
555
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className, style: styles.container, children: [
556
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: styles.heading, children: labels.title }),
557
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSave, style: styles.form, children: [
558
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.section, children: [
559
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: styles.sectionTitle, children: labels.personalInfo }),
560
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.inputGroup, children: [
561
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "name", style: styles.label, children: labels.name }),
562
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
563
- "input",
564
- {
565
- id: "name",
566
- type: "text",
567
- value: subscriber.name || "",
568
- onChange: (e) => setSubscriber({ ...subscriber, name: e.target.value }),
569
- disabled: loading,
570
- style: styles.input
571
- }
572
- )
573
- ] }),
574
- locales.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.inputGroup, children: [
575
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "locale", style: styles.label, children: labels.language }),
576
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
577
- "select",
578
- {
579
- id: "locale",
580
- value: subscriber.locale || locales[0],
581
- onChange: (e) => setSubscriber({ ...subscriber, locale: e.target.value }),
582
- disabled: loading,
583
- style: styles.select,
584
- children: locales.map((locale) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: locale, children: locale.toUpperCase() }, locale))
585
- }
586
- )
587
- ] })
588
- ] }),
589
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.section, children: [
590
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: styles.sectionTitle, children: labels.emailPreferences }),
591
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.checkbox, children: [
592
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
593
- "input",
594
- {
595
- id: "pref-newsletter",
596
- type: "checkbox",
597
- checked: subscriber.emailPreferences?.newsletter ?? true,
598
- onChange: (e) => setSubscriber({
599
- ...subscriber,
600
- emailPreferences: {
601
- ...subscriber.emailPreferences,
602
- newsletter: e.target.checked
603
- }
604
- }),
605
- disabled: loading,
606
- style: styles.checkboxInput
607
- }
608
- ),
609
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "pref-newsletter", style: styles.checkboxLabel, children: labels.newsletter })
610
- ] }),
611
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.checkbox, children: [
612
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
613
- "input",
614
- {
615
- id: "pref-announcements",
616
- type: "checkbox",
617
- checked: subscriber.emailPreferences?.announcements ?? true,
618
- onChange: (e) => setSubscriber({
619
- ...subscriber,
620
- emailPreferences: {
621
- ...subscriber.emailPreferences,
622
- announcements: e.target.checked
623
- }
624
- }),
625
- disabled: loading,
626
- style: styles.checkboxInput
627
- }
628
- ),
629
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "pref-announcements", style: styles.checkboxLabel, children: labels.announcements })
630
- ] })
631
- ] }),
632
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.buttonGroup, children: [
633
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
634
- "button",
635
- {
636
- type: "submit",
637
- disabled: loading,
638
- style: {
639
- ...styles.button,
640
- ...styles.primaryButton,
641
- ...loading && { opacity: 0.5, cursor: "not-allowed" }
642
- },
643
- children: loading ? labels.saving : labels.saveButton
644
- }
645
- ),
646
- showUnsubscribe && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
647
- "button",
648
- {
649
- type: "button",
650
- onClick: handleUnsubscribe,
651
- disabled: loading,
652
- style: {
653
- ...styles.button,
654
- ...styles.dangerButton,
655
- ...loading && { opacity: 0.5, cursor: "not-allowed" }
656
- },
657
- children: labels.unsubscribeButton
658
- }
659
- )
660
- ] }),
661
- error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.error, children: error }),
662
- success && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: styles.success, children: labels.saved })
663
- ] })
664
- ] });
665
- };
666
- function createPreferencesForm(defaultProps) {
667
- return (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PreferencesForm, { ...defaultProps, ...props });
668
- }
669
-
670
- // src/components/MagicLinkVerify.tsx
671
- var import_react3 = require("react");
672
- var import_jsx_runtime3 = require("react/jsx-runtime");
673
- var defaultStyles3 = {
674
- container: {
675
- maxWidth: "400px",
676
- margin: "4rem auto",
677
- padding: "2rem",
678
- textAlign: "center"
679
- },
680
- heading: {
681
- fontSize: "1.5rem",
682
- fontWeight: "600",
683
- marginBottom: "1rem",
684
- color: "#111827"
685
- },
686
- message: {
687
- fontSize: "1rem",
688
- color: "#6b7280",
689
- marginBottom: "1.5rem"
690
- },
691
- error: {
692
- fontSize: "1rem",
693
- color: "#ef4444",
694
- marginBottom: "1.5rem"
695
- },
696
- button: {
697
- padding: "0.75rem 1.5rem",
698
- fontSize: "1rem",
699
- fontWeight: "500",
700
- color: "#ffffff",
701
- backgroundColor: "#3b82f6",
702
- border: "none",
703
- borderRadius: "0.375rem",
704
- cursor: "pointer",
705
- transition: "background-color 0.2s"
706
- }
707
- };
708
- var MagicLinkVerify = ({
709
- token: propToken,
710
- onSuccess,
711
- onError,
712
- apiEndpoint = "/api/newsletter/verify-magic-link",
713
- className,
714
- styles: customStyles = {},
715
- labels = {
716
- verifying: "Verifying your magic link...",
717
- success: "Successfully verified! Redirecting...",
718
- error: "Failed to verify magic link",
719
- expired: "This magic link has expired. Please request a new one.",
720
- invalid: "This magic link is invalid. Please request a new one.",
721
- redirecting: "Redirecting to your preferences...",
722
- tryAgain: "Try Again"
723
- }
724
- }) => {
725
- const [status, setStatus] = (0, import_react3.useState)("verifying");
726
- const [error, setError] = (0, import_react3.useState)(null);
727
- const [_sessionToken, setSessionToken] = (0, import_react3.useState)(null);
728
- const styles = {
729
- container: { ...defaultStyles3.container, ...customStyles.container },
730
- heading: { ...defaultStyles3.heading, ...customStyles.heading },
731
- message: { ...defaultStyles3.message, ...customStyles.message },
732
- error: { ...defaultStyles3.error, ...customStyles.error },
733
- button: { ...defaultStyles3.button, ...customStyles.button }
734
- };
735
- (0, import_react3.useEffect)(() => {
736
- const token = propToken || new URLSearchParams(window.location.search).get("token");
737
- if (token) {
738
- verifyToken(token);
739
- } else {
740
- setStatus("error");
741
- setError(labels.invalid || "Invalid magic link");
742
- }
743
- }, [propToken]);
744
- const verifyToken = async (token) => {
745
- try {
746
- const response = await fetch(apiEndpoint, {
747
- method: "POST",
748
- headers: {
749
- "Content-Type": "application/json"
750
- },
751
- body: JSON.stringify({ token })
752
- });
753
- const data = await response.json();
754
- if (!response.ok) {
755
- if (data.error?.includes("expired")) {
756
- throw new Error(labels.expired);
757
- }
758
- throw new Error(data.error || labels.error);
759
- }
760
- setStatus("success");
761
- setSessionToken(data.sessionToken);
762
- if (typeof window !== "undefined" && data.sessionToken) {
763
- localStorage.setItem("newsletter_session", data.sessionToken);
764
- }
765
- if (onSuccess) {
766
- onSuccess(data.sessionToken, data.subscriber);
767
- }
768
- } catch (err) {
769
- setStatus("error");
770
- const errorMessage = err instanceof Error ? err.message : labels.error || "Verification failed";
771
- setError(errorMessage);
772
- if (onError) {
773
- onError(err instanceof Error ? err : new Error(errorMessage));
774
- }
775
- }
776
- };
777
- const handleTryAgain = () => {
778
- window.location.href = "/";
779
- };
780
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, style: styles.container, children: [
781
- status === "verifying" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
782
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: styles.heading, children: "Verifying" }),
783
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: styles.message, children: labels.verifying })
784
- ] }),
785
- status === "success" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
786
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: styles.heading, children: "Success!" }),
787
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: styles.message, children: labels.success })
788
- ] }),
789
- status === "error" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
790
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { style: styles.heading, children: "Verification Failed" }),
791
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: styles.error, children: error }),
792
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { onClick: handleTryAgain, style: styles.button, children: labels.tryAgain })
793
- ] })
794
- ] });
795
- };
796
- function createMagicLinkVerify(defaultProps) {
797
- return (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MagicLinkVerify, { ...defaultProps, ...props });
798
- }
799
-
800
- // src/hooks/useNewsletterAuth.ts
801
- var import_react4 = require("react");
802
- function useNewsletterAuth(_options = {}) {
803
- const [subscriber, setSubscriber] = (0, import_react4.useState)(null);
804
- const [isLoading, setIsLoading] = (0, import_react4.useState)(true);
805
- const [error, setError] = (0, import_react4.useState)(null);
806
- const checkAuth = (0, import_react4.useCallback)(async () => {
807
- try {
808
- const response = await fetch("/api/newsletter/me", {
809
- method: "GET",
810
- credentials: "include",
811
- headers: {
812
- "Content-Type": "application/json"
813
- }
814
- });
815
- if (response.ok) {
816
- const data = await response.json();
817
- setSubscriber(data.subscriber);
818
- setError(null);
819
- } else {
820
- setSubscriber(null);
821
- if (response.status !== 401) {
822
- setError(new Error("Failed to check authentication"));
823
- }
824
- }
825
- } catch (err) {
826
- console.error("Auth check failed:", err);
827
- setError(err instanceof Error ? err : new Error("An error occurred"));
828
- setSubscriber(null);
829
- } finally {
830
- setIsLoading(false);
831
- }
832
- }, []);
833
- (0, import_react4.useEffect)(() => {
834
- checkAuth();
835
- }, [checkAuth]);
836
- const signOut = (0, import_react4.useCallback)(async () => {
837
- try {
838
- const response = await fetch("/api/newsletter/signout", {
839
- method: "POST",
840
- credentials: "include",
841
- headers: {
842
- "Content-Type": "application/json"
843
- }
844
- });
845
- if (response.ok) {
846
- setSubscriber(null);
847
- setError(null);
848
- } else {
849
- throw new Error("Failed to sign out");
850
- }
851
- } catch (err) {
852
- console.error("Sign out error:", err);
853
- setError(err instanceof Error ? err : new Error("Sign out failed"));
854
- throw err;
855
- }
856
- }, []);
857
- const refreshAuth = (0, import_react4.useCallback)(async () => {
858
- setIsLoading(true);
859
- await checkAuth();
860
- }, [checkAuth]);
861
- const login = (0, import_react4.useCallback)(async (_token) => {
862
- await refreshAuth();
863
- }, [refreshAuth]);
864
- return {
865
- subscriber,
866
- isAuthenticated: !!subscriber,
867
- isLoading,
868
- loading: isLoading,
869
- // Alias for backward compatibility
870
- error,
871
- signOut,
872
- logout: signOut,
873
- // Alias for backward compatibility
874
- refreshAuth,
875
- refreshSubscriber: refreshAuth,
876
- // Alias for backward compatibility
877
- login
878
- // For backward compatibility
879
- };
880
- }
881
- // Annotate the CommonJS export names for ESM import in node:
882
- 0 && (module.exports = {
883
- MagicLinkVerify,
884
- NewsletterForm,
885
- PreferencesForm,
886
- createMagicLinkVerify,
887
- createNewsletterForm,
888
- createPreferencesForm,
889
- useNewsletterAuth
890
- });
891
- //# sourceMappingURL=client.cjs.map