@neowhale/storefront 0.2.19 → 0.2.21

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.
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var chunk7KXJLHGA_cjs = require('../chunk-7KXJLHGA.cjs');
4
- var chunkCQCCXDUS_cjs = require('../chunk-CQCCXDUS.cjs');
4
+ var chunkVAA2KKCH_cjs = require('../chunk-VAA2KKCH.cjs');
5
5
  var react = require('react');
6
6
  var navigation = require('next/navigation');
7
7
  var vanilla = require('zustand/vanilla');
@@ -1027,7 +1027,7 @@ function BehavioralTrackerComponent({ pathname }) {
1027
1027
  const baseUrl = config.proxyPath;
1028
1028
  const endpoint = `${baseUrl}/v1/stores/${config.storeId}/storefront/behavioral`;
1029
1029
  const sendBatch = async (batch) => {
1030
- await chunkCQCCXDUS_cjs.resilientSend(endpoint, batch, {
1030
+ await chunkVAA2KKCH_cjs.resilientSend(endpoint, batch, {
1031
1031
  "Content-Type": "application/json",
1032
1032
  "x-api-key": config.apiKey
1033
1033
  });
@@ -1213,7 +1213,7 @@ function FingerprintCollector() {
1213
1213
  collectFingerprint().then(async (fp) => {
1214
1214
  const baseUrl = config.proxyPath;
1215
1215
  const url = `${baseUrl}/v1/stores/${config.storeId}/storefront/fingerprints`;
1216
- await chunkCQCCXDUS_cjs.resilientSend(url, fp, {
1216
+ await chunkVAA2KKCH_cjs.resilientSend(url, fp, {
1217
1217
  "Content-Type": "application/json",
1218
1218
  "x-api-key": config.apiKey
1219
1219
  }).catch(() => {
@@ -1594,7 +1594,7 @@ function SessionRecorderComponent() {
1594
1594
  const sid = sessionId;
1595
1595
  const recorder = new SessionRecorder({
1596
1596
  sendChunk: async (events, sequence) => {
1597
- await chunkCQCCXDUS_cjs.resilientSend(url, {
1597
+ await chunkVAA2KKCH_cjs.resilientSend(url, {
1598
1598
  session_id: sid,
1599
1599
  visitor_id: visitorId,
1600
1600
  events,
@@ -1673,7 +1673,7 @@ function WhaleProvider({
1673
1673
  trackingEnabled: trackingEnabled ?? envBool("NEXT_PUBLIC_TRACKING_ENABLED") ?? true,
1674
1674
  recordingRate: recordingRate ?? envNumber("NEXT_PUBLIC_RECORDING_RATE") ?? 0.1
1675
1675
  };
1676
- const client = new chunkCQCCXDUS_cjs.WhaleClient({
1676
+ const client = new chunkVAA2KKCH_cjs.WhaleClient({
1677
1677
  storeId,
1678
1678
  apiKey,
1679
1679
  gatewayUrl: resolvedConfig.gatewayUrl,
@@ -1861,12 +1861,12 @@ function useCheckout() {
1861
1861
  setLoading(false);
1862
1862
  }
1863
1863
  }, [ctx.client, session]);
1864
- const complete = react.useCallback(async (payment) => {
1864
+ const complete = react.useCallback(async (payment, opts) => {
1865
1865
  if (!session) throw new Error("No active checkout session");
1866
1866
  setLoading(true);
1867
1867
  setError(null);
1868
1868
  try {
1869
- const order = await ctx.client.completeCheckout(session.id, payment);
1869
+ const order = await ctx.client.completeCheckout(session.id, payment, opts);
1870
1870
  setSession(null);
1871
1871
  return order;
1872
1872
  } catch (err) {
@@ -2020,7 +2020,11 @@ function useLoyalty() {
2020
2020
  await refresh();
2021
2021
  return result;
2022
2022
  }, [customer?.id, ctx.client, refresh]);
2023
- return { account, rewards, transactions, loading, error, refresh, redeemReward };
2023
+ const fetchProductsByCategory = react.useCallback(async (category, locationId, tier) => {
2024
+ const res = await ctx.client.listLoyaltyProducts({ category, location_id: locationId, tier });
2025
+ return res.data;
2026
+ }, [ctx.client]);
2027
+ return { account, rewards, transactions, loading, error, refresh, redeemReward, fetchProductsByCategory };
2024
2028
  }
2025
2029
  function useReviews(productId) {
2026
2030
  const ctx = react.useContext(WhaleContext);
@@ -2411,16 +2415,27 @@ function useReferral() {
2411
2415
  referredBy: status?.referred_by ?? null
2412
2416
  };
2413
2417
  }
2418
+ function trackClick(tracking, label, url, position) {
2419
+ if (!tracking?.gatewayUrl || !tracking?.code) return;
2420
+ const body = JSON.stringify({ label, url, position });
2421
+ if (typeof navigator !== "undefined" && navigator.sendBeacon) {
2422
+ navigator.sendBeacon(
2423
+ `${tracking.gatewayUrl}/q/${encodeURIComponent(tracking.code)}/click`,
2424
+ new Blob([body], { type: "application/json" })
2425
+ );
2426
+ }
2427
+ }
2414
2428
  function SectionRenderer({
2415
2429
  section,
2416
2430
  data,
2417
- theme
2431
+ theme,
2432
+ tracking
2418
2433
  }) {
2419
2434
  const [showCOA, setShowCOA] = react.useState(false);
2420
2435
  const el = (() => {
2421
2436
  switch (section.type) {
2422
2437
  case "hero":
2423
- return /* @__PURE__ */ jsxRuntime.jsx(HeroSection, { section, theme });
2438
+ return /* @__PURE__ */ jsxRuntime.jsx(HeroSection, { section, theme, tracking });
2424
2439
  case "text":
2425
2440
  return /* @__PURE__ */ jsxRuntime.jsx(TextSection, { section, theme });
2426
2441
  case "image":
@@ -2430,15 +2445,17 @@ function SectionRenderer({
2430
2445
  case "gallery":
2431
2446
  return /* @__PURE__ */ jsxRuntime.jsx(GallerySection, { section, theme });
2432
2447
  case "cta":
2433
- return /* @__PURE__ */ jsxRuntime.jsx(CTASection, { section, theme });
2448
+ return /* @__PURE__ */ jsxRuntime.jsx(CTASection, { section, theme, tracking });
2434
2449
  case "stats":
2435
2450
  return /* @__PURE__ */ jsxRuntime.jsx(StatsSection, { section, theme });
2436
2451
  case "product_card":
2437
- return /* @__PURE__ */ jsxRuntime.jsx(ProductCardSection, { section, data, theme });
2452
+ return /* @__PURE__ */ jsxRuntime.jsx(ProductCardSection, { section, data, theme, tracking });
2438
2453
  case "coa_viewer":
2439
- return /* @__PURE__ */ jsxRuntime.jsx(COAViewerSection, { section, data, theme, onShowCOA: () => setShowCOA(true) });
2454
+ return /* @__PURE__ */ jsxRuntime.jsx(COAViewerSection, { section, data, theme, onShowCOA: () => setShowCOA(true), tracking });
2440
2455
  case "social_links":
2441
2456
  return /* @__PURE__ */ jsxRuntime.jsx(SocialLinksSection, { section, theme });
2457
+ case "lead_capture":
2458
+ return /* @__PURE__ */ jsxRuntime.jsx(LeadCaptureSection, { section, data, theme });
2442
2459
  case "divider":
2443
2460
  return /* @__PURE__ */ jsxRuntime.jsx(DividerSection, { theme });
2444
2461
  default:
@@ -2450,7 +2467,7 @@ function SectionRenderer({
2450
2467
  showCOA && data?.coa && /* @__PURE__ */ jsxRuntime.jsx(COAModal, { coa: data.coa, theme, onClose: () => setShowCOA(false) })
2451
2468
  ] });
2452
2469
  }
2453
- function HeroSection({ section, theme }) {
2470
+ function HeroSection({ section, theme, tracking }) {
2454
2471
  const { title, subtitle, background_image, cta_text, cta_url } = section.content;
2455
2472
  return /* @__PURE__ */ jsxRuntime.jsxs(
2456
2473
  "div",
@@ -2492,6 +2509,7 @@ function HeroSection({ section, theme }) {
2492
2509
  "a",
2493
2510
  {
2494
2511
  href: cta_url,
2512
+ onClick: () => trackClick(tracking, cta_text, cta_url),
2495
2513
  style: {
2496
2514
  display: "inline-block",
2497
2515
  padding: "0.875rem 2rem",
@@ -2577,35 +2595,57 @@ function GallerySection({ section, theme }) {
2577
2595
  }
2578
2596
  ) }, i)) }) });
2579
2597
  }
2580
- function CTASection({ section, theme }) {
2581
- const { buttons } = section.content;
2598
+ function CTASection({ section, theme, tracking }) {
2599
+ const { title, subtitle, buttons } = section.content;
2582
2600
  if (!buttons || buttons.length === 0) return null;
2583
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "2rem 1.5rem", maxWidth: 480, margin: "0 auto", display: "flex", flexDirection: "column", gap: "0.75rem" }, children: buttons.map((btn, i) => {
2584
- const isPrimary = btn.style !== "outline";
2585
- return /* @__PURE__ */ jsxRuntime.jsx(
2586
- "a",
2587
- {
2588
- href: btn.url,
2589
- style: {
2590
- display: "block",
2591
- width: "100%",
2592
- padding: "0.875rem",
2593
- background: isPrimary ? theme.fg : "transparent",
2594
- color: isPrimary ? theme.bg : theme.fg,
2595
- border: isPrimary ? "none" : `1px solid ${theme.fg}20`,
2596
- fontSize: "0.85rem",
2597
- fontWeight: 500,
2598
- textAlign: "center",
2599
- textDecoration: "none",
2600
- boxSizing: "border-box",
2601
- letterSpacing: "0.08em",
2602
- textTransform: "uppercase"
2601
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "2rem 1.5rem", maxWidth: 480, margin: "0 auto", display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2602
+ title && /* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
2603
+ fontSize: "clamp(1.25rem, 4vw, 1.5rem)",
2604
+ fontWeight: 300,
2605
+ fontFamily: theme.fontDisplay || "inherit",
2606
+ margin: "0 0 0.25rem",
2607
+ lineHeight: 1.2,
2608
+ letterSpacing: "-0.02em",
2609
+ color: theme.fg,
2610
+ textAlign: "center"
2611
+ }, children: title }),
2612
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
2613
+ fontSize: "0.8rem",
2614
+ color: theme.accent,
2615
+ margin: "0 0 0.75rem",
2616
+ lineHeight: 1.6,
2617
+ textTransform: "uppercase",
2618
+ letterSpacing: "0.15em",
2619
+ textAlign: "center"
2620
+ }, children: subtitle }),
2621
+ buttons.map((btn, i) => {
2622
+ const isPrimary = btn.style !== "outline";
2623
+ return /* @__PURE__ */ jsxRuntime.jsx(
2624
+ "a",
2625
+ {
2626
+ href: btn.url,
2627
+ onClick: () => trackClick(tracking, btn.text, btn.url, i),
2628
+ style: {
2629
+ display: "block",
2630
+ width: "100%",
2631
+ padding: "0.875rem",
2632
+ background: isPrimary ? theme.fg : "transparent",
2633
+ color: isPrimary ? theme.bg : theme.fg,
2634
+ border: isPrimary ? "none" : `1px solid ${theme.fg}20`,
2635
+ fontSize: "0.85rem",
2636
+ fontWeight: 500,
2637
+ textAlign: "center",
2638
+ textDecoration: "none",
2639
+ boxSizing: "border-box",
2640
+ letterSpacing: "0.08em",
2641
+ textTransform: "uppercase"
2642
+ },
2643
+ children: btn.text
2603
2644
  },
2604
- children: btn.text
2605
- },
2606
- i
2607
- );
2608
- }) });
2645
+ i
2646
+ );
2647
+ })
2648
+ ] });
2609
2649
  }
2610
2650
  function StatsSection({ section, theme }) {
2611
2651
  const { stats } = section.content;
@@ -2657,7 +2697,7 @@ function StatsSection({ section, theme }) {
2657
2697
  }, children: stat.label })
2658
2698
  ] }, i)) }) });
2659
2699
  }
2660
- function ProductCardSection({ section, data, theme }) {
2700
+ function ProductCardSection({ section, data, theme, tracking }) {
2661
2701
  const product = data?.product;
2662
2702
  const c = section.content;
2663
2703
  const name = c.name || product?.name || "";
@@ -2673,6 +2713,7 @@ function ProductCardSection({ section, data, theme }) {
2673
2713
  "a",
2674
2714
  {
2675
2715
  href: url,
2716
+ onClick: () => trackClick(tracking, "View Product", url),
2676
2717
  style: {
2677
2718
  display: "block",
2678
2719
  width: "100%",
@@ -2697,7 +2738,8 @@ function COAViewerSection({
2697
2738
  section,
2698
2739
  data,
2699
2740
  theme,
2700
- onShowCOA
2741
+ onShowCOA,
2742
+ tracking
2701
2743
  }) {
2702
2744
  const coa = data?.coa;
2703
2745
  const c = section.content;
@@ -2718,10 +2760,200 @@ function COAViewerSection({
2718
2760
  display: "block",
2719
2761
  boxSizing: "border-box"
2720
2762
  };
2763
+ const buttonLabel = c.button_text || "View Lab Results";
2721
2764
  if (coa.viewer_url) {
2722
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: coa.viewer_url, target: "_blank", rel: "noopener noreferrer", style: buttonStyle, children: c.button_text || "View Lab Results" }) });
2765
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(
2766
+ "a",
2767
+ {
2768
+ href: coa.viewer_url,
2769
+ target: "_blank",
2770
+ rel: "noopener noreferrer",
2771
+ onClick: () => trackClick(tracking, buttonLabel, coa.viewer_url),
2772
+ style: buttonStyle,
2773
+ children: buttonLabel
2774
+ }
2775
+ ) });
2723
2776
  }
2724
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onShowCOA, style: buttonStyle, children: c.button_text || "View Lab Results" }) });
2777
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => {
2778
+ trackClick(tracking, buttonLabel, coa.url);
2779
+ onShowCOA();
2780
+ }, style: buttonStyle, children: buttonLabel }) });
2781
+ }
2782
+ function LeadCaptureSection({ section, data, theme }) {
2783
+ const c = section.content;
2784
+ const [firstName, setFirstName] = react.useState("");
2785
+ const [email, setEmail] = react.useState("");
2786
+ const [status, setStatus] = react.useState("idle");
2787
+ const [errorMsg, setErrorMsg] = react.useState("");
2788
+ const gatewayUrl = c.gateway_url || data.gatewayUrl || "https://whale-gateway.fly.dev";
2789
+ const storeId = c.store_id || data.store?.id;
2790
+ const slug = c.landing_page_slug || data.landing_page?.slug;
2791
+ async function handleSubmit(e) {
2792
+ e.preventDefault();
2793
+ if (!email || !storeId) return;
2794
+ setStatus("loading");
2795
+ setErrorMsg("");
2796
+ try {
2797
+ const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
2798
+ method: "POST",
2799
+ headers: { "Content-Type": "application/json" },
2800
+ body: JSON.stringify({
2801
+ email,
2802
+ first_name: firstName || void 0,
2803
+ source: c.source || "landing_page",
2804
+ landing_page_slug: slug || void 0,
2805
+ tags: c.tags || void 0
2806
+ })
2807
+ });
2808
+ if (!res.ok) {
2809
+ const body = await res.json().catch(() => ({}));
2810
+ throw new Error(body?.error?.message || "Something went wrong. Please try again.");
2811
+ }
2812
+ setStatus("success");
2813
+ } catch (err) {
2814
+ setErrorMsg(err instanceof Error ? err.message : "Something went wrong. Please try again.");
2815
+ setStatus("error");
2816
+ }
2817
+ }
2818
+ const heading = c.heading || "get 10% off your first visit.";
2819
+ const subtitle = c.subtitle || "drop your email and we will send you the code.";
2820
+ const buttonText = c.button_text || "Claim My Discount";
2821
+ const successHeading = c.success_heading || "You\u2019re in!";
2822
+ const successMessage = c.success_message || "Check your inbox for the discount code.";
2823
+ const inputStyle = {
2824
+ flex: 1,
2825
+ minWidth: 0,
2826
+ padding: "0.875rem 1rem",
2827
+ background: theme.surface,
2828
+ border: `1px solid ${theme.fg}15`,
2829
+ color: theme.fg,
2830
+ fontSize: "0.95rem",
2831
+ fontWeight: 300,
2832
+ outline: "none",
2833
+ boxSizing: "border-box",
2834
+ fontFamily: "inherit",
2835
+ transition: "border-color 0.2s"
2836
+ };
2837
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "3.5rem 1.5rem", maxWidth: 560, margin: "0 auto" }, children: [
2838
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: `@keyframes lc-spin { to { transform: rotate(360deg) } }` }),
2839
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2840
+ background: theme.surface,
2841
+ border: `1px solid ${theme.fg}12`,
2842
+ padding: "clamp(2rem, 6vw, 3rem)"
2843
+ }, children: status === "success" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center" }, children: [
2844
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
2845
+ fontSize: "clamp(1.5rem, 5vw, 2rem)",
2846
+ fontWeight: 300,
2847
+ fontFamily: theme.fontDisplay || "inherit",
2848
+ margin: "0 0 0.75rem",
2849
+ lineHeight: 1.2,
2850
+ letterSpacing: "-0.02em",
2851
+ color: theme.fg
2852
+ }, children: successHeading }),
2853
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
2854
+ fontSize: "0.9rem",
2855
+ color: `${theme.fg}99`,
2856
+ margin: "0 0 1.5rem",
2857
+ lineHeight: 1.6,
2858
+ fontWeight: 300
2859
+ }, children: successMessage }),
2860
+ c.coupon_code && /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
2861
+ display: "inline-block",
2862
+ padding: "0.75rem 2rem",
2863
+ background: `${theme.fg}08`,
2864
+ border: `1px dashed ${theme.fg}30`,
2865
+ fontSize: "clamp(1.25rem, 4vw, 1.75rem)",
2866
+ fontWeight: 500,
2867
+ fontFamily: "monospace",
2868
+ letterSpacing: "0.12em",
2869
+ color: theme.accent
2870
+ }, children: c.coupon_code })
2871
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2872
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", marginBottom: "clamp(1.5rem, 4vw, 2rem)" }, children: [
2873
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: {
2874
+ fontSize: "clamp(1.5rem, 5vw, 2.25rem)",
2875
+ fontWeight: 300,
2876
+ fontFamily: theme.fontDisplay || "inherit",
2877
+ margin: "0 0 0.5rem",
2878
+ lineHeight: 1.15,
2879
+ letterSpacing: "-0.02em",
2880
+ color: theme.fg
2881
+ }, children: heading }),
2882
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: {
2883
+ fontSize: "0.85rem",
2884
+ color: theme.accent,
2885
+ margin: 0,
2886
+ lineHeight: 1.6,
2887
+ textTransform: "uppercase",
2888
+ letterSpacing: "0.15em"
2889
+ }, children: subtitle })
2890
+ ] }),
2891
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2892
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "0.75rem", flexWrap: "wrap" }, children: [
2893
+ /* @__PURE__ */ jsxRuntime.jsx(
2894
+ "input",
2895
+ {
2896
+ type: "text",
2897
+ placeholder: "First name",
2898
+ value: firstName,
2899
+ onChange: (e) => setFirstName(e.target.value),
2900
+ style: inputStyle
2901
+ }
2902
+ ),
2903
+ /* @__PURE__ */ jsxRuntime.jsx(
2904
+ "input",
2905
+ {
2906
+ type: "email",
2907
+ placeholder: "Email address",
2908
+ value: email,
2909
+ onChange: (e) => setEmail(e.target.value),
2910
+ required: true,
2911
+ style: inputStyle
2912
+ }
2913
+ )
2914
+ ] }),
2915
+ status === "error" && errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.8rem", color: "#e55", margin: 0, fontWeight: 400 }, children: errorMsg }),
2916
+ /* @__PURE__ */ jsxRuntime.jsxs(
2917
+ "button",
2918
+ {
2919
+ type: "submit",
2920
+ disabled: status === "loading",
2921
+ style: {
2922
+ width: "100%",
2923
+ padding: "0.875rem",
2924
+ background: theme.fg,
2925
+ color: theme.bg,
2926
+ border: "none",
2927
+ fontSize: "0.85rem",
2928
+ fontWeight: 500,
2929
+ cursor: status === "loading" ? "wait" : "pointer",
2930
+ letterSpacing: "0.08em",
2931
+ textTransform: "uppercase",
2932
+ fontFamily: "inherit",
2933
+ display: "flex",
2934
+ alignItems: "center",
2935
+ justifyContent: "center",
2936
+ gap: "0.5rem",
2937
+ opacity: status === "loading" ? 0.7 : 1,
2938
+ transition: "opacity 0.2s"
2939
+ },
2940
+ children: [
2941
+ status === "loading" && /* @__PURE__ */ jsxRuntime.jsx("span", { style: {
2942
+ display: "inline-block",
2943
+ width: 16,
2944
+ height: 16,
2945
+ border: `2px solid ${theme.bg}40`,
2946
+ borderTopColor: theme.bg,
2947
+ borderRadius: "50%",
2948
+ animation: "lc-spin 0.8s linear infinite"
2949
+ } }),
2950
+ buttonText
2951
+ ]
2952
+ }
2953
+ )
2954
+ ] })
2955
+ ] }) })
2956
+ ] });
2725
2957
  }
2726
2958
  function SocialLinksSection({ section, theme }) {
2727
2959
  const { links } = section.content;
@@ -2844,15 +3076,16 @@ function QRLandingPage({
2844
3076
  const logoUrl = data.qr_code.logo_url || data.store?.logo_url;
2845
3077
  const storeName = data.store?.name;
2846
3078
  const sorted = [...sections].sort((a, b) => a.order - b.order);
3079
+ const tracking = { gatewayUrl, code };
2847
3080
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minHeight: "100dvh", background: theme.bg, color: theme.fg, fontFamily }, children: [
2848
3081
  lp?.custom_css && /* @__PURE__ */ jsxRuntime.jsx("style", { children: lp.custom_css }),
2849
3082
  logoUrl && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "1.5rem", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: logoUrl, alt: storeName || "Store", style: { height: 40, objectFit: "contain" } }) }),
2850
3083
  sorted.map((section) => {
2851
- const defaultRenderer = () => /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data, theme }, section.id);
3084
+ const defaultRenderer = () => /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data, theme, tracking }, section.id);
2852
3085
  if (renderSection) {
2853
3086
  return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderSection(section, defaultRenderer) }, section.id);
2854
3087
  }
2855
- return /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data, theme }, section.id);
3088
+ return /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data, theme, tracking }, section.id);
2856
3089
  }),
2857
3090
  storeName && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "2rem 1.5rem", borderTop: `1px solid ${theme.surface}`, textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: "0.75rem", color: theme.muted, margin: 0 }, children: [
2858
3091
  storeName,
@@ -3102,10 +3335,11 @@ function LandingPage({
3102
3335
  if (state === "expired") return /* @__PURE__ */ jsxRuntime.jsx(DefaultExpired2, {});
3103
3336
  if (state === "error") return /* @__PURE__ */ jsxRuntime.jsx(DefaultError2, { message: errorMsg });
3104
3337
  if (!data) return null;
3105
- return /* @__PURE__ */ jsxRuntime.jsx(PageLayout, { data, renderSection });
3338
+ return /* @__PURE__ */ jsxRuntime.jsx(PageLayout, { data, gatewayUrl, renderSection });
3106
3339
  }
3107
3340
  function PageLayout({
3108
3341
  data,
3342
+ gatewayUrl,
3109
3343
  renderSection
3110
3344
  }) {
3111
3345
  const { landing_page: lp, store } = data;
@@ -3121,15 +3355,16 @@ function PageLayout({
3121
3355
  const fontFamily = lp.font_family || theme.fontDisplay || "system-ui, -apple-system, sans-serif";
3122
3356
  const logoUrl = store?.logo_url;
3123
3357
  const sorted = [...lp.sections].sort((a, b) => a.order - b.order);
3358
+ const sectionData = { ...data, gatewayUrl, landing_page: { slug: lp.slug } };
3124
3359
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minHeight: "100dvh", background: theme.bg, color: theme.fg, fontFamily }, children: [
3125
3360
  lp.custom_css && /* @__PURE__ */ jsxRuntime.jsx("style", { children: lp.custom_css }),
3126
3361
  logoUrl && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "1.5rem", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: logoUrl, alt: store?.name || "Store", style: { height: 40, objectFit: "contain" } }) }),
3127
3362
  sorted.map((section) => {
3128
- const defaultRenderer = () => /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data, theme }, section.id);
3363
+ const defaultRenderer = () => /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data: sectionData, theme }, section.id);
3129
3364
  if (renderSection) {
3130
3365
  return /* @__PURE__ */ jsxRuntime.jsx("div", { children: renderSection(section, defaultRenderer) }, section.id);
3131
3366
  }
3132
- return /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data, theme }, section.id);
3367
+ return /* @__PURE__ */ jsxRuntime.jsx(SectionRenderer, { section, data: sectionData, theme }, section.id);
3133
3368
  }),
3134
3369
  store?.name && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "2rem 1.5rem", borderTop: `1px solid ${theme.surface}`, textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsxs("p", { style: { fontSize: "0.75rem", color: theme.muted, margin: 0 }, children: [
3135
3370
  "Powered by ",