@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.
- package/dist/{chunk-XHWAUMWS.js → chunk-3Q7CPJBA.js} +18 -9
- package/dist/chunk-3Q7CPJBA.js.map +1 -0
- package/dist/{chunk-CQCCXDUS.cjs → chunk-VAA2KKCH.cjs} +18 -9
- package/dist/chunk-VAA2KKCH.cjs.map +1 -0
- package/dist/{client-D1XVKpFt.d.cts → client-BSO263Uv.d.cts} +15 -2
- package/dist/{client-D1XVKpFt.d.ts → client-BSO263Uv.d.ts} +15 -2
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/next/index.cjs +4 -4
- package/dist/next/index.d.cts +1 -1
- package/dist/next/index.d.ts +1 -1
- package/dist/next/index.js +1 -1
- package/dist/{pixel-manager-C6PAp7vQ.d.ts → pixel-manager-BcL95odX.d.ts} +1 -1
- package/dist/{pixel-manager-DZwpn_x2.d.cts → pixel-manager-DJ9m2FaQ.d.cts} +1 -1
- package/dist/react/index.cjs +238 -24
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +21 -5
- package/dist/react/index.d.ts +21 -5
- package/dist/react/index.js +234 -20
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-CQCCXDUS.cjs.map +0 -1
- package/dist/chunk-XHWAUMWS.js.map +0 -1
package/dist/react/index.d.cts
CHANGED
|
@@ -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-
|
|
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-
|
|
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
|
|
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 };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -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-
|
|
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-
|
|
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
|
|
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 };
|
package/dist/react/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PixelManager } from '../chunk-PXS2DPVL.js';
|
|
2
|
-
import { resilientSend, WhaleClient } from '../chunk-
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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 ",
|