@neowhale/storefront 0.2.57 → 0.2.59

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.
@@ -2304,6 +2304,8 @@ function HeroSection({ section, theme, tracking, onEvent, data }) {
2304
2304
  onSubmit: handleSubmit,
2305
2305
  successHeading: c.inline_form.success_heading || "you're in.",
2306
2306
  successMessage: c.inline_form.success_message || "check your inbox.",
2307
+ successCtaText: c.inline_form.success_cta_text,
2308
+ successCtaUrl: c.inline_form.success_cta_url,
2307
2309
  submitText: c.inline_form.button_text || "send my code",
2308
2310
  theme,
2309
2311
  onEvent,
@@ -2335,12 +2337,36 @@ function HeroSection({ section, theme, tracking, onEvent, data }) {
2335
2337
  ] })
2336
2338
  ] });
2337
2339
  }
2338
- function HeroInlineForm({ ctaText, formOpen, setFormOpen, firstName, setFirstName, email, setEmail, status, errorMsg, onSubmit, successHeading, successMessage, submitText, theme, onEvent, tracking }) {
2340
+ function HeroInlineForm({ ctaText, formOpen, setFormOpen, firstName, setFirstName, email, setEmail, status, errorMsg, onSubmit, successHeading, successMessage, successCtaText, successCtaUrl, submitText, theme, onEvent, tracking }) {
2339
2341
  const formMaxW = "min(480px, 90vw)";
2340
2342
  if (status === "success") {
2341
2343
  return /* @__PURE__ */ jsxs("div", { style: { maxWidth: formMaxW, margin: "0 auto", padding: "1.5rem 2rem", background: `${theme.fg}06`, border: `1px solid ${theme.fg}10` }, children: [
2342
2344
  /* @__PURE__ */ jsx("p", { style: { fontSize: "clamp(1rem, 3vw, 1.25rem)", fontWeight: 300, color: theme.fg, margin: "0 0 0.375rem", fontFamily: theme.fontDisplay || "inherit" }, children: successHeading }),
2343
- /* @__PURE__ */ jsx("p", { style: { fontSize: "0.85rem", color: `${theme.fg}70`, margin: 0, lineHeight: 1.5 }, children: successMessage })
2345
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.85rem", color: `${theme.fg}70`, margin: 0, lineHeight: 1.5 }, children: successMessage }),
2346
+ successCtaUrl && /* @__PURE__ */ jsx(
2347
+ "button",
2348
+ {
2349
+ onClick: () => {
2350
+ window.location.href = successCtaUrl;
2351
+ onEvent?.("cta_click", { label: successCtaText || "shop now", url: successCtaUrl });
2352
+ },
2353
+ style: {
2354
+ marginTop: "1rem",
2355
+ width: "100%",
2356
+ padding: "0.875rem",
2357
+ background: theme.accent || theme.fg,
2358
+ color: "#fff",
2359
+ border: "none",
2360
+ fontSize: "0.85rem",
2361
+ fontWeight: 500,
2362
+ cursor: "pointer",
2363
+ letterSpacing: "0.08em",
2364
+ textTransform: "uppercase",
2365
+ fontFamily: "inherit"
2366
+ },
2367
+ children: successCtaText || "shop now"
2368
+ }
2369
+ )
2344
2370
  ] });
2345
2371
  }
2346
2372
  if (!formOpen) {
@@ -2863,6 +2889,25 @@ function COAModal({ coa, theme, onClose }) {
2863
2889
  /* @__PURE__ */ jsx("iframe", { src: coa.url, style: { flex: 1, border: "none", background: "#fff" }, title: "Lab Results" })
2864
2890
  ] });
2865
2891
  }
2892
+ var TURNSTILE_SITE_KEY = "0x4AAAAAACwmUPgmyfw6pWfT";
2893
+ var TURNSTILE_SCRIPT_URL = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
2894
+ var turnstilePromise = null;
2895
+ function loadTurnstileScript() {
2896
+ if (turnstilePromise) return turnstilePromise;
2897
+ if (typeof window !== "undefined" && window.turnstile) {
2898
+ turnstilePromise = Promise.resolve();
2899
+ return turnstilePromise;
2900
+ }
2901
+ turnstilePromise = new Promise((resolve, reject) => {
2902
+ const script = document.createElement("script");
2903
+ script.src = TURNSTILE_SCRIPT_URL;
2904
+ script.async = true;
2905
+ script.onload = () => resolve();
2906
+ script.onerror = () => reject(new Error("Failed to load Turnstile script"));
2907
+ document.head.appendChild(script);
2908
+ });
2909
+ return turnstilePromise;
2910
+ }
2866
2911
  function LeadCaptureSection({ section, data, theme, onEvent }) {
2867
2912
  const c = section.content;
2868
2913
  const [firstName, setFirstName] = useState("");
@@ -2871,6 +2916,41 @@ function LeadCaptureSection({ section, data, theme, onEvent }) {
2871
2916
  const [status, setStatus] = useState("idle");
2872
2917
  const [errorMsg, setErrorMsg] = useState("");
2873
2918
  const [serverMessage, setServerMessage] = useState(null);
2919
+ const turnstileRef = useRef(null);
2920
+ const turnstileToken = useRef(null);
2921
+ const turnstileWidgetId = useRef(null);
2922
+ const pendingSubmit = useRef(null);
2923
+ const onTurnstileToken = useCallback((token) => {
2924
+ turnstileToken.current = token;
2925
+ if (pendingSubmit.current) {
2926
+ const cb = pendingSubmit.current;
2927
+ pendingSubmit.current = null;
2928
+ cb();
2929
+ }
2930
+ }, []);
2931
+ useEffect(() => {
2932
+ if (typeof window === "undefined") return;
2933
+ let widgetId = null;
2934
+ loadTurnstileScript().then(() => {
2935
+ const el = turnstileRef.current;
2936
+ if (!el || !window.turnstile) return;
2937
+ widgetId = window.turnstile.render(el, {
2938
+ sitekey: TURNSTILE_SITE_KEY,
2939
+ callback: onTurnstileToken,
2940
+ "expired-callback": () => {
2941
+ turnstileToken.current = null;
2942
+ },
2943
+ size: "invisible"
2944
+ });
2945
+ turnstileWidgetId.current = widgetId;
2946
+ }).catch(() => {
2947
+ });
2948
+ return () => {
2949
+ if (widgetId != null && window.turnstile) {
2950
+ window.turnstile.remove(widgetId);
2951
+ }
2952
+ };
2953
+ }, [onTurnstileToken]);
2874
2954
  const gatewayUrl = c.gateway_url || data.gatewayUrl || "https://whale-gateway.fly.dev";
2875
2955
  const storeId = c.store_id || data.store?.id;
2876
2956
  const slug = c.landing_page_slug || data.landing_page?.slug;
@@ -2879,11 +2959,7 @@ function LeadCaptureSection({ section, data, theme, onEvent }) {
2879
2959
  const buttonText = c.button_text || "Claim My Discount";
2880
2960
  const successHeading = c.success_heading || "You\u2019re in!";
2881
2961
  const successMessage = c.success_message || "Check your inbox for the discount code.";
2882
- async function handleSubmit(e) {
2883
- e.preventDefault();
2884
- if (!email || !storeId) return;
2885
- setStatus("loading");
2886
- setErrorMsg("");
2962
+ async function submitLead(cfToken) {
2887
2963
  const urlParams = typeof window !== "undefined" ? new URLSearchParams(window.location.search) : null;
2888
2964
  try {
2889
2965
  const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
@@ -2905,7 +2981,8 @@ function LeadCaptureSection({ section, data, theme, onEvent }) {
2905
2981
  utm_source: urlParams?.get("utm_source") || void 0,
2906
2982
  utm_medium: urlParams?.get("utm_medium") || void 0,
2907
2983
  utm_campaign: urlParams?.get("utm_campaign") || void 0,
2908
- utm_content: urlParams?.get("utm_content") || void 0
2984
+ utm_content: urlParams?.get("utm_content") || void 0,
2985
+ cf_turnstile_response: cfToken || void 0
2909
2986
  })
2910
2987
  });
2911
2988
  if (!res.ok) {
@@ -2926,6 +3003,22 @@ function LeadCaptureSection({ section, data, theme, onEvent }) {
2926
3003
  setStatus("error");
2927
3004
  }
2928
3005
  }
3006
+ async function handleSubmit(e) {
3007
+ e.preventDefault();
3008
+ if (!email || !storeId) return;
3009
+ setStatus("loading");
3010
+ setErrorMsg("");
3011
+ if (turnstileToken.current) {
3012
+ return submitLead(turnstileToken.current);
3013
+ }
3014
+ const turnstile = window.turnstile;
3015
+ if (turnstile && turnstileWidgetId.current != null) {
3016
+ pendingSubmit.current = () => submitLead(turnstileToken.current);
3017
+ turnstile.execute(turnstileWidgetId.current);
3018
+ } else {
3019
+ return submitLead(null);
3020
+ }
3021
+ }
2929
3022
  const inputStyle = {
2930
3023
  flex: 1,
2931
3024
  minWidth: 0,
@@ -3019,7 +3112,8 @@ function LeadCaptureSection({ section, data, theme, onEvent }) {
3019
3112
  animation: "lc-spin 0.8s linear infinite"
3020
3113
  } }),
3021
3114
  buttonText
3022
- ] })
3115
+ ] }),
3116
+ /* @__PURE__ */ jsx("div", { ref: turnstileRef, style: { display: "none" } })
3023
3117
  ] })
3024
3118
  ] })
3025
3119
  ] });