@burdenoff/website-sdk 2026.1031.3 → 2026.1101.2
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/README.md +42 -8
- package/dist/analytics/index.js +19 -69
- package/dist/analytics/index.js.map +1 -1
- package/dist/analytics/index.mjs +3 -69
- package/dist/analytics/index.mjs.map +1 -1
- package/dist/avatar-live/index.js +1 -0
- package/dist/avatar-live/index.js.map +1 -1
- package/dist/avatar-live/index.mjs +1 -0
- package/dist/avatar-live/index.mjs.map +1 -1
- package/dist/avatar-live-view/index.js +10 -30
- package/dist/avatar-live-view/index.js.map +1 -1
- package/dist/avatar-live-view/index.mjs +4 -24
- package/dist/avatar-live-view/index.mjs.map +1 -1
- package/dist/chunk-23H4JUL4.js +41 -0
- package/dist/chunk-23H4JUL4.js.map +1 -0
- package/dist/chunk-34RX5P75.mjs +25 -0
- package/dist/chunk-34RX5P75.mjs.map +1 -0
- package/dist/chunk-3LFFY7AZ.js +184 -0
- package/dist/chunk-3LFFY7AZ.js.map +1 -0
- package/dist/chunk-3X26GE4S.js +2794 -0
- package/dist/chunk-3X26GE4S.js.map +1 -0
- package/dist/chunk-45GCA4GG.js +85 -0
- package/dist/chunk-45GCA4GG.js.map +1 -0
- package/dist/chunk-4SAGVLHN.js +876 -0
- package/dist/chunk-4SAGVLHN.js.map +1 -0
- package/dist/chunk-4U6YAII5.js +218 -0
- package/dist/chunk-4U6YAII5.js.map +1 -0
- package/dist/chunk-5GMTBOO6.js +21 -0
- package/dist/chunk-5GMTBOO6.js.map +1 -0
- package/dist/chunk-5JRJ57CL.mjs +329 -0
- package/dist/chunk-5JRJ57CL.mjs.map +1 -0
- package/dist/chunk-6C2DKIC7.js +4 -0
- package/dist/chunk-6C2DKIC7.js.map +1 -0
- package/dist/chunk-6IBFBWC5.mjs +17 -0
- package/dist/chunk-6IBFBWC5.mjs.map +1 -0
- package/dist/chunk-6KY2ZRVI.js +116 -0
- package/dist/chunk-6KY2ZRVI.js.map +1 -0
- package/dist/chunk-6VJT3SM4.mjs +182 -0
- package/dist/chunk-6VJT3SM4.mjs.map +1 -0
- package/dist/chunk-6YZUFMK2.mjs +40 -0
- package/dist/chunk-6YZUFMK2.mjs.map +1 -0
- package/dist/chunk-7A6R7CGG.js +47 -0
- package/dist/chunk-7A6R7CGG.js.map +1 -0
- package/dist/chunk-7PWL4V2R.js +4 -0
- package/dist/chunk-7PWL4V2R.js.map +1 -0
- package/dist/chunk-AA33WDYS.js +161 -0
- package/dist/chunk-AA33WDYS.js.map +1 -0
- package/dist/chunk-AHRGFXV2.js +525 -0
- package/dist/chunk-AHRGFXV2.js.map +1 -0
- package/dist/chunk-B63XLDZH.mjs +109 -0
- package/dist/chunk-B63XLDZH.mjs.map +1 -0
- package/dist/chunk-BX2USEWF.mjs +35 -0
- package/dist/chunk-BX2USEWF.mjs.map +1 -0
- package/dist/chunk-BYSZT35R.js +150 -0
- package/dist/chunk-BYSZT35R.js.map +1 -0
- package/dist/chunk-C6OJIHNO.js +12 -0
- package/dist/chunk-C6OJIHNO.js.map +1 -0
- package/dist/chunk-COOELBX7.mjs +63 -0
- package/dist/chunk-COOELBX7.mjs.map +1 -0
- package/dist/chunk-D2TW7MNC.mjs +2771 -0
- package/dist/chunk-D2TW7MNC.mjs.map +1 -0
- package/dist/chunk-D5KEZ6V6.mjs +3 -0
- package/dist/chunk-D5KEZ6V6.mjs.map +1 -0
- package/dist/chunk-E3GUGJMY.js +46 -0
- package/dist/chunk-E3GUGJMY.js.map +1 -0
- package/dist/chunk-EBZ2HGJ2.mjs +52 -0
- package/dist/chunk-EBZ2HGJ2.mjs.map +1 -0
- package/dist/chunk-EDLTUOIA.mjs +210 -0
- package/dist/chunk-EDLTUOIA.mjs.map +1 -0
- package/dist/chunk-EJQSOT4X.js +4 -0
- package/dist/chunk-EJQSOT4X.js.map +1 -0
- package/dist/chunk-EUPFS6MZ.mjs +2019 -0
- package/dist/chunk-EUPFS6MZ.mjs.map +1 -0
- package/dist/chunk-F3XWDC3B.js +77 -0
- package/dist/chunk-F3XWDC3B.js.map +1 -0
- package/dist/chunk-FFADMVIK.mjs +5127 -0
- package/dist/chunk-FFADMVIK.mjs.map +1 -0
- package/dist/chunk-FJWS7BKT.mjs +3 -0
- package/dist/chunk-FJWS7BKT.mjs.map +1 -0
- package/dist/chunk-FJZJDUOR.mjs +3 -0
- package/dist/chunk-FJZJDUOR.mjs.map +1 -0
- package/dist/chunk-GCFLCO2Z.mjs +145 -0
- package/dist/chunk-GCFLCO2Z.mjs.map +1 -0
- package/dist/chunk-GEXC4LRP.js +61 -0
- package/dist/chunk-GEXC4LRP.js.map +1 -0
- package/dist/chunk-GTRAXQGC.mjs +3 -0
- package/dist/chunk-GTRAXQGC.mjs.map +1 -0
- package/dist/chunk-IKOIRUKW.js +270 -0
- package/dist/chunk-IKOIRUKW.js.map +1 -0
- package/dist/chunk-IXTWOPRN.js +45 -0
- package/dist/chunk-IXTWOPRN.js.map +1 -0
- package/dist/chunk-JDXOXGOK.js +547 -0
- package/dist/chunk-JDXOXGOK.js.map +1 -0
- package/dist/chunk-JSLDWYV7.mjs +558 -0
- package/dist/chunk-JSLDWYV7.mjs.map +1 -0
- package/dist/chunk-JXLSTVBK.js +336 -0
- package/dist/chunk-JXLSTVBK.js.map +1 -0
- package/dist/chunk-KHYXK7FG.mjs +49 -0
- package/dist/chunk-KHYXK7FG.mjs.map +1 -0
- package/dist/chunk-KSMBOWQQ.js +2034 -0
- package/dist/chunk-KSMBOWQQ.js.map +1 -0
- package/dist/chunk-KU2PXHGB.mjs +83 -0
- package/dist/chunk-KU2PXHGB.mjs.map +1 -0
- package/dist/chunk-KZANIV3S.mjs +37 -0
- package/dist/chunk-KZANIV3S.mjs.map +1 -0
- package/dist/chunk-L4BP6YOB.js +20 -0
- package/dist/chunk-L4BP6YOB.js.map +1 -0
- package/dist/chunk-MRKA2OAF.mjs +75 -0
- package/dist/chunk-MRKA2OAF.mjs.map +1 -0
- package/dist/chunk-N5EC53MH.mjs +80 -0
- package/dist/chunk-N5EC53MH.mjs.map +1 -0
- package/dist/chunk-NZANQGDM.mjs +34 -0
- package/dist/chunk-NZANQGDM.mjs.map +1 -0
- package/dist/chunk-O4GS3XPZ.js +10 -0
- package/dist/chunk-O4GS3XPZ.js.map +1 -0
- package/dist/chunk-O76QDGRM.js +5154 -0
- package/dist/chunk-O76QDGRM.js.map +1 -0
- package/dist/chunk-OYEUNZJY.js +114 -0
- package/dist/chunk-OYEUNZJY.js.map +1 -0
- package/dist/chunk-PHXAGQNB.js +74 -0
- package/dist/chunk-PHXAGQNB.js.map +1 -0
- package/dist/chunk-PIHHPP7J.mjs +16 -0
- package/dist/chunk-PIHHPP7J.mjs.map +1 -0
- package/dist/chunk-PXRHVVOU.mjs +499 -0
- package/dist/chunk-PXRHVVOU.mjs.map +1 -0
- package/dist/chunk-QMA6U6AU.js +36 -0
- package/dist/chunk-QMA6U6AU.js.map +1 -0
- package/dist/chunk-R6J7IULF.js +44 -0
- package/dist/chunk-R6J7IULF.js.map +1 -0
- package/dist/chunk-R7G6TWIS.mjs +10 -0
- package/dist/chunk-R7G6TWIS.mjs.map +1 -0
- package/dist/chunk-RUMGFI6L.mjs +544 -0
- package/dist/chunk-RUMGFI6L.mjs.map +1 -0
- package/dist/chunk-S54JWSJF.js +565 -0
- package/dist/chunk-S54JWSJF.js.map +1 -0
- package/dist/chunk-SK5UGG6A.js +2041 -0
- package/dist/chunk-SK5UGG6A.js.map +1 -0
- package/dist/chunk-SKIYDKIS.mjs +70 -0
- package/dist/chunk-SKIYDKIS.mjs.map +1 -0
- package/dist/chunk-SZNS5IK6.mjs +322 -0
- package/dist/chunk-SZNS5IK6.mjs.map +1 -0
- package/dist/chunk-T7JIPZAC.js +66 -0
- package/dist/chunk-T7JIPZAC.js.map +1 -0
- package/dist/chunk-TGYQHO2E.mjs +864 -0
- package/dist/chunk-TGYQHO2E.mjs.map +1 -0
- package/dist/chunk-TT3MHN42.mjs +8 -0
- package/dist/chunk-TT3MHN42.mjs.map +1 -0
- package/dist/chunk-UM55U65W.mjs +268 -0
- package/dist/chunk-UM55U65W.mjs.map +1 -0
- package/dist/chunk-UQ2HALUD.js +72 -0
- package/dist/chunk-UQ2HALUD.js.map +1 -0
- package/dist/chunk-UXWT7G77.js +82 -0
- package/dist/chunk-UXWT7G77.js.map +1 -0
- package/dist/chunk-VNS5WDWO.mjs +7 -0
- package/dist/chunk-VNS5WDWO.mjs.map +1 -0
- package/dist/chunk-VRWZLGR7.js +4 -0
- package/dist/chunk-VRWZLGR7.js.map +1 -0
- package/dist/chunk-VZLDSNH4.mjs +22 -0
- package/dist/chunk-VZLDSNH4.mjs.map +1 -0
- package/dist/chunk-W6P3YETJ.js +92 -0
- package/dist/chunk-W6P3YETJ.js.map +1 -0
- package/dist/chunk-WPKFFQCR.mjs +90 -0
- package/dist/chunk-WPKFFQCR.mjs.map +1 -0
- package/dist/chunk-WTVTI5TO.mjs +22 -0
- package/dist/chunk-WTVTI5TO.mjs.map +1 -0
- package/dist/chunk-XJOBZ4RJ.js +44 -0
- package/dist/chunk-XJOBZ4RJ.js.map +1 -0
- package/dist/chunk-XP2JDNDU.js +325 -0
- package/dist/chunk-XP2JDNDU.js.map +1 -0
- package/dist/chunk-Y4V5CEWD.mjs +112 -0
- package/dist/chunk-Y4V5CEWD.mjs.map +1 -0
- package/dist/chunk-YERN2UWM.js +116 -0
- package/dist/chunk-YERN2UWM.js.map +1 -0
- package/dist/chunk-ZKJQWFAA.mjs +114 -0
- package/dist/chunk-ZKJQWFAA.mjs.map +1 -0
- package/dist/chunk-ZOON3S3Y.mjs +138 -0
- package/dist/chunk-ZOON3S3Y.mjs.map +1 -0
- package/dist/chunk-ZP6QRAYC.mjs +2024 -0
- package/dist/chunk-ZP6QRAYC.mjs.map +1 -0
- package/dist/chunk-ZSTFX7FV.js +9 -0
- package/dist/chunk-ZSTFX7FV.js.map +1 -0
- package/dist/client/index.js +23 -331
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +3 -330
- package/dist/client/index.mjs.map +1 -1
- package/dist/comparison/index.js +28 -111
- package/dist/comparison/index.js.map +1 -1
- package/dist/comparison/index.mjs +2 -107
- package/dist/comparison/index.mjs.map +1 -1
- package/dist/components/contact.js +21 -931
- package/dist/components/contact.js.map +1 -1
- package/dist/components/contact.mjs +12 -909
- package/dist/components/contact.mjs.map +1 -1
- package/dist/components/electron-download.js +12 -124
- package/dist/components/electron-download.js.map +1 -1
- package/dist/components/electron-download.mjs +4 -106
- package/dist/components/electron-download.mjs.map +1 -1
- package/dist/components/explore-cta.js +8 -112
- package/dist/components/explore-cta.js.map +1 -1
- package/dist/components/explore-cta.mjs +3 -114
- package/dist/components/explore-cta.mjs.map +1 -1
- package/dist/components/explore.js +62 -7833
- package/dist/components/explore.js.map +1 -1
- package/dist/components/explore.mjs +13 -7800
- package/dist/components/explore.mjs.map +1 -1
- package/dist/components/launch-countdown.js +8 -83
- package/dist/components/launch-countdown.js.map +1 -1
- package/dist/components/launch-countdown.mjs +3 -85
- package/dist/components/launch-countdown.mjs.map +1 -1
- package/dist/components/newsletter.js +20 -993
- package/dist/components/newsletter.js.map +1 -1
- package/dist/components/newsletter.mjs +11 -971
- package/dist/components/newsletter.mjs.map +1 -1
- package/dist/components/partners.js +24 -1302
- package/dist/components/partners.js.map +1 -1
- package/dist/components/partners.mjs +15 -1276
- package/dist/components/partners.mjs.map +1 -1
- package/dist/components/pricing.js +49 -1249
- package/dist/components/pricing.js.map +1 -1
- package/dist/components/pricing.mjs +8 -1226
- package/dist/components/pricing.mjs.map +1 -1
- package/dist/components/problems-solved.js +8 -150
- package/dist/components/problems-solved.js.map +1 -1
- package/dist/components/problems-solved.mjs +4 -133
- package/dist/components/problems-solved.mjs.map +1 -1
- package/dist/components/resource-links.js +8 -304
- package/dist/components/resource-links.js.map +1 -1
- package/dist/components/resource-links.mjs +5 -308
- package/dist/components/resource-links.mjs.map +1 -1
- package/dist/components/social-links.js +8 -343
- package/dist/components/social-links.js.map +1 -1
- package/dist/components/social-links.mjs +5 -347
- package/dist/components/social-links.mjs.map +1 -1
- package/dist/components/unsubscribe.js +10 -627
- package/dist/components/unsubscribe.js.map +1 -1
- package/dist/components/unsubscribe.mjs +6 -611
- package/dist/components/unsubscribe.mjs.map +1 -1
- package/dist/components/waitlist.js +21 -1001
- package/dist/components/waitlist.js.map +1 -1
- package/dist/components/waitlist.mjs +12 -982
- package/dist/components/waitlist.mjs.map +1 -1
- package/dist/components/website-switcher.js +12 -175
- package/dist/components/website-switcher.js.map +1 -1
- package/dist/components/website-switcher.mjs +4 -157
- package/dist/components/website-switcher.mjs.map +1 -1
- package/dist/content/index.js +118 -3616
- package/dist/content/index.js.map +1 -1
- package/dist/content/index.mjs +12 -3567
- package/dist/content/index.mjs.map +1 -1
- package/dist/hooks/index.js +37 -2321
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +6 -2318
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.js +4145 -20599
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3766 -20567
- package/dist/index.mjs.map +1 -1
- package/dist/product/index.js +20 -393
- package/dist/product/index.js.map +1 -1
- package/dist/product/index.mjs +5 -394
- package/dist/product/index.mjs.map +1 -1
- package/dist/seo/index.js +8 -76
- package/dist/seo/index.js.map +1 -1
- package/dist/seo/index.mjs +3 -78
- package/dist/seo/index.mjs.map +1 -1
- package/dist/store/index.js +51 -2650
- package/dist/store/index.js.map +1 -1
- package/dist/store/index.mjs +13 -2619
- package/dist/store/index.mjs.map +1 -1
- package/dist/utils/index.js +69 -134
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +5 -122
- package/dist/utils/index.mjs.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
import { useDeferredRecaptcha, RECAPTCHA_WIDGET_HEIGHT } from './chunk-6IBFBWC5.mjs';
|
|
2
|
+
import { Label } from './chunk-WTVTI5TO.mjs';
|
|
3
|
+
import { Input } from './chunk-34RX5P75.mjs';
|
|
4
|
+
import { PageHead } from './chunk-N5EC53MH.mjs';
|
|
5
|
+
import { Button } from './chunk-KHYXK7FG.mjs';
|
|
6
|
+
import { useProduct, useProductConfig } from './chunk-GCFLCO2Z.mjs';
|
|
7
|
+
import { useWebSDK, useWebSDKConfig } from './chunk-5JRJ57CL.mjs';
|
|
8
|
+
import { useRef, useState, useEffect } from 'react';
|
|
9
|
+
import { zodResolver } from '@hookform/resolvers/zod';
|
|
10
|
+
import ReCAPTCHA from 'react-google-recaptcha';
|
|
11
|
+
import { useForm } from 'react-hook-form';
|
|
12
|
+
import { toast } from 'sonner';
|
|
13
|
+
import { z } from 'zod';
|
|
14
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
15
|
+
|
|
16
|
+
var newsletterSchema = z.object({
|
|
17
|
+
email: z.string().email("Please enter a valid email address")
|
|
18
|
+
});
|
|
19
|
+
var SUBSCRIBE_MUTATION = (
|
|
20
|
+
/* GraphQL */
|
|
21
|
+
`
|
|
22
|
+
mutation Subscribe($input: SubscribeInput!) {
|
|
23
|
+
subscribe(input: $input) {
|
|
24
|
+
id
|
|
25
|
+
email
|
|
26
|
+
alreadySubscribed
|
|
27
|
+
status
|
|
28
|
+
subscribedAt
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`
|
|
32
|
+
);
|
|
33
|
+
async function subscribeNewsletter(client, email, productId, recaptchaToken) {
|
|
34
|
+
try {
|
|
35
|
+
const result = await client.mutate(SUBSCRIBE_MUTATION, {
|
|
36
|
+
input: {
|
|
37
|
+
email: email.trim().toLowerCase(),
|
|
38
|
+
platformProductId: productId,
|
|
39
|
+
metadata: {
|
|
40
|
+
source: "website",
|
|
41
|
+
referrer: typeof window !== "undefined" ? window.location.href : "",
|
|
42
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43
|
+
...recaptchaToken ? { recaptchaToken } : {}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
if (result.errors?.length) {
|
|
48
|
+
const errorMsg = result.errors[0]?.message ?? "Subscription failed";
|
|
49
|
+
const code = result.errors[0]?.extensions?.code;
|
|
50
|
+
if (code === "DUPLICATE_SUBSCRIBER" || errorMsg.toLowerCase().includes("already subscribed")) {
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
message: "You are already part of this newsletter."
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return { success: false, message: errorMsg };
|
|
57
|
+
}
|
|
58
|
+
if (result.data?.subscribe?.alreadySubscribed) {
|
|
59
|
+
return {
|
|
60
|
+
success: true,
|
|
61
|
+
message: "You are already part of this newsletter."
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { success: true };
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error("Newsletter subscription error:", error);
|
|
67
|
+
return { success: false, message: "Network error. Please try again." };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function useRateLimit(maxAttempts, windowMinutes) {
|
|
71
|
+
const rateLimitRef = useRef(null);
|
|
72
|
+
const [isLimited, setIsLimited] = useState(false);
|
|
73
|
+
const [resetTime, setResetTime] = useState(null);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const state = rateLimitRef.current;
|
|
76
|
+
if (state && Date.now() > state.resetTime) {
|
|
77
|
+
rateLimitRef.current = null;
|
|
78
|
+
setIsLimited(false);
|
|
79
|
+
setResetTime(null);
|
|
80
|
+
} else if (state && state.attempts >= maxAttempts) {
|
|
81
|
+
setIsLimited(true);
|
|
82
|
+
setResetTime(new Date(state.resetTime));
|
|
83
|
+
}
|
|
84
|
+
}, [maxAttempts]);
|
|
85
|
+
function recordAttempt() {
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
const state = rateLimitRef.current;
|
|
88
|
+
if (state && now > state.resetTime) {
|
|
89
|
+
rateLimitRef.current = null;
|
|
90
|
+
}
|
|
91
|
+
const current = rateLimitRef.current;
|
|
92
|
+
if (!current) {
|
|
93
|
+
rateLimitRef.current = {
|
|
94
|
+
attempts: 1,
|
|
95
|
+
resetTime: now + windowMinutes * 60 * 1e3
|
|
96
|
+
};
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
current.attempts += 1;
|
|
100
|
+
if (current.attempts >= maxAttempts) {
|
|
101
|
+
setIsLimited(true);
|
|
102
|
+
setResetTime(new Date(current.resetTime));
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
function checkLimit() {
|
|
108
|
+
const state = rateLimitRef.current;
|
|
109
|
+
if (!state) return false;
|
|
110
|
+
if (Date.now() > state.resetTime) {
|
|
111
|
+
rateLimitRef.current = null;
|
|
112
|
+
setIsLimited(false);
|
|
113
|
+
setResetTime(null);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
return state.attempts >= maxAttempts;
|
|
117
|
+
}
|
|
118
|
+
return { isLimited, resetTime, recordAttempt, checkLimit };
|
|
119
|
+
}
|
|
120
|
+
function NewsletterPage({
|
|
121
|
+
productName,
|
|
122
|
+
layout = "centered",
|
|
123
|
+
rateLimitAttempts = 3,
|
|
124
|
+
rateLimitWindowMinutes = 15,
|
|
125
|
+
heroHeading = "Stay Updated",
|
|
126
|
+
heroSubtitle = "Subscribe to our newsletter",
|
|
127
|
+
heroDescription,
|
|
128
|
+
features,
|
|
129
|
+
successMessage = "Successfully subscribed to newsletter!",
|
|
130
|
+
errorMessage = "Failed to subscribe. Please try again.",
|
|
131
|
+
rateLimitMessage,
|
|
132
|
+
className,
|
|
133
|
+
seoTitle,
|
|
134
|
+
seoDescription,
|
|
135
|
+
seoKeywords,
|
|
136
|
+
seoImage,
|
|
137
|
+
seoUrl,
|
|
138
|
+
recaptchaSiteKey
|
|
139
|
+
}) {
|
|
140
|
+
const client = useWebSDK();
|
|
141
|
+
const config = useWebSDKConfig();
|
|
142
|
+
const { product } = useProduct();
|
|
143
|
+
const productConfig = useProductConfig();
|
|
144
|
+
const effectiveProductId = product?.id || config.productId;
|
|
145
|
+
const displayName = productName ?? product?.name ?? config.productId;
|
|
146
|
+
const effectiveRecaptchaSiteKey = recaptchaSiteKey ?? productConfig.recaptchaSiteKey ?? config.recaptchaSiteKey ?? "";
|
|
147
|
+
const recaptchaRef = useRef(null);
|
|
148
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
149
|
+
const { isLimited, resetTime, recordAttempt, checkLimit } = useRateLimit(
|
|
150
|
+
rateLimitAttempts,
|
|
151
|
+
rateLimitWindowMinutes
|
|
152
|
+
);
|
|
153
|
+
const {
|
|
154
|
+
register,
|
|
155
|
+
handleSubmit,
|
|
156
|
+
formState: { errors },
|
|
157
|
+
reset
|
|
158
|
+
} = useForm({
|
|
159
|
+
resolver: zodResolver(newsletterSchema)
|
|
160
|
+
});
|
|
161
|
+
const onSubmit = async (data) => {
|
|
162
|
+
const recaptchaToken = recaptchaRef.current?.getValue() ?? "";
|
|
163
|
+
if (effectiveRecaptchaSiteKey && !recaptchaToken) {
|
|
164
|
+
toast.error("Please complete the reCAPTCHA verification");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (checkLimit()) {
|
|
168
|
+
toast.error(
|
|
169
|
+
rateLimitMessage ?? `Too many attempts. Please try again after ${resetTime?.toLocaleTimeString()}`
|
|
170
|
+
);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
setIsSubmitting(true);
|
|
174
|
+
try {
|
|
175
|
+
const result = await subscribeNewsletter(
|
|
176
|
+
client,
|
|
177
|
+
data.email,
|
|
178
|
+
effectiveProductId,
|
|
179
|
+
recaptchaToken || void 0
|
|
180
|
+
);
|
|
181
|
+
if (result.success) {
|
|
182
|
+
if (result.message) {
|
|
183
|
+
toast.info(result.message);
|
|
184
|
+
} else {
|
|
185
|
+
toast.success(successMessage);
|
|
186
|
+
}
|
|
187
|
+
reset();
|
|
188
|
+
} else {
|
|
189
|
+
toast.error(result.message ?? errorMessage);
|
|
190
|
+
}
|
|
191
|
+
recordAttempt();
|
|
192
|
+
recaptchaRef.current?.reset();
|
|
193
|
+
} catch (_error) {
|
|
194
|
+
toast.error(errorMessage);
|
|
195
|
+
recaptchaRef.current?.reset();
|
|
196
|
+
} finally {
|
|
197
|
+
setIsSubmitting(false);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const defaultFeatures = [
|
|
201
|
+
{
|
|
202
|
+
icon: /* @__PURE__ */ jsx(
|
|
203
|
+
"svg",
|
|
204
|
+
{
|
|
205
|
+
className: "h-6 w-6",
|
|
206
|
+
fill: "none",
|
|
207
|
+
stroke: "currentColor",
|
|
208
|
+
viewBox: "0 0 24 24",
|
|
209
|
+
children: /* @__PURE__ */ jsx(
|
|
210
|
+
"path",
|
|
211
|
+
{
|
|
212
|
+
strokeLinecap: "round",
|
|
213
|
+
strokeLinejoin: "round",
|
|
214
|
+
strokeWidth: 2,
|
|
215
|
+
d: "M13 10V3L4 14h7v7l9-11h-7z"
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
}
|
|
219
|
+
),
|
|
220
|
+
title: "Latest Updates",
|
|
221
|
+
description: "Get the latest news and updates delivered to your inbox"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
icon: /* @__PURE__ */ jsx(
|
|
225
|
+
"svg",
|
|
226
|
+
{
|
|
227
|
+
className: "h-6 w-6",
|
|
228
|
+
fill: "none",
|
|
229
|
+
stroke: "currentColor",
|
|
230
|
+
viewBox: "0 0 24 24",
|
|
231
|
+
children: /* @__PURE__ */ jsx(
|
|
232
|
+
"path",
|
|
233
|
+
{
|
|
234
|
+
strokeLinecap: "round",
|
|
235
|
+
strokeLinejoin: "round",
|
|
236
|
+
strokeWidth: 2,
|
|
237
|
+
d: "M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
),
|
|
242
|
+
title: "Exclusive Content",
|
|
243
|
+
description: "Access exclusive content and insights not available elsewhere"
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
icon: /* @__PURE__ */ jsx(
|
|
247
|
+
"svg",
|
|
248
|
+
{
|
|
249
|
+
className: "h-6 w-6",
|
|
250
|
+
fill: "none",
|
|
251
|
+
stroke: "currentColor",
|
|
252
|
+
viewBox: "0 0 24 24",
|
|
253
|
+
children: /* @__PURE__ */ jsx(
|
|
254
|
+
"path",
|
|
255
|
+
{
|
|
256
|
+
strokeLinecap: "round",
|
|
257
|
+
strokeLinejoin: "round",
|
|
258
|
+
strokeWidth: 2,
|
|
259
|
+
d: "M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"
|
|
260
|
+
}
|
|
261
|
+
)
|
|
262
|
+
}
|
|
263
|
+
),
|
|
264
|
+
title: "Early Access",
|
|
265
|
+
description: "Be the first to know about new features and product launches"
|
|
266
|
+
}
|
|
267
|
+
];
|
|
268
|
+
const displayFeatures = features ?? defaultFeatures;
|
|
269
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
270
|
+
seoTitle && /* @__PURE__ */ jsx(
|
|
271
|
+
PageHead,
|
|
272
|
+
{
|
|
273
|
+
title: seoTitle,
|
|
274
|
+
description: seoDescription ?? heroDescription ?? heroSubtitle,
|
|
275
|
+
productName: displayName,
|
|
276
|
+
keywords: seoKeywords,
|
|
277
|
+
image: seoImage,
|
|
278
|
+
url: seoUrl
|
|
279
|
+
}
|
|
280
|
+
),
|
|
281
|
+
/* @__PURE__ */ jsx("div", { className, children: layout === "centered" ? (
|
|
282
|
+
// Centered Layout
|
|
283
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-screen flex items-center justify-center px-4 py-12", children: /* @__PURE__ */ jsxs("div", { className: "max-w-md w-full space-y-8", children: [
|
|
284
|
+
/* @__PURE__ */ jsxs("div", { className: "text-center", children: [
|
|
285
|
+
/* @__PURE__ */ jsx("h1", { className: "text-4xl font-bold tracking-tight", children: heroHeading }),
|
|
286
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-lg text-muted-foreground", children: heroSubtitle }),
|
|
287
|
+
heroDescription && /* @__PURE__ */ jsx("p", { className: "mt-4 text-sm text-muted-foreground", children: heroDescription })
|
|
288
|
+
] }),
|
|
289
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6", children: [
|
|
290
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
291
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "Email address" }),
|
|
292
|
+
/* @__PURE__ */ jsx(
|
|
293
|
+
Input,
|
|
294
|
+
{
|
|
295
|
+
id: "email",
|
|
296
|
+
type: "email",
|
|
297
|
+
placeholder: "you@example.com",
|
|
298
|
+
disabled: isSubmitting || isLimited,
|
|
299
|
+
...register("email")
|
|
300
|
+
}
|
|
301
|
+
),
|
|
302
|
+
errors.email && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errors.email.message })
|
|
303
|
+
] }),
|
|
304
|
+
effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
|
|
305
|
+
ReCAPTCHA,
|
|
306
|
+
{
|
|
307
|
+
ref: recaptchaRef,
|
|
308
|
+
sitekey: effectiveRecaptchaSiteKey
|
|
309
|
+
}
|
|
310
|
+
) }),
|
|
311
|
+
/* @__PURE__ */ jsx(
|
|
312
|
+
Button,
|
|
313
|
+
{
|
|
314
|
+
type: "submit",
|
|
315
|
+
className: "w-full",
|
|
316
|
+
disabled: isSubmitting || isLimited,
|
|
317
|
+
children: isSubmitting ? "Subscribing..." : "Subscribe"
|
|
318
|
+
}
|
|
319
|
+
),
|
|
320
|
+
isLimited && resetTime && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground text-center", children: [
|
|
321
|
+
"Rate limit reached. Try again after",
|
|
322
|
+
" ",
|
|
323
|
+
resetTime.toLocaleTimeString()
|
|
324
|
+
] })
|
|
325
|
+
] }),
|
|
326
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground text-center", children: [
|
|
327
|
+
"By subscribing, you agree to receive emails from ",
|
|
328
|
+
displayName,
|
|
329
|
+
". You can unsubscribe at any time."
|
|
330
|
+
] })
|
|
331
|
+
] }) })
|
|
332
|
+
) : (
|
|
333
|
+
// Split Layout
|
|
334
|
+
/* @__PURE__ */ jsxs("div", { className: "min-h-screen grid lg:grid-cols-2", children: [
|
|
335
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center px-4 py-12 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "max-w-md w-full space-y-8", children: [
|
|
336
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
337
|
+
/* @__PURE__ */ jsx("h1", { className: "text-4xl font-bold tracking-tight", children: heroHeading }),
|
|
338
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-lg text-muted-foreground", children: heroSubtitle }),
|
|
339
|
+
heroDescription && /* @__PURE__ */ jsx("p", { className: "mt-4 text-sm text-muted-foreground", children: heroDescription })
|
|
340
|
+
] }),
|
|
341
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-6", children: [
|
|
342
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
343
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "Email address" }),
|
|
344
|
+
/* @__PURE__ */ jsx(
|
|
345
|
+
Input,
|
|
346
|
+
{
|
|
347
|
+
id: "email",
|
|
348
|
+
type: "email",
|
|
349
|
+
placeholder: "you@example.com",
|
|
350
|
+
disabled: isSubmitting || isLimited,
|
|
351
|
+
...register("email")
|
|
352
|
+
}
|
|
353
|
+
),
|
|
354
|
+
errors.email && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errors.email.message })
|
|
355
|
+
] }),
|
|
356
|
+
effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx("div", { className: "flex justify-center sm:justify-start", children: /* @__PURE__ */ jsx(
|
|
357
|
+
ReCAPTCHA,
|
|
358
|
+
{
|
|
359
|
+
ref: recaptchaRef,
|
|
360
|
+
sitekey: effectiveRecaptchaSiteKey
|
|
361
|
+
}
|
|
362
|
+
) }),
|
|
363
|
+
/* @__PURE__ */ jsx(
|
|
364
|
+
Button,
|
|
365
|
+
{
|
|
366
|
+
type: "submit",
|
|
367
|
+
className: "w-full",
|
|
368
|
+
disabled: isSubmitting || isLimited,
|
|
369
|
+
children: isSubmitting ? "Subscribing..." : "Subscribe"
|
|
370
|
+
}
|
|
371
|
+
),
|
|
372
|
+
isLimited && resetTime && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground text-center", children: [
|
|
373
|
+
"Rate limit reached. Try again after",
|
|
374
|
+
" ",
|
|
375
|
+
resetTime.toLocaleTimeString()
|
|
376
|
+
] })
|
|
377
|
+
] }),
|
|
378
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
379
|
+
"By subscribing, you agree to receive emails from ",
|
|
380
|
+
displayName,
|
|
381
|
+
". You can unsubscribe at any time."
|
|
382
|
+
] })
|
|
383
|
+
] }) }),
|
|
384
|
+
/* @__PURE__ */ jsx("div", { className: "hidden lg:flex items-center justify-center bg-muted px-4 py-12 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "max-w-md space-y-8", children: [
|
|
385
|
+
/* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold", children: "Why Subscribe?" }),
|
|
386
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-6", children: displayFeatures.map((feature, index) => /* @__PURE__ */ jsxs("div", { className: "flex gap-4", children: [
|
|
387
|
+
/* @__PURE__ */ jsx("div", { className: "flex-shrink-0 text-primary", children: feature.icon }),
|
|
388
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
389
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold", children: feature.title }),
|
|
390
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: feature.description })
|
|
391
|
+
] })
|
|
392
|
+
] }, index)) })
|
|
393
|
+
] }) })
|
|
394
|
+
] })
|
|
395
|
+
) })
|
|
396
|
+
] });
|
|
397
|
+
}
|
|
398
|
+
function NewsletterForm({
|
|
399
|
+
variant = "inline",
|
|
400
|
+
showLabel = false,
|
|
401
|
+
showDescription = false,
|
|
402
|
+
description = "Subscribe to our newsletter for updates",
|
|
403
|
+
buttonText = "Subscribe",
|
|
404
|
+
className = "",
|
|
405
|
+
recaptchaSiteKey
|
|
406
|
+
}) {
|
|
407
|
+
const client = useWebSDK();
|
|
408
|
+
const config = useWebSDKConfig();
|
|
409
|
+
const { product } = useProduct();
|
|
410
|
+
const productConfig = useProductConfig();
|
|
411
|
+
const effectiveProductId = product?.id || config.productId;
|
|
412
|
+
const effectiveRecaptchaSiteKey = recaptchaSiteKey ?? productConfig.recaptchaSiteKey ?? config.recaptchaSiteKey ?? "";
|
|
413
|
+
const recaptchaRef = useRef(null);
|
|
414
|
+
const recaptchaGate = useDeferredRecaptcha(effectiveRecaptchaSiteKey);
|
|
415
|
+
const [email, setEmail] = useState("");
|
|
416
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
417
|
+
const handleSubmit = async (e) => {
|
|
418
|
+
e.preventDefault();
|
|
419
|
+
if (!email || !email.includes("@")) {
|
|
420
|
+
toast.error("Please enter a valid email address");
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const recaptchaToken = recaptchaRef.current?.getValue() ?? "";
|
|
424
|
+
if (effectiveRecaptchaSiteKey && !recaptchaToken) {
|
|
425
|
+
recaptchaGate.arm();
|
|
426
|
+
toast.error("Please complete the reCAPTCHA verification");
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
setIsLoading(true);
|
|
430
|
+
try {
|
|
431
|
+
const result = await subscribeNewsletter(
|
|
432
|
+
client,
|
|
433
|
+
email,
|
|
434
|
+
effectiveProductId,
|
|
435
|
+
recaptchaToken || void 0
|
|
436
|
+
);
|
|
437
|
+
if (result.success) {
|
|
438
|
+
if (result.message) {
|
|
439
|
+
toast.info(result.message);
|
|
440
|
+
} else {
|
|
441
|
+
toast.success("Successfully subscribed!");
|
|
442
|
+
}
|
|
443
|
+
setEmail("");
|
|
444
|
+
} else {
|
|
445
|
+
toast.error(result.message ?? "Subscription failed");
|
|
446
|
+
}
|
|
447
|
+
recaptchaRef.current?.reset();
|
|
448
|
+
} catch (_error) {
|
|
449
|
+
toast.error("An error occurred. Please try again.");
|
|
450
|
+
recaptchaRef.current?.reset();
|
|
451
|
+
} finally {
|
|
452
|
+
setIsLoading(false);
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
const isInline = variant === "inline";
|
|
456
|
+
return /* @__PURE__ */ jsxs("div", { className, style: { overflow: "visible" }, children: [
|
|
457
|
+
showDescription && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-3", children: description }),
|
|
458
|
+
/* @__PURE__ */ jsxs(
|
|
459
|
+
"form",
|
|
460
|
+
{
|
|
461
|
+
onSubmit: handleSubmit,
|
|
462
|
+
className: isInline ? "flex flex-col gap-2" : "flex flex-col gap-2",
|
|
463
|
+
style: { overflow: "visible" },
|
|
464
|
+
...recaptchaGate.formProps,
|
|
465
|
+
children: [
|
|
466
|
+
/* @__PURE__ */ jsxs(
|
|
467
|
+
"div",
|
|
468
|
+
{
|
|
469
|
+
className: isInline && !effectiveRecaptchaSiteKey ? "flex gap-2" : "flex flex-col gap-2",
|
|
470
|
+
children: [
|
|
471
|
+
/* @__PURE__ */ jsxs(
|
|
472
|
+
"div",
|
|
473
|
+
{
|
|
474
|
+
className: isInline && !effectiveRecaptchaSiteKey ? "flex-1" : "w-full",
|
|
475
|
+
children: [
|
|
476
|
+
showLabel && /* @__PURE__ */ jsx(Label, { htmlFor: "newsletter-email", className: "text-sm mb-1 block", children: "Email" }),
|
|
477
|
+
/* @__PURE__ */ jsx(
|
|
478
|
+
Input,
|
|
479
|
+
{
|
|
480
|
+
id: "newsletter-email",
|
|
481
|
+
type: "email",
|
|
482
|
+
placeholder: "Enter your email",
|
|
483
|
+
value: email,
|
|
484
|
+
onChange: (e) => setEmail(e.target.value),
|
|
485
|
+
disabled: isLoading,
|
|
486
|
+
required: true,
|
|
487
|
+
className: "w-full"
|
|
488
|
+
}
|
|
489
|
+
)
|
|
490
|
+
]
|
|
491
|
+
}
|
|
492
|
+
),
|
|
493
|
+
!effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx(
|
|
494
|
+
Button,
|
|
495
|
+
{
|
|
496
|
+
type: "submit",
|
|
497
|
+
disabled: isLoading,
|
|
498
|
+
className: isInline ? "whitespace-nowrap" : "w-full",
|
|
499
|
+
children: isLoading ? "Subscribing..." : buttonText
|
|
500
|
+
}
|
|
501
|
+
)
|
|
502
|
+
]
|
|
503
|
+
}
|
|
504
|
+
),
|
|
505
|
+
effectiveRecaptchaSiteKey && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
506
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
507
|
+
body > div[style*="position: absolute"] > div > iframe[title*="recaptcha challenge"],
|
|
508
|
+
body > div:not([class]):not([id]) > div > iframe[title*="recaptcha"] {
|
|
509
|
+
position: fixed !important;
|
|
510
|
+
top: 50% !important;
|
|
511
|
+
left: 50% !important;
|
|
512
|
+
transform: translate(-50%, -50%) !important;
|
|
513
|
+
z-index: 99999 !important;
|
|
514
|
+
}
|
|
515
|
+
body > div[style*="position: absolute"]:has(iframe[title*="recaptcha challenge"]) {
|
|
516
|
+
position: fixed !important;
|
|
517
|
+
top: 0 !important;
|
|
518
|
+
left: 0 !important;
|
|
519
|
+
width: 100vw !important;
|
|
520
|
+
height: 100vh !important;
|
|
521
|
+
display: flex !important;
|
|
522
|
+
align-items: center !important;
|
|
523
|
+
justify-content: center !important;
|
|
524
|
+
z-index: 99999 !important;
|
|
525
|
+
background: rgba(0,0,0,0.3) !important;
|
|
526
|
+
}
|
|
527
|
+
` }),
|
|
528
|
+
/* @__PURE__ */ jsx(
|
|
529
|
+
"div",
|
|
530
|
+
{
|
|
531
|
+
style: {
|
|
532
|
+
position: "relative",
|
|
533
|
+
zIndex: 50,
|
|
534
|
+
display: "flex",
|
|
535
|
+
justifyContent: "flex-start",
|
|
536
|
+
minHeight: RECAPTCHA_WIDGET_HEIGHT
|
|
537
|
+
},
|
|
538
|
+
children: recaptchaGate.armed && /* @__PURE__ */ jsx(
|
|
539
|
+
ReCAPTCHA,
|
|
540
|
+
{
|
|
541
|
+
ref: recaptchaRef,
|
|
542
|
+
sitekey: effectiveRecaptchaSiteKey,
|
|
543
|
+
size: "normal"
|
|
544
|
+
}
|
|
545
|
+
)
|
|
546
|
+
}
|
|
547
|
+
)
|
|
548
|
+
] }),
|
|
549
|
+
effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isLoading, className: "w-full", children: isLoading ? "Subscribing..." : buttonText })
|
|
550
|
+
]
|
|
551
|
+
}
|
|
552
|
+
)
|
|
553
|
+
] });
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export { NewsletterForm, NewsletterPage };
|
|
557
|
+
//# sourceMappingURL=chunk-JSLDWYV7.mjs.map
|
|
558
|
+
//# sourceMappingURL=chunk-JSLDWYV7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/newsletter.tsx"],"names":[],"mappings":"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","file":"chunk-JSLDWYV7.mjs","sourcesContent":["/**\n * Newsletter Component\n * Reusable newsletter subscription component with email validation and rate limiting.\n * Uses GraphQL mutations via the WebSDKClient provider.\n *\n * @example\n * ```tsx\n * import { NewsletterPage } from '@burdenoff/website-sdk/components/newsletter'\n *\n * function Newsletter() {\n * return (\n * <NewsletterPage\n * productName=\"BigConsole\"\n * layout=\"centered\"\n * seoTitle=\"Subscribe to Newsletter\"\n * seoDescription=\"Stay updated with our latest news\"\n * seoKeywords=\"newsletter, updates, news\"\n * />\n * )\n * }\n * ```\n */\n\n\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\n\nimport { zodResolver } from \"@hookform/resolvers/zod\";\nimport ReCAPTCHA from \"react-google-recaptcha\";\nimport { useForm } from \"react-hook-form\";\nimport { toast } from \"sonner\";\nimport { z } from \"zod\";\n\nimport { useWebSDK, useWebSDKConfig } from \"../client/provider\";\nimport {\n RECAPTCHA_WIDGET_HEIGHT,\n useDeferredRecaptcha,\n} from \"../hooks/use-deferred-recaptcha\";\nimport { useProduct, useProductConfig } from \"../product/product-provider\";\nimport { PageHead } from \"../seo/page-head\";\nimport { Button } from \"../ui/button\";\nimport { Input } from \"../ui/input\";\nimport { Label } from \"../ui/label\";\n\nimport type { WebSDKClient } from \"../client/graphql-client\";\n\n// ============================================================================\n// TYPES & INTERFACES\n// ============================================================================\n\n/**\n * Newsletter page component configuration props\n */\nexport interface NewsletterPageProps {\n /**\n * Product name (used in title and branding).\n * Falls back to SDK config productId if not provided.\n */\n productName?: string;\n /**\n * Layout variant\n * @default 'centered'\n */\n layout?: \"centered\" | \"split\";\n /**\n * Rate limit attempts\n * @default 3\n */\n rateLimitAttempts?: number;\n /**\n * Rate limit window in minutes\n * @default 15\n */\n rateLimitWindowMinutes?: number;\n /**\n * Hero section heading\n * @default 'Stay Updated'\n */\n heroHeading?: string;\n /**\n * Hero section subtitle\n * @default 'Subscribe to our newsletter'\n */\n heroSubtitle?: string;\n /**\n * Hero section description\n */\n heroDescription?: string;\n /**\n * Features to display (for split layout)\n */\n features?: Array<{\n icon: React.ReactNode;\n title: string;\n description: string;\n }>;\n /**\n * Success message after subscription\n * @default 'Successfully subscribed to newsletter!'\n */\n successMessage?: string;\n /**\n * Error message on failure\n * @default 'Failed to subscribe. Please try again.'\n */\n errorMessage?: string;\n /**\n * Rate limit error message\n */\n rateLimitMessage?: string;\n /**\n * Custom CSS class for container\n */\n className?: string;\n /**\n * SEO: Page title (optional, for SEO meta tags)\n */\n seoTitle?: string;\n /**\n * SEO: Page description (optional, for SEO meta tags)\n */\n seoDescription?: string;\n /**\n * SEO: Keywords (optional, for SEO meta tags)\n */\n seoKeywords?: string;\n /**\n * SEO: OG Image URL (optional, for SEO meta tags)\n */\n seoImage?: string;\n /**\n * SEO: Canonical URL (optional, for SEO meta tags)\n */\n seoUrl?: string;\n /**\n * reCAPTCHA site key (optional, falls back to SDK config)\n */\n recaptchaSiteKey?: string;\n}\n\ninterface RateLimitState {\n attempts: number;\n resetTime: number;\n}\n\n// ============================================================================\n// VALIDATION SCHEMA\n// ============================================================================\n\nconst newsletterSchema = z.object({\n email: z.string().email(\"Please enter a valid email address\"),\n});\n\ntype NewsletterFormData = z.infer<typeof newsletterSchema>;\n\n// ============================================================================\n// GRAPHQL MUTATION\n// ============================================================================\n\nconst SUBSCRIBE_MUTATION = /* GraphQL */ `\n mutation Subscribe($input: SubscribeInput!) {\n subscribe(input: $input) {\n id\n email\n alreadySubscribed\n status\n subscribedAt\n }\n }\n`;\n\n// ============================================================================\n// API SERVICE\n// ============================================================================\n\nasync function subscribeNewsletter(\n client: WebSDKClient,\n email: string,\n productId: string,\n recaptchaToken?: string,\n): Promise<{ success: boolean; message?: string }> {\n try {\n const result = await client.mutate<{\n subscribe: {\n id: string;\n email: string;\n status: string;\n alreadySubscribed?: boolean;\n };\n }>(SUBSCRIBE_MUTATION, {\n input: {\n email: email.trim().toLowerCase(),\n platformProductId: productId,\n metadata: {\n source: \"website\",\n referrer: typeof window !== \"undefined\" ? window.location.href : \"\",\n timestamp: new Date().toISOString(),\n ...(recaptchaToken ? { recaptchaToken } : {}),\n },\n },\n });\n\n if (result.errors?.length) {\n const errorMsg = result.errors[0]?.message ?? \"Subscription failed\";\n const code = (result.errors[0] as { extensions?: { code?: string } })\n ?.extensions?.code;\n if (\n code === \"DUPLICATE_SUBSCRIBER\" ||\n errorMsg.toLowerCase().includes(\"already subscribed\")\n ) {\n return {\n success: true,\n message: \"You are already part of this newsletter.\",\n };\n }\n return { success: false, message: errorMsg };\n }\n\n if (result.data?.subscribe?.alreadySubscribed) {\n return {\n success: true,\n message: \"You are already part of this newsletter.\",\n };\n }\n\n return { success: true };\n } catch (error) {\n console.error(\"Newsletter subscription error:\", error);\n return { success: false, message: \"Network error. Please try again.\" };\n }\n}\n\n// ============================================================================\n// RATE LIMITING (in-memory for SSR compatibility)\n// ============================================================================\n\nfunction useRateLimit(maxAttempts: number, windowMinutes: number) {\n const rateLimitRef = useRef<RateLimitState | null>(null);\n const [isLimited, setIsLimited] = useState(false);\n const [resetTime, setResetTime] = useState<Date | null>(null);\n\n useEffect(() => {\n // Check if existing rate limit has expired on mount\n const state = rateLimitRef.current;\n if (state && Date.now() > state.resetTime) {\n rateLimitRef.current = null;\n setIsLimited(false);\n setResetTime(null);\n } else if (state && state.attempts >= maxAttempts) {\n setIsLimited(true);\n setResetTime(new Date(state.resetTime));\n }\n }, [maxAttempts]);\n\n function recordAttempt(): boolean {\n const now = Date.now();\n const state = rateLimitRef.current;\n\n // Reset if window expired\n if (state && now > state.resetTime) {\n rateLimitRef.current = null;\n }\n\n const current = rateLimitRef.current;\n\n if (!current) {\n rateLimitRef.current = {\n attempts: 1,\n resetTime: now + windowMinutes * 60 * 1000,\n };\n return false;\n }\n\n current.attempts += 1;\n\n if (current.attempts >= maxAttempts) {\n setIsLimited(true);\n setResetTime(new Date(current.resetTime));\n return true;\n }\n\n return false;\n }\n\n function checkLimit(): boolean {\n const state = rateLimitRef.current;\n if (!state) return false;\n if (Date.now() > state.resetTime) {\n rateLimitRef.current = null;\n setIsLimited(false);\n setResetTime(null);\n return false;\n }\n return state.attempts >= maxAttempts;\n }\n\n return { isLimited, resetTime, recordAttempt, checkLimit };\n}\n\n// ============================================================================\n// MAIN COMPONENT\n// ============================================================================\n\nexport function NewsletterPage({\n productName,\n layout = \"centered\",\n rateLimitAttempts = 3,\n rateLimitWindowMinutes = 15,\n heroHeading = \"Stay Updated\",\n heroSubtitle = \"Subscribe to our newsletter\",\n heroDescription,\n features,\n successMessage = \"Successfully subscribed to newsletter!\",\n errorMessage = \"Failed to subscribe. Please try again.\",\n rateLimitMessage,\n className,\n seoTitle,\n seoDescription,\n seoKeywords,\n seoImage,\n seoUrl,\n recaptchaSiteKey,\n}: NewsletterPageProps) {\n const client = useWebSDK();\n const config = useWebSDKConfig();\n const { product } = useProduct();\n const productConfig = useProductConfig();\n const effectiveProductId = product?.id || config.productId;\n const displayName = productName ?? product?.name ?? config.productId;\n const effectiveRecaptchaSiteKey =\n recaptchaSiteKey ??\n productConfig.recaptchaSiteKey ??\n config.recaptchaSiteKey ??\n \"\";\n\n const recaptchaRef = useRef<ReCAPTCHA>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const { isLimited, resetTime, recordAttempt, checkLimit } = useRateLimit(\n rateLimitAttempts,\n rateLimitWindowMinutes,\n );\n\n const {\n register,\n handleSubmit,\n formState: { errors },\n reset,\n } = useForm<NewsletterFormData>({\n resolver: zodResolver(newsletterSchema),\n });\n\n const onSubmit = async (data: NewsletterFormData) => {\n // Check reCAPTCHA\n const recaptchaToken = recaptchaRef.current?.getValue() ?? \"\";\n if (effectiveRecaptchaSiteKey && !recaptchaToken) {\n toast.error(\"Please complete the reCAPTCHA verification\");\n return;\n }\n\n // Check rate limit\n if (checkLimit()) {\n toast.error(\n rateLimitMessage ??\n `Too many attempts. Please try again after ${resetTime?.toLocaleTimeString()}`,\n );\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n const result = await subscribeNewsletter(\n client,\n data.email,\n effectiveProductId,\n recaptchaToken || undefined,\n );\n\n if (result.success) {\n if (result.message) {\n toast.info(result.message);\n } else {\n toast.success(successMessage);\n }\n reset();\n } else {\n toast.error(result.message ?? errorMessage);\n }\n\n // Record the attempt for rate limiting\n recordAttempt();\n recaptchaRef.current?.reset();\n } catch (_error) {\n toast.error(errorMessage);\n recaptchaRef.current?.reset();\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const defaultFeatures = [\n {\n icon: (\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M13 10V3L4 14h7v7l9-11h-7z\"\n />\n </svg>\n ),\n title: \"Latest Updates\",\n description: \"Get the latest news and updates delivered to your inbox\",\n },\n {\n icon: (\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4\"\n />\n </svg>\n ),\n title: \"Exclusive Content\",\n description:\n \"Access exclusive content and insights not available elsewhere\",\n },\n {\n icon: (\n <svg\n className=\"h-6 w-6\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9\"\n />\n </svg>\n ),\n title: \"Early Access\",\n description:\n \"Be the first to know about new features and product launches\",\n },\n ];\n\n const displayFeatures = features ?? defaultFeatures;\n\n return (\n <>\n {/* SEO Meta Tags */}\n {seoTitle && (\n <PageHead\n title={seoTitle}\n description={seoDescription ?? heroDescription ?? heroSubtitle}\n productName={displayName}\n keywords={seoKeywords}\n image={seoImage}\n url={seoUrl}\n />\n )}\n\n <div className={className}>\n {layout === \"centered\" ? (\n // Centered Layout\n <div className=\"min-h-screen flex items-center justify-center px-4 py-12\">\n <div className=\"max-w-md w-full space-y-8\">\n {/* Header */}\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold tracking-tight\">\n {heroHeading}\n </h1>\n <p className=\"mt-2 text-lg text-muted-foreground\">\n {heroSubtitle}\n </p>\n {heroDescription && (\n <p className=\"mt-4 text-sm text-muted-foreground\">\n {heroDescription}\n </p>\n )}\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit(onSubmit)} className=\"space-y-6\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email address</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n disabled={isSubmitting || isLimited}\n {...register(\"email\")}\n />\n {errors.email && (\n <p className=\"text-sm text-destructive\">\n {errors.email.message}\n </p>\n )}\n </div>\n\n {effectiveRecaptchaSiteKey && (\n <div className=\"flex justify-center\">\n <ReCAPTCHA\n ref={recaptchaRef}\n sitekey={effectiveRecaptchaSiteKey}\n />\n </div>\n )}\n\n <Button\n type=\"submit\"\n className=\"w-full\"\n disabled={isSubmitting || isLimited}\n >\n {isSubmitting ? \"Subscribing...\" : \"Subscribe\"}\n </Button>\n\n {isLimited && resetTime && (\n <p className=\"text-sm text-muted-foreground text-center\">\n Rate limit reached. Try again after{\" \"}\n {resetTime.toLocaleTimeString()}\n </p>\n )}\n </form>\n\n {/* Privacy Notice */}\n <p className=\"text-xs text-muted-foreground text-center\">\n By subscribing, you agree to receive emails from {displayName}.\n You can unsubscribe at any time.\n </p>\n </div>\n </div>\n ) : (\n // Split Layout\n <div className=\"min-h-screen grid lg:grid-cols-2\">\n {/* Left Column - Form */}\n <div className=\"flex items-center justify-center px-4 py-12 sm:px-6 lg:px-8\">\n <div className=\"max-w-md w-full space-y-8\">\n {/* Header */}\n <div>\n <h1 className=\"text-4xl font-bold tracking-tight\">\n {heroHeading}\n </h1>\n <p className=\"mt-2 text-lg text-muted-foreground\">\n {heroSubtitle}\n </p>\n {heroDescription && (\n <p className=\"mt-4 text-sm text-muted-foreground\">\n {heroDescription}\n </p>\n )}\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit(onSubmit)} className=\"space-y-6\">\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email address</Label>\n <Input\n id=\"email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n disabled={isSubmitting || isLimited}\n {...register(\"email\")}\n />\n {errors.email && (\n <p className=\"text-sm text-destructive\">\n {errors.email.message}\n </p>\n )}\n </div>\n\n {effectiveRecaptchaSiteKey && (\n <div className=\"flex justify-center sm:justify-start\">\n <ReCAPTCHA\n ref={recaptchaRef}\n sitekey={effectiveRecaptchaSiteKey}\n />\n </div>\n )}\n\n <Button\n type=\"submit\"\n className=\"w-full\"\n disabled={isSubmitting || isLimited}\n >\n {isSubmitting ? \"Subscribing...\" : \"Subscribe\"}\n </Button>\n\n {isLimited && resetTime && (\n <p className=\"text-sm text-muted-foreground text-center\">\n Rate limit reached. Try again after{\" \"}\n {resetTime.toLocaleTimeString()}\n </p>\n )}\n </form>\n\n {/* Privacy Notice */}\n <p className=\"text-xs text-muted-foreground\">\n By subscribing, you agree to receive emails from {displayName}\n . You can unsubscribe at any time.\n </p>\n </div>\n </div>\n\n {/* Right Column - Features */}\n <div className=\"hidden lg:flex items-center justify-center bg-muted px-4 py-12 sm:px-6 lg:px-8\">\n <div className=\"max-w-md space-y-8\">\n <h2 className=\"text-2xl font-bold\">Why Subscribe?</h2>\n <div className=\"space-y-6\">\n {displayFeatures.map((feature, index) => (\n <div key={index} className=\"flex gap-4\">\n <div className=\"flex-shrink-0 text-primary\">\n {feature.icon}\n </div>\n <div>\n <h3 className=\"font-semibold\">{feature.title}</h3>\n <p className=\"text-sm text-muted-foreground\">\n {feature.description}\n </p>\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n </>\n );\n}\n\n// ============================================================================\n// NEWSLETTER FORM (Inline Component)\n// ============================================================================\n\nexport interface NewsletterFormProps {\n /**\n * Layout variant\n * @default 'inline'\n */\n variant?: \"inline\" | \"stacked\";\n /**\n * Show email label\n * @default false\n */\n showLabel?: boolean;\n /**\n * Show description text\n * @default false\n */\n showDescription?: boolean;\n /**\n * Description text\n * @default 'Subscribe to our newsletter for updates'\n */\n description?: string;\n /**\n * Button text\n * @default 'Subscribe'\n */\n buttonText?: string;\n /**\n * Custom CSS class\n */\n className?: string;\n /**\n * reCAPTCHA site key (optional, falls back to SDK config)\n */\n recaptchaSiteKey?: string;\n}\n\n/**\n * Lightweight newsletter subscription form for inline use (e.g., footers)\n */\nexport function NewsletterForm({\n variant = \"inline\",\n showLabel = false,\n showDescription = false,\n description = \"Subscribe to our newsletter for updates\",\n buttonText = \"Subscribe\",\n className = \"\",\n recaptchaSiteKey,\n}: NewsletterFormProps) {\n const client = useWebSDK();\n const config = useWebSDKConfig();\n const { product } = useProduct();\n const productConfig = useProductConfig();\n const effectiveProductId = product?.id || config.productId;\n const effectiveRecaptchaSiteKey =\n recaptchaSiteKey ??\n productConfig.recaptchaSiteKey ??\n config.recaptchaSiteKey ??\n \"\";\n\n const recaptchaRef = useRef<ReCAPTCHA>(null);\n const recaptchaGate = useDeferredRecaptcha(effectiveRecaptchaSiteKey);\n const [email, setEmail] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!email || !email.includes(\"@\")) {\n toast.error(\"Please enter a valid email address\");\n return;\n }\n\n // Check reCAPTCHA\n const recaptchaToken = recaptchaRef.current?.getValue() ?? \"\";\n if (effectiveRecaptchaSiteKey && !recaptchaToken) {\n recaptchaGate.arm();\n toast.error(\"Please complete the reCAPTCHA verification\");\n return;\n }\n\n setIsLoading(true);\n\n try {\n const result = await subscribeNewsletter(\n client,\n email,\n effectiveProductId,\n recaptchaToken || undefined,\n );\n\n if (result.success) {\n if (result.message) {\n toast.info(result.message);\n } else {\n toast.success(\"Successfully subscribed!\");\n }\n setEmail(\"\");\n } else {\n toast.error(result.message ?? \"Subscription failed\");\n }\n recaptchaRef.current?.reset();\n } catch (_error) {\n toast.error(\"An error occurred. Please try again.\");\n recaptchaRef.current?.reset();\n } finally {\n setIsLoading(false);\n }\n };\n\n const isInline = variant === \"inline\";\n\n return (\n <div className={className} style={{ overflow: \"visible\" }}>\n {showDescription && (\n <p className=\"text-sm text-muted-foreground mb-3\">{description}</p>\n )}\n <form\n onSubmit={handleSubmit}\n className={isInline ? \"flex flex-col gap-2\" : \"flex flex-col gap-2\"}\n style={{ overflow: \"visible\" }}\n {...recaptchaGate.formProps}\n >\n <div\n className={\n isInline && !effectiveRecaptchaSiteKey\n ? \"flex gap-2\"\n : \"flex flex-col gap-2\"\n }\n >\n <div\n className={\n isInline && !effectiveRecaptchaSiteKey ? \"flex-1\" : \"w-full\"\n }\n >\n {showLabel && (\n <Label htmlFor=\"newsletter-email\" className=\"text-sm mb-1 block\">\n Email\n </Label>\n )}\n <Input\n id=\"newsletter-email\"\n type=\"email\"\n placeholder=\"Enter your email\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n disabled={isLoading}\n required\n className=\"w-full\"\n />\n </div>\n {!effectiveRecaptchaSiteKey && (\n <Button\n type=\"submit\"\n disabled={isLoading}\n className={isInline ? \"whitespace-nowrap\" : \"w-full\"}\n >\n {isLoading ? \"Subscribing...\" : buttonText}\n </Button>\n )}\n </div>\n {effectiveRecaptchaSiteKey && (\n <>\n <style>{`\n body > div[style*=\"position: absolute\"] > div > iframe[title*=\"recaptcha challenge\"],\n body > div:not([class]):not([id]) > div > iframe[title*=\"recaptcha\"] {\n position: fixed !important;\n top: 50% !important;\n left: 50% !important;\n transform: translate(-50%, -50%) !important;\n z-index: 99999 !important;\n }\n body > div[style*=\"position: absolute\"]:has(iframe[title*=\"recaptcha challenge\"]) {\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n width: 100vw !important;\n height: 100vh !important;\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n z-index: 99999 !important;\n background: rgba(0,0,0,0.3) !important;\n }\n `}</style>\n <div\n style={{\n position: \"relative\",\n zIndex: 50,\n display: \"flex\",\n justifyContent: \"flex-start\",\n minHeight: RECAPTCHA_WIDGET_HEIGHT,\n }}\n >\n {/* Normal size (not the cramped compact square), left-aligned to\n the form fields' edge so it reads as a standard checkbox.\n Mounted on first engagement — see useDeferredRecaptcha. */}\n {recaptchaGate.armed && (\n <ReCAPTCHA\n ref={recaptchaRef}\n sitekey={effectiveRecaptchaSiteKey}\n size=\"normal\"\n />\n )}\n </div>\n </>\n )}\n {effectiveRecaptchaSiteKey && (\n <Button type=\"submit\" disabled={isLoading} className=\"w-full\">\n {isLoading ? \"Subscribing...\" : buttonText}\n </Button>\n )}\n </form>\n </div>\n );\n}\n"]}
|