@neowhale/storefront 0.2.19 → 0.2.20

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,11 +1,11 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { F as WhaleStorefrontConfig, r as Product, P as PaymentData, O as Order, a as CartItem, T as TaxBreakdown, W as WhaleClient, f as Customer, E as EventType, g as CustomerAnalytics, d as CheckoutSession, A as Address, b as Category, c as CategoryTreeNode, l as LoyaltyAccount, m as LoyaltyReward, n as LoyaltyTransaction, v as Review, w as ReviewSummary, G as WishlistItem, R as Recommendation, k as Location, x as ShippingMethod, y as ShippingRate, D as DealValidation, C as Cart, H as ReferralStatus, I as ReferralEnrollment, i as LandingSection, Q as QRLandingData, h as LandingPageRenderData } from '../client-D1XVKpFt.cjs';
4
+ import { F as WhaleStorefrontConfig, r as Product, P as PaymentData, O as Order, a as CartItem, T as TaxBreakdown, W as WhaleClient, f as Customer, E as EventType, g as CustomerAnalytics, d as CheckoutSession, A as Address, b as Category, c as CategoryTreeNode, l as LoyaltyAccount, m as LoyaltyReward, n as LoyaltyTransaction, v as Review, w as ReviewSummary, G as WishlistItem, R as Recommendation, k as Location, x as ShippingMethod, y as ShippingRate, D as DealValidation, C as Cart, H as ReferralStatus, I as ReferralEnrollment, i as LandingSection, Q as QRLandingData, h as LandingPageRenderData } from '../client-BSO263Uv.cjs';
5
5
  import { ThemeTokens } from '@neowhale/ui';
6
6
  import * as zustand_middleware from 'zustand/middleware';
7
7
  import * as zustand from 'zustand';
8
- import { P as PixelManager } from '../pixel-manager-DZwpn_x2.cjs';
8
+ import { P as PixelManager } from '../pixel-manager-DJ9m2FaQ.cjs';
9
9
 
10
10
  interface WhaleProviderProps extends WhaleStorefrontConfig {
11
11
  children: ReactNode;
@@ -257,6 +257,8 @@ declare function useCheckout(): {
257
257
  billing_address?: Address;
258
258
  shipping_method_id?: string;
259
259
  coupon_code?: string;
260
+ loyalty_reward_id?: string;
261
+ selected_product_id?: string;
260
262
  }) => Promise<CheckoutSession>;
261
263
  updateSession: (params: {
262
264
  customer_email?: string;
@@ -265,7 +267,10 @@ declare function useCheckout(): {
265
267
  shipping_method_id?: string;
266
268
  coupon_code?: string;
267
269
  }) => Promise<CheckoutSession>;
268
- complete: (payment?: PaymentData) => Promise<Order>;
270
+ complete: (payment?: PaymentData, opts?: {
271
+ loyalty_reward_id?: string;
272
+ selected_product_id?: string;
273
+ }) => Promise<Order>;
269
274
  reset: () => void;
270
275
  };
271
276
 
@@ -308,6 +313,7 @@ declare function useLoyalty(): {
308
313
  success: boolean;
309
314
  points_remaining: number;
310
315
  }>;
316
+ fetchProductsByCategory: (category: string, locationId: string, tier?: string) => Promise<Product[]>;
311
317
  };
312
318
 
313
319
  declare function useReviews(productId: string | null | undefined): {
@@ -431,8 +437,13 @@ interface SectionTheme {
431
437
  fontDisplay?: string;
432
438
  fontBody?: string;
433
439
  }
440
+ interface ClickTrackingContext {
441
+ gatewayUrl?: string;
442
+ code?: string;
443
+ }
434
444
  interface SectionData {
435
445
  store?: {
446
+ id?: string;
436
447
  name?: string | null;
437
448
  logo_url?: string | null;
438
449
  tagline?: string | null;
@@ -444,11 +455,16 @@ interface SectionData {
444
455
  viewer_url?: string | null;
445
456
  document_name: string;
446
457
  } | null;
458
+ gatewayUrl?: string;
459
+ landing_page?: {
460
+ slug?: string;
461
+ } | null;
447
462
  }
448
- declare function SectionRenderer({ section, data, theme, }: {
463
+ declare function SectionRenderer({ section, data, theme, tracking, }: {
449
464
  section: LandingSection;
450
465
  data: SectionData;
451
466
  theme: SectionTheme;
467
+ tracking?: ClickTrackingContext;
452
468
  }): react_jsx_runtime.JSX.Element;
453
469
 
454
470
  /**
@@ -495,4 +511,4 @@ declare function FingerprintCollector(): null;
495
511
 
496
512
  declare function SessionRecorderComponent(): null;
497
513
 
498
- export { AnalyticsTracker, type AuthActions, AuthInitializer, type AuthState, type AuthStore, BehavioralTrackerComponent, type CartActions, CartInitializer, type CartState, type CartStore, FingerprintCollector, LandingPage, type LandingPageProps, PixelInitializer, QRLandingPage, type QRLandingPageProps, type SearchParams, SectionRenderer, type SectionTheme, SessionRecorderComponent, WhaleContext, type WhaleContextValue, WhaleProvider, type WhaleProviderProps, useAnalytics, useAuth, useCart, useCartItemCount, useCartTotal, useCategories, useCheckout, useCoupons, useCustomerAnalytics, useCustomerOrders, useDeals, useLocations, useLoyalty, useProduct, useProducts, useRecommendations, useReferral, useReviews, useSearch, useShipping, useWhaleClient, useWishlist };
514
+ export { AnalyticsTracker, type AuthActions, AuthInitializer, type AuthState, type AuthStore, BehavioralTrackerComponent, type CartActions, CartInitializer, type CartState, type CartStore, type ClickTrackingContext, FingerprintCollector, LandingPage, type LandingPageProps, PixelInitializer, QRLandingPage, type QRLandingPageProps, type SearchParams, SectionRenderer, type SectionTheme, SessionRecorderComponent, WhaleContext, type WhaleContextValue, WhaleProvider, type WhaleProviderProps, useAnalytics, useAuth, useCart, useCartItemCount, useCartTotal, useCategories, useCheckout, useCoupons, useCustomerAnalytics, useCustomerOrders, useDeals, useLocations, useLoyalty, useProduct, useProducts, useRecommendations, useReferral, useReviews, useSearch, useShipping, useWhaleClient, useWishlist };
@@ -1,11 +1,11 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { F as WhaleStorefrontConfig, r as Product, P as PaymentData, O as Order, a as CartItem, T as TaxBreakdown, W as WhaleClient, f as Customer, E as EventType, g as CustomerAnalytics, d as CheckoutSession, A as Address, b as Category, c as CategoryTreeNode, l as LoyaltyAccount, m as LoyaltyReward, n as LoyaltyTransaction, v as Review, w as ReviewSummary, G as WishlistItem, R as Recommendation, k as Location, x as ShippingMethod, y as ShippingRate, D as DealValidation, C as Cart, H as ReferralStatus, I as ReferralEnrollment, i as LandingSection, Q as QRLandingData, h as LandingPageRenderData } from '../client-D1XVKpFt.js';
4
+ import { F as WhaleStorefrontConfig, r as Product, P as PaymentData, O as Order, a as CartItem, T as TaxBreakdown, W as WhaleClient, f as Customer, E as EventType, g as CustomerAnalytics, d as CheckoutSession, A as Address, b as Category, c as CategoryTreeNode, l as LoyaltyAccount, m as LoyaltyReward, n as LoyaltyTransaction, v as Review, w as ReviewSummary, G as WishlistItem, R as Recommendation, k as Location, x as ShippingMethod, y as ShippingRate, D as DealValidation, C as Cart, H as ReferralStatus, I as ReferralEnrollment, i as LandingSection, Q as QRLandingData, h as LandingPageRenderData } from '../client-BSO263Uv.js';
5
5
  import { ThemeTokens } from '@neowhale/ui';
6
6
  import * as zustand_middleware from 'zustand/middleware';
7
7
  import * as zustand from 'zustand';
8
- import { P as PixelManager } from '../pixel-manager-C6PAp7vQ.js';
8
+ import { P as PixelManager } from '../pixel-manager-BcL95odX.js';
9
9
 
10
10
  interface WhaleProviderProps extends WhaleStorefrontConfig {
11
11
  children: ReactNode;
@@ -257,6 +257,8 @@ declare function useCheckout(): {
257
257
  billing_address?: Address;
258
258
  shipping_method_id?: string;
259
259
  coupon_code?: string;
260
+ loyalty_reward_id?: string;
261
+ selected_product_id?: string;
260
262
  }) => Promise<CheckoutSession>;
261
263
  updateSession: (params: {
262
264
  customer_email?: string;
@@ -265,7 +267,10 @@ declare function useCheckout(): {
265
267
  shipping_method_id?: string;
266
268
  coupon_code?: string;
267
269
  }) => Promise<CheckoutSession>;
268
- complete: (payment?: PaymentData) => Promise<Order>;
270
+ complete: (payment?: PaymentData, opts?: {
271
+ loyalty_reward_id?: string;
272
+ selected_product_id?: string;
273
+ }) => Promise<Order>;
269
274
  reset: () => void;
270
275
  };
271
276
 
@@ -308,6 +313,7 @@ declare function useLoyalty(): {
308
313
  success: boolean;
309
314
  points_remaining: number;
310
315
  }>;
316
+ fetchProductsByCategory: (category: string, locationId: string, tier?: string) => Promise<Product[]>;
311
317
  };
312
318
 
313
319
  declare function useReviews(productId: string | null | undefined): {
@@ -431,8 +437,13 @@ interface SectionTheme {
431
437
  fontDisplay?: string;
432
438
  fontBody?: string;
433
439
  }
440
+ interface ClickTrackingContext {
441
+ gatewayUrl?: string;
442
+ code?: string;
443
+ }
434
444
  interface SectionData {
435
445
  store?: {
446
+ id?: string;
436
447
  name?: string | null;
437
448
  logo_url?: string | null;
438
449
  tagline?: string | null;
@@ -444,11 +455,16 @@ interface SectionData {
444
455
  viewer_url?: string | null;
445
456
  document_name: string;
446
457
  } | null;
458
+ gatewayUrl?: string;
459
+ landing_page?: {
460
+ slug?: string;
461
+ } | null;
447
462
  }
448
- declare function SectionRenderer({ section, data, theme, }: {
463
+ declare function SectionRenderer({ section, data, theme, tracking, }: {
449
464
  section: LandingSection;
450
465
  data: SectionData;
451
466
  theme: SectionTheme;
467
+ tracking?: ClickTrackingContext;
452
468
  }): react_jsx_runtime.JSX.Element;
453
469
 
454
470
  /**
@@ -495,4 +511,4 @@ declare function FingerprintCollector(): null;
495
511
 
496
512
  declare function SessionRecorderComponent(): null;
497
513
 
498
- export { AnalyticsTracker, type AuthActions, AuthInitializer, type AuthState, type AuthStore, BehavioralTrackerComponent, type CartActions, CartInitializer, type CartState, type CartStore, FingerprintCollector, LandingPage, type LandingPageProps, PixelInitializer, QRLandingPage, type QRLandingPageProps, type SearchParams, SectionRenderer, type SectionTheme, SessionRecorderComponent, WhaleContext, type WhaleContextValue, WhaleProvider, type WhaleProviderProps, useAnalytics, useAuth, useCart, useCartItemCount, useCartTotal, useCategories, useCheckout, useCoupons, useCustomerAnalytics, useCustomerOrders, useDeals, useLocations, useLoyalty, useProduct, useProducts, useRecommendations, useReferral, useReviews, useSearch, useShipping, useWhaleClient, useWishlist };
514
+ export { AnalyticsTracker, type AuthActions, AuthInitializer, type AuthState, type AuthStore, BehavioralTrackerComponent, type CartActions, CartInitializer, type CartState, type CartStore, type ClickTrackingContext, FingerprintCollector, LandingPage, type LandingPageProps, PixelInitializer, QRLandingPage, type QRLandingPageProps, type SearchParams, SectionRenderer, type SectionTheme, SessionRecorderComponent, WhaleContext, type WhaleContextValue, WhaleProvider, type WhaleProviderProps, useAnalytics, useAuth, useCart, useCartItemCount, useCartTotal, useCategories, useCheckout, useCoupons, useCustomerAnalytics, useCustomerOrders, useDeals, useLocations, useLoyalty, useProduct, useProducts, useRecommendations, useReferral, useReviews, useSearch, useShipping, useWhaleClient, useWishlist };
@@ -1,5 +1,5 @@
1
1
  import { PixelManager } from '../chunk-PXS2DPVL.js';
2
- import { resilientSend, WhaleClient } from '../chunk-XHWAUMWS.js';
2
+ import { resilientSend, WhaleClient } from '../chunk-3Q7CPJBA.js';
3
3
  import { createContext, useContext, useRef, useCallback, useEffect, useState, useMemo } from 'react';
4
4
  import { usePathname } from 'next/navigation';
5
5
  import { createStore } from 'zustand/vanilla';
@@ -1859,12 +1859,12 @@ function useCheckout() {
1859
1859
  setLoading(false);
1860
1860
  }
1861
1861
  }, [ctx.client, session]);
1862
- const complete = useCallback(async (payment) => {
1862
+ const complete = useCallback(async (payment, opts) => {
1863
1863
  if (!session) throw new Error("No active checkout session");
1864
1864
  setLoading(true);
1865
1865
  setError(null);
1866
1866
  try {
1867
- const order = await ctx.client.completeCheckout(session.id, payment);
1867
+ const order = await ctx.client.completeCheckout(session.id, payment, opts);
1868
1868
  setSession(null);
1869
1869
  return order;
1870
1870
  } catch (err) {
@@ -2018,7 +2018,11 @@ function useLoyalty() {
2018
2018
  await refresh();
2019
2019
  return result;
2020
2020
  }, [customer?.id, ctx.client, refresh]);
2021
- return { account, rewards, transactions, loading, error, refresh, redeemReward };
2021
+ const fetchProductsByCategory = useCallback(async (category, locationId, tier) => {
2022
+ const res = await ctx.client.listLoyaltyProducts({ category, location_id: locationId, tier });
2023
+ return res.data;
2024
+ }, [ctx.client]);
2025
+ return { account, rewards, transactions, loading, error, refresh, redeemReward, fetchProductsByCategory };
2022
2026
  }
2023
2027
  function useReviews(productId) {
2024
2028
  const ctx = useContext(WhaleContext);
@@ -2409,16 +2413,27 @@ function useReferral() {
2409
2413
  referredBy: status?.referred_by ?? null
2410
2414
  };
2411
2415
  }
2416
+ function trackClick(tracking, label, url, position) {
2417
+ if (!tracking?.gatewayUrl || !tracking?.code) return;
2418
+ const body = JSON.stringify({ label, url, position });
2419
+ if (typeof navigator !== "undefined" && navigator.sendBeacon) {
2420
+ navigator.sendBeacon(
2421
+ `${tracking.gatewayUrl}/q/${encodeURIComponent(tracking.code)}/click`,
2422
+ new Blob([body], { type: "application/json" })
2423
+ );
2424
+ }
2425
+ }
2412
2426
  function SectionRenderer({
2413
2427
  section,
2414
2428
  data,
2415
- theme
2429
+ theme,
2430
+ tracking
2416
2431
  }) {
2417
2432
  const [showCOA, setShowCOA] = useState(false);
2418
2433
  const el = (() => {
2419
2434
  switch (section.type) {
2420
2435
  case "hero":
2421
- return /* @__PURE__ */ jsx(HeroSection, { section, theme });
2436
+ return /* @__PURE__ */ jsx(HeroSection, { section, theme, tracking });
2422
2437
  case "text":
2423
2438
  return /* @__PURE__ */ jsx(TextSection, { section, theme });
2424
2439
  case "image":
@@ -2428,15 +2443,17 @@ function SectionRenderer({
2428
2443
  case "gallery":
2429
2444
  return /* @__PURE__ */ jsx(GallerySection, { section, theme });
2430
2445
  case "cta":
2431
- return /* @__PURE__ */ jsx(CTASection, { section, theme });
2446
+ return /* @__PURE__ */ jsx(CTASection, { section, theme, tracking });
2432
2447
  case "stats":
2433
2448
  return /* @__PURE__ */ jsx(StatsSection, { section, theme });
2434
2449
  case "product_card":
2435
- return /* @__PURE__ */ jsx(ProductCardSection, { section, data, theme });
2450
+ return /* @__PURE__ */ jsx(ProductCardSection, { section, data, theme, tracking });
2436
2451
  case "coa_viewer":
2437
- return /* @__PURE__ */ jsx(COAViewerSection, { section, data, theme, onShowCOA: () => setShowCOA(true) });
2452
+ return /* @__PURE__ */ jsx(COAViewerSection, { section, data, theme, onShowCOA: () => setShowCOA(true), tracking });
2438
2453
  case "social_links":
2439
2454
  return /* @__PURE__ */ jsx(SocialLinksSection, { section, theme });
2455
+ case "lead_capture":
2456
+ return /* @__PURE__ */ jsx(LeadCaptureSection, { section, data, theme });
2440
2457
  case "divider":
2441
2458
  return /* @__PURE__ */ jsx(DividerSection, { theme });
2442
2459
  default:
@@ -2448,7 +2465,7 @@ function SectionRenderer({
2448
2465
  showCOA && data?.coa && /* @__PURE__ */ jsx(COAModal, { coa: data.coa, theme, onClose: () => setShowCOA(false) })
2449
2466
  ] });
2450
2467
  }
2451
- function HeroSection({ section, theme }) {
2468
+ function HeroSection({ section, theme, tracking }) {
2452
2469
  const { title, subtitle, background_image, cta_text, cta_url } = section.content;
2453
2470
  return /* @__PURE__ */ jsxs(
2454
2471
  "div",
@@ -2490,6 +2507,7 @@ function HeroSection({ section, theme }) {
2490
2507
  "a",
2491
2508
  {
2492
2509
  href: cta_url,
2510
+ onClick: () => trackClick(tracking, cta_text, cta_url),
2493
2511
  style: {
2494
2512
  display: "inline-block",
2495
2513
  padding: "0.875rem 2rem",
@@ -2575,7 +2593,7 @@ function GallerySection({ section, theme }) {
2575
2593
  }
2576
2594
  ) }, i)) }) });
2577
2595
  }
2578
- function CTASection({ section, theme }) {
2596
+ function CTASection({ section, theme, tracking }) {
2579
2597
  const { buttons } = section.content;
2580
2598
  if (!buttons || buttons.length === 0) return null;
2581
2599
  return /* @__PURE__ */ 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,6 +2602,7 @@ function CTASection({ section, theme }) {
2584
2602
  "a",
2585
2603
  {
2586
2604
  href: btn.url,
2605
+ onClick: () => trackClick(tracking, btn.text, btn.url, i),
2587
2606
  style: {
2588
2607
  display: "block",
2589
2608
  width: "100%",
@@ -2655,7 +2674,7 @@ function StatsSection({ section, theme }) {
2655
2674
  }, children: stat.label })
2656
2675
  ] }, i)) }) });
2657
2676
  }
2658
- function ProductCardSection({ section, data, theme }) {
2677
+ function ProductCardSection({ section, data, theme, tracking }) {
2659
2678
  const product = data?.product;
2660
2679
  const c = section.content;
2661
2680
  const name = c.name || product?.name || "";
@@ -2671,6 +2690,7 @@ function ProductCardSection({ section, data, theme }) {
2671
2690
  "a",
2672
2691
  {
2673
2692
  href: url,
2693
+ onClick: () => trackClick(tracking, "View Product", url),
2674
2694
  style: {
2675
2695
  display: "block",
2676
2696
  width: "100%",
@@ -2695,7 +2715,8 @@ function COAViewerSection({
2695
2715
  section,
2696
2716
  data,
2697
2717
  theme,
2698
- onShowCOA
2718
+ onShowCOA,
2719
+ tracking
2699
2720
  }) {
2700
2721
  const coa = data?.coa;
2701
2722
  const c = section.content;
@@ -2716,10 +2737,200 @@ function COAViewerSection({
2716
2737
  display: "block",
2717
2738
  boxSizing: "border-box"
2718
2739
  };
2740
+ const buttonLabel = c.button_text || "View Lab Results";
2719
2741
  if (coa.viewer_url) {
2720
- return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx("a", { href: coa.viewer_url, target: "_blank", rel: "noopener noreferrer", style: buttonStyle, children: c.button_text || "View Lab Results" }) });
2742
+ return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx(
2743
+ "a",
2744
+ {
2745
+ href: coa.viewer_url,
2746
+ target: "_blank",
2747
+ rel: "noopener noreferrer",
2748
+ onClick: () => trackClick(tracking, buttonLabel, coa.viewer_url),
2749
+ style: buttonStyle,
2750
+ children: buttonLabel
2751
+ }
2752
+ ) });
2721
2753
  }
2722
- return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx("button", { onClick: onShowCOA, style: buttonStyle, children: c.button_text || "View Lab Results" }) });
2754
+ return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx("button", { onClick: () => {
2755
+ trackClick(tracking, buttonLabel, coa.url);
2756
+ onShowCOA();
2757
+ }, style: buttonStyle, children: buttonLabel }) });
2758
+ }
2759
+ function LeadCaptureSection({ section, data, theme }) {
2760
+ const c = section.content;
2761
+ const [firstName, setFirstName] = useState("");
2762
+ const [email, setEmail] = useState("");
2763
+ const [status, setStatus] = useState("idle");
2764
+ const [errorMsg, setErrorMsg] = useState("");
2765
+ const gatewayUrl = c.gateway_url || data.gatewayUrl || "https://whale-gateway.fly.dev";
2766
+ const storeId = c.store_id || data.store?.id;
2767
+ const slug = c.landing_page_slug || data.landing_page?.slug;
2768
+ async function handleSubmit(e) {
2769
+ e.preventDefault();
2770
+ if (!email || !storeId) return;
2771
+ setStatus("loading");
2772
+ setErrorMsg("");
2773
+ try {
2774
+ const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
2775
+ method: "POST",
2776
+ headers: { "Content-Type": "application/json" },
2777
+ body: JSON.stringify({
2778
+ email,
2779
+ first_name: firstName || void 0,
2780
+ source: c.source || "landing_page",
2781
+ landing_page_slug: slug || void 0,
2782
+ tags: c.tags || void 0
2783
+ })
2784
+ });
2785
+ if (!res.ok) {
2786
+ const body = await res.json().catch(() => ({}));
2787
+ throw new Error(body?.error?.message || "Something went wrong. Please try again.");
2788
+ }
2789
+ setStatus("success");
2790
+ } catch (err) {
2791
+ setErrorMsg(err instanceof Error ? err.message : "Something went wrong. Please try again.");
2792
+ setStatus("error");
2793
+ }
2794
+ }
2795
+ const heading = c.heading || "get 10% off your first visit.";
2796
+ const subtitle = c.subtitle || "drop your email and we will send you the code.";
2797
+ const buttonText = c.button_text || "Claim My Discount";
2798
+ const successHeading = c.success_heading || "You\u2019re in!";
2799
+ const successMessage = c.success_message || "Check your inbox for the discount code.";
2800
+ const inputStyle = {
2801
+ flex: 1,
2802
+ minWidth: 0,
2803
+ padding: "0.875rem 1rem",
2804
+ background: theme.surface,
2805
+ border: `1px solid ${theme.fg}15`,
2806
+ color: theme.fg,
2807
+ fontSize: "0.95rem",
2808
+ fontWeight: 300,
2809
+ outline: "none",
2810
+ boxSizing: "border-box",
2811
+ fontFamily: "inherit",
2812
+ transition: "border-color 0.2s"
2813
+ };
2814
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "3.5rem 1.5rem", maxWidth: 560, margin: "0 auto" }, children: [
2815
+ /* @__PURE__ */ jsx("style", { children: `@keyframes lc-spin { to { transform: rotate(360deg) } }` }),
2816
+ /* @__PURE__ */ jsx("div", { style: {
2817
+ background: theme.surface,
2818
+ border: `1px solid ${theme.fg}12`,
2819
+ padding: "clamp(2rem, 6vw, 3rem)"
2820
+ }, children: status === "success" ? /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
2821
+ /* @__PURE__ */ jsx("h2", { style: {
2822
+ fontSize: "clamp(1.5rem, 5vw, 2rem)",
2823
+ fontWeight: 300,
2824
+ fontFamily: theme.fontDisplay || "inherit",
2825
+ margin: "0 0 0.75rem",
2826
+ lineHeight: 1.2,
2827
+ letterSpacing: "-0.02em",
2828
+ color: theme.fg
2829
+ }, children: successHeading }),
2830
+ /* @__PURE__ */ jsx("p", { style: {
2831
+ fontSize: "0.9rem",
2832
+ color: `${theme.fg}99`,
2833
+ margin: "0 0 1.5rem",
2834
+ lineHeight: 1.6,
2835
+ fontWeight: 300
2836
+ }, children: successMessage }),
2837
+ c.coupon_code && /* @__PURE__ */ jsx("div", { style: {
2838
+ display: "inline-block",
2839
+ padding: "0.75rem 2rem",
2840
+ background: `${theme.fg}08`,
2841
+ border: `1px dashed ${theme.fg}30`,
2842
+ fontSize: "clamp(1.25rem, 4vw, 1.75rem)",
2843
+ fontWeight: 500,
2844
+ fontFamily: "monospace",
2845
+ letterSpacing: "0.12em",
2846
+ color: theme.accent
2847
+ }, children: c.coupon_code })
2848
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2849
+ /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", marginBottom: "clamp(1.5rem, 4vw, 2rem)" }, children: [
2850
+ /* @__PURE__ */ jsx("h2", { style: {
2851
+ fontSize: "clamp(1.5rem, 5vw, 2.25rem)",
2852
+ fontWeight: 300,
2853
+ fontFamily: theme.fontDisplay || "inherit",
2854
+ margin: "0 0 0.5rem",
2855
+ lineHeight: 1.15,
2856
+ letterSpacing: "-0.02em",
2857
+ color: theme.fg
2858
+ }, children: heading }),
2859
+ /* @__PURE__ */ jsx("p", { style: {
2860
+ fontSize: "0.85rem",
2861
+ color: theme.accent,
2862
+ margin: 0,
2863
+ lineHeight: 1.6,
2864
+ textTransform: "uppercase",
2865
+ letterSpacing: "0.15em"
2866
+ }, children: subtitle })
2867
+ ] }),
2868
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
2869
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.75rem", flexWrap: "wrap" }, children: [
2870
+ /* @__PURE__ */ jsx(
2871
+ "input",
2872
+ {
2873
+ type: "text",
2874
+ placeholder: "First name",
2875
+ value: firstName,
2876
+ onChange: (e) => setFirstName(e.target.value),
2877
+ style: inputStyle
2878
+ }
2879
+ ),
2880
+ /* @__PURE__ */ jsx(
2881
+ "input",
2882
+ {
2883
+ type: "email",
2884
+ placeholder: "Email address",
2885
+ value: email,
2886
+ onChange: (e) => setEmail(e.target.value),
2887
+ required: true,
2888
+ style: inputStyle
2889
+ }
2890
+ )
2891
+ ] }),
2892
+ status === "error" && errorMsg && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: "#e55", margin: 0, fontWeight: 400 }, children: errorMsg }),
2893
+ /* @__PURE__ */ jsxs(
2894
+ "button",
2895
+ {
2896
+ type: "submit",
2897
+ disabled: status === "loading",
2898
+ style: {
2899
+ width: "100%",
2900
+ padding: "0.875rem",
2901
+ background: theme.fg,
2902
+ color: theme.bg,
2903
+ border: "none",
2904
+ fontSize: "0.85rem",
2905
+ fontWeight: 500,
2906
+ cursor: status === "loading" ? "wait" : "pointer",
2907
+ letterSpacing: "0.08em",
2908
+ textTransform: "uppercase",
2909
+ fontFamily: "inherit",
2910
+ display: "flex",
2911
+ alignItems: "center",
2912
+ justifyContent: "center",
2913
+ gap: "0.5rem",
2914
+ opacity: status === "loading" ? 0.7 : 1,
2915
+ transition: "opacity 0.2s"
2916
+ },
2917
+ children: [
2918
+ status === "loading" && /* @__PURE__ */ jsx("span", { style: {
2919
+ display: "inline-block",
2920
+ width: 16,
2921
+ height: 16,
2922
+ border: `2px solid ${theme.bg}40`,
2923
+ borderTopColor: theme.bg,
2924
+ borderRadius: "50%",
2925
+ animation: "lc-spin 0.8s linear infinite"
2926
+ } }),
2927
+ buttonText
2928
+ ]
2929
+ }
2930
+ )
2931
+ ] })
2932
+ ] }) })
2933
+ ] });
2723
2934
  }
2724
2935
  function SocialLinksSection({ section, theme }) {
2725
2936
  const { links } = section.content;
@@ -2842,15 +3053,16 @@ function QRLandingPage({
2842
3053
  const logoUrl = data.qr_code.logo_url || data.store?.logo_url;
2843
3054
  const storeName = data.store?.name;
2844
3055
  const sorted = [...sections].sort((a, b) => a.order - b.order);
3056
+ const tracking = { gatewayUrl, code };
2845
3057
  return /* @__PURE__ */ jsxs("div", { style: { minHeight: "100dvh", background: theme.bg, color: theme.fg, fontFamily }, children: [
2846
3058
  lp?.custom_css && /* @__PURE__ */ jsx("style", { children: lp.custom_css }),
2847
3059
  logoUrl && /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx("img", { src: logoUrl, alt: storeName || "Store", style: { height: 40, objectFit: "contain" } }) }),
2848
3060
  sorted.map((section) => {
2849
- const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
3061
+ const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme, tracking }, section.id);
2850
3062
  if (renderSection) {
2851
3063
  return /* @__PURE__ */ jsx("div", { children: renderSection(section, defaultRenderer) }, section.id);
2852
3064
  }
2853
- return /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
3065
+ return /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme, tracking }, section.id);
2854
3066
  }),
2855
3067
  storeName && /* @__PURE__ */ jsx("div", { style: { padding: "2rem 1.5rem", borderTop: `1px solid ${theme.surface}`, textAlign: "center" }, children: /* @__PURE__ */ jsxs("p", { style: { fontSize: "0.75rem", color: theme.muted, margin: 0 }, children: [
2856
3068
  storeName,
@@ -3100,10 +3312,11 @@ function LandingPage({
3100
3312
  if (state === "expired") return /* @__PURE__ */ jsx(DefaultExpired2, {});
3101
3313
  if (state === "error") return /* @__PURE__ */ jsx(DefaultError2, { message: errorMsg });
3102
3314
  if (!data) return null;
3103
- return /* @__PURE__ */ jsx(PageLayout, { data, renderSection });
3315
+ return /* @__PURE__ */ jsx(PageLayout, { data, gatewayUrl, renderSection });
3104
3316
  }
3105
3317
  function PageLayout({
3106
3318
  data,
3319
+ gatewayUrl,
3107
3320
  renderSection
3108
3321
  }) {
3109
3322
  const { landing_page: lp, store } = data;
@@ -3119,15 +3332,16 @@ function PageLayout({
3119
3332
  const fontFamily = lp.font_family || theme.fontDisplay || "system-ui, -apple-system, sans-serif";
3120
3333
  const logoUrl = store?.logo_url;
3121
3334
  const sorted = [...lp.sections].sort((a, b) => a.order - b.order);
3335
+ const sectionData = { ...data, gatewayUrl, landing_page: { slug: lp.slug } };
3122
3336
  return /* @__PURE__ */ jsxs("div", { style: { minHeight: "100dvh", background: theme.bg, color: theme.fg, fontFamily }, children: [
3123
3337
  lp.custom_css && /* @__PURE__ */ jsx("style", { children: lp.custom_css }),
3124
3338
  logoUrl && /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ jsx("img", { src: logoUrl, alt: store?.name || "Store", style: { height: 40, objectFit: "contain" } }) }),
3125
3339
  sorted.map((section) => {
3126
- const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
3340
+ const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme }, section.id);
3127
3341
  if (renderSection) {
3128
3342
  return /* @__PURE__ */ jsx("div", { children: renderSection(section, defaultRenderer) }, section.id);
3129
3343
  }
3130
- return /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
3344
+ return /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme }, section.id);
3131
3345
  }),
3132
3346
  store?.name && /* @__PURE__ */ jsx("div", { style: { padding: "2rem 1.5rem", borderTop: `1px solid ${theme.surface}`, textAlign: "center" }, children: /* @__PURE__ */ jsxs("p", { style: { fontSize: "0.75rem", color: theme.muted, margin: 0 }, children: [
3133
3347
  "Powered by ",