@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.
- 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 +285 -50
- 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 +281 -46
- 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,35 +2593,57 @@ function GallerySection({ section, theme }) {
|
|
|
2575
2593
|
}
|
|
2576
2594
|
) }, i)) }) });
|
|
2577
2595
|
}
|
|
2578
|
-
function CTASection({ section, theme }) {
|
|
2579
|
-
const { buttons } = section.content;
|
|
2596
|
+
function CTASection({ section, theme, tracking }) {
|
|
2597
|
+
const { title, subtitle, buttons } = section.content;
|
|
2580
2598
|
if (!buttons || buttons.length === 0) return null;
|
|
2581
|
-
return /* @__PURE__ */
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2599
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "2rem 1.5rem", maxWidth: 480, margin: "0 auto", display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
2600
|
+
title && /* @__PURE__ */ jsx("h2", { style: {
|
|
2601
|
+
fontSize: "clamp(1.25rem, 4vw, 1.5rem)",
|
|
2602
|
+
fontWeight: 300,
|
|
2603
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
2604
|
+
margin: "0 0 0.25rem",
|
|
2605
|
+
lineHeight: 1.2,
|
|
2606
|
+
letterSpacing: "-0.02em",
|
|
2607
|
+
color: theme.fg,
|
|
2608
|
+
textAlign: "center"
|
|
2609
|
+
}, children: title }),
|
|
2610
|
+
subtitle && /* @__PURE__ */ jsx("p", { style: {
|
|
2611
|
+
fontSize: "0.8rem",
|
|
2612
|
+
color: theme.accent,
|
|
2613
|
+
margin: "0 0 0.75rem",
|
|
2614
|
+
lineHeight: 1.6,
|
|
2615
|
+
textTransform: "uppercase",
|
|
2616
|
+
letterSpacing: "0.15em",
|
|
2617
|
+
textAlign: "center"
|
|
2618
|
+
}, children: subtitle }),
|
|
2619
|
+
buttons.map((btn, i) => {
|
|
2620
|
+
const isPrimary = btn.style !== "outline";
|
|
2621
|
+
return /* @__PURE__ */ jsx(
|
|
2622
|
+
"a",
|
|
2623
|
+
{
|
|
2624
|
+
href: btn.url,
|
|
2625
|
+
onClick: () => trackClick(tracking, btn.text, btn.url, i),
|
|
2626
|
+
style: {
|
|
2627
|
+
display: "block",
|
|
2628
|
+
width: "100%",
|
|
2629
|
+
padding: "0.875rem",
|
|
2630
|
+
background: isPrimary ? theme.fg : "transparent",
|
|
2631
|
+
color: isPrimary ? theme.bg : theme.fg,
|
|
2632
|
+
border: isPrimary ? "none" : `1px solid ${theme.fg}20`,
|
|
2633
|
+
fontSize: "0.85rem",
|
|
2634
|
+
fontWeight: 500,
|
|
2635
|
+
textAlign: "center",
|
|
2636
|
+
textDecoration: "none",
|
|
2637
|
+
boxSizing: "border-box",
|
|
2638
|
+
letterSpacing: "0.08em",
|
|
2639
|
+
textTransform: "uppercase"
|
|
2640
|
+
},
|
|
2641
|
+
children: btn.text
|
|
2601
2642
|
},
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
}) });
|
|
2643
|
+
i
|
|
2644
|
+
);
|
|
2645
|
+
})
|
|
2646
|
+
] });
|
|
2607
2647
|
}
|
|
2608
2648
|
function StatsSection({ section, theme }) {
|
|
2609
2649
|
const { stats } = section.content;
|
|
@@ -2655,7 +2695,7 @@ function StatsSection({ section, theme }) {
|
|
|
2655
2695
|
}, children: stat.label })
|
|
2656
2696
|
] }, i)) }) });
|
|
2657
2697
|
}
|
|
2658
|
-
function ProductCardSection({ section, data, theme }) {
|
|
2698
|
+
function ProductCardSection({ section, data, theme, tracking }) {
|
|
2659
2699
|
const product = data?.product;
|
|
2660
2700
|
const c = section.content;
|
|
2661
2701
|
const name = c.name || product?.name || "";
|
|
@@ -2671,6 +2711,7 @@ function ProductCardSection({ section, data, theme }) {
|
|
|
2671
2711
|
"a",
|
|
2672
2712
|
{
|
|
2673
2713
|
href: url,
|
|
2714
|
+
onClick: () => trackClick(tracking, "View Product", url),
|
|
2674
2715
|
style: {
|
|
2675
2716
|
display: "block",
|
|
2676
2717
|
width: "100%",
|
|
@@ -2695,7 +2736,8 @@ function COAViewerSection({
|
|
|
2695
2736
|
section,
|
|
2696
2737
|
data,
|
|
2697
2738
|
theme,
|
|
2698
|
-
onShowCOA
|
|
2739
|
+
onShowCOA,
|
|
2740
|
+
tracking
|
|
2699
2741
|
}) {
|
|
2700
2742
|
const coa = data?.coa;
|
|
2701
2743
|
const c = section.content;
|
|
@@ -2716,10 +2758,200 @@ function COAViewerSection({
|
|
|
2716
2758
|
display: "block",
|
|
2717
2759
|
boxSizing: "border-box"
|
|
2718
2760
|
};
|
|
2761
|
+
const buttonLabel = c.button_text || "View Lab Results";
|
|
2719
2762
|
if (coa.viewer_url) {
|
|
2720
|
-
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx(
|
|
2763
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx(
|
|
2764
|
+
"a",
|
|
2765
|
+
{
|
|
2766
|
+
href: coa.viewer_url,
|
|
2767
|
+
target: "_blank",
|
|
2768
|
+
rel: "noopener noreferrer",
|
|
2769
|
+
onClick: () => trackClick(tracking, buttonLabel, coa.viewer_url),
|
|
2770
|
+
style: buttonStyle,
|
|
2771
|
+
children: buttonLabel
|
|
2772
|
+
}
|
|
2773
|
+
) });
|
|
2721
2774
|
}
|
|
2722
|
-
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx("button", { onClick:
|
|
2775
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "1.5rem", maxWidth: 480, margin: "0 auto" }, children: /* @__PURE__ */ jsx("button", { onClick: () => {
|
|
2776
|
+
trackClick(tracking, buttonLabel, coa.url);
|
|
2777
|
+
onShowCOA();
|
|
2778
|
+
}, style: buttonStyle, children: buttonLabel }) });
|
|
2779
|
+
}
|
|
2780
|
+
function LeadCaptureSection({ section, data, theme }) {
|
|
2781
|
+
const c = section.content;
|
|
2782
|
+
const [firstName, setFirstName] = useState("");
|
|
2783
|
+
const [email, setEmail] = useState("");
|
|
2784
|
+
const [status, setStatus] = useState("idle");
|
|
2785
|
+
const [errorMsg, setErrorMsg] = useState("");
|
|
2786
|
+
const gatewayUrl = c.gateway_url || data.gatewayUrl || "https://whale-gateway.fly.dev";
|
|
2787
|
+
const storeId = c.store_id || data.store?.id;
|
|
2788
|
+
const slug = c.landing_page_slug || data.landing_page?.slug;
|
|
2789
|
+
async function handleSubmit(e) {
|
|
2790
|
+
e.preventDefault();
|
|
2791
|
+
if (!email || !storeId) return;
|
|
2792
|
+
setStatus("loading");
|
|
2793
|
+
setErrorMsg("");
|
|
2794
|
+
try {
|
|
2795
|
+
const res = await fetch(`${gatewayUrl}/v1/stores/${storeId}/storefront/leads`, {
|
|
2796
|
+
method: "POST",
|
|
2797
|
+
headers: { "Content-Type": "application/json" },
|
|
2798
|
+
body: JSON.stringify({
|
|
2799
|
+
email,
|
|
2800
|
+
first_name: firstName || void 0,
|
|
2801
|
+
source: c.source || "landing_page",
|
|
2802
|
+
landing_page_slug: slug || void 0,
|
|
2803
|
+
tags: c.tags || void 0
|
|
2804
|
+
})
|
|
2805
|
+
});
|
|
2806
|
+
if (!res.ok) {
|
|
2807
|
+
const body = await res.json().catch(() => ({}));
|
|
2808
|
+
throw new Error(body?.error?.message || "Something went wrong. Please try again.");
|
|
2809
|
+
}
|
|
2810
|
+
setStatus("success");
|
|
2811
|
+
} catch (err) {
|
|
2812
|
+
setErrorMsg(err instanceof Error ? err.message : "Something went wrong. Please try again.");
|
|
2813
|
+
setStatus("error");
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
const heading = c.heading || "get 10% off your first visit.";
|
|
2817
|
+
const subtitle = c.subtitle || "drop your email and we will send you the code.";
|
|
2818
|
+
const buttonText = c.button_text || "Claim My Discount";
|
|
2819
|
+
const successHeading = c.success_heading || "You\u2019re in!";
|
|
2820
|
+
const successMessage = c.success_message || "Check your inbox for the discount code.";
|
|
2821
|
+
const inputStyle = {
|
|
2822
|
+
flex: 1,
|
|
2823
|
+
minWidth: 0,
|
|
2824
|
+
padding: "0.875rem 1rem",
|
|
2825
|
+
background: theme.surface,
|
|
2826
|
+
border: `1px solid ${theme.fg}15`,
|
|
2827
|
+
color: theme.fg,
|
|
2828
|
+
fontSize: "0.95rem",
|
|
2829
|
+
fontWeight: 300,
|
|
2830
|
+
outline: "none",
|
|
2831
|
+
boxSizing: "border-box",
|
|
2832
|
+
fontFamily: "inherit",
|
|
2833
|
+
transition: "border-color 0.2s"
|
|
2834
|
+
};
|
|
2835
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "3.5rem 1.5rem", maxWidth: 560, margin: "0 auto" }, children: [
|
|
2836
|
+
/* @__PURE__ */ jsx("style", { children: `@keyframes lc-spin { to { transform: rotate(360deg) } }` }),
|
|
2837
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
2838
|
+
background: theme.surface,
|
|
2839
|
+
border: `1px solid ${theme.fg}12`,
|
|
2840
|
+
padding: "clamp(2rem, 6vw, 3rem)"
|
|
2841
|
+
}, children: status === "success" ? /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
|
|
2842
|
+
/* @__PURE__ */ jsx("h2", { style: {
|
|
2843
|
+
fontSize: "clamp(1.5rem, 5vw, 2rem)",
|
|
2844
|
+
fontWeight: 300,
|
|
2845
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
2846
|
+
margin: "0 0 0.75rem",
|
|
2847
|
+
lineHeight: 1.2,
|
|
2848
|
+
letterSpacing: "-0.02em",
|
|
2849
|
+
color: theme.fg
|
|
2850
|
+
}, children: successHeading }),
|
|
2851
|
+
/* @__PURE__ */ jsx("p", { style: {
|
|
2852
|
+
fontSize: "0.9rem",
|
|
2853
|
+
color: `${theme.fg}99`,
|
|
2854
|
+
margin: "0 0 1.5rem",
|
|
2855
|
+
lineHeight: 1.6,
|
|
2856
|
+
fontWeight: 300
|
|
2857
|
+
}, children: successMessage }),
|
|
2858
|
+
c.coupon_code && /* @__PURE__ */ jsx("div", { style: {
|
|
2859
|
+
display: "inline-block",
|
|
2860
|
+
padding: "0.75rem 2rem",
|
|
2861
|
+
background: `${theme.fg}08`,
|
|
2862
|
+
border: `1px dashed ${theme.fg}30`,
|
|
2863
|
+
fontSize: "clamp(1.25rem, 4vw, 1.75rem)",
|
|
2864
|
+
fontWeight: 500,
|
|
2865
|
+
fontFamily: "monospace",
|
|
2866
|
+
letterSpacing: "0.12em",
|
|
2867
|
+
color: theme.accent
|
|
2868
|
+
}, children: c.coupon_code })
|
|
2869
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2870
|
+
/* @__PURE__ */ jsxs("div", { style: { textAlign: "center", marginBottom: "clamp(1.5rem, 4vw, 2rem)" }, children: [
|
|
2871
|
+
/* @__PURE__ */ jsx("h2", { style: {
|
|
2872
|
+
fontSize: "clamp(1.5rem, 5vw, 2.25rem)",
|
|
2873
|
+
fontWeight: 300,
|
|
2874
|
+
fontFamily: theme.fontDisplay || "inherit",
|
|
2875
|
+
margin: "0 0 0.5rem",
|
|
2876
|
+
lineHeight: 1.15,
|
|
2877
|
+
letterSpacing: "-0.02em",
|
|
2878
|
+
color: theme.fg
|
|
2879
|
+
}, children: heading }),
|
|
2880
|
+
/* @__PURE__ */ jsx("p", { style: {
|
|
2881
|
+
fontSize: "0.85rem",
|
|
2882
|
+
color: theme.accent,
|
|
2883
|
+
margin: 0,
|
|
2884
|
+
lineHeight: 1.6,
|
|
2885
|
+
textTransform: "uppercase",
|
|
2886
|
+
letterSpacing: "0.15em"
|
|
2887
|
+
}, children: subtitle })
|
|
2888
|
+
] }),
|
|
2889
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: { display: "flex", flexDirection: "column", gap: "0.75rem" }, children: [
|
|
2890
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.75rem", flexWrap: "wrap" }, children: [
|
|
2891
|
+
/* @__PURE__ */ jsx(
|
|
2892
|
+
"input",
|
|
2893
|
+
{
|
|
2894
|
+
type: "text",
|
|
2895
|
+
placeholder: "First name",
|
|
2896
|
+
value: firstName,
|
|
2897
|
+
onChange: (e) => setFirstName(e.target.value),
|
|
2898
|
+
style: inputStyle
|
|
2899
|
+
}
|
|
2900
|
+
),
|
|
2901
|
+
/* @__PURE__ */ jsx(
|
|
2902
|
+
"input",
|
|
2903
|
+
{
|
|
2904
|
+
type: "email",
|
|
2905
|
+
placeholder: "Email address",
|
|
2906
|
+
value: email,
|
|
2907
|
+
onChange: (e) => setEmail(e.target.value),
|
|
2908
|
+
required: true,
|
|
2909
|
+
style: inputStyle
|
|
2910
|
+
}
|
|
2911
|
+
)
|
|
2912
|
+
] }),
|
|
2913
|
+
status === "error" && errorMsg && /* @__PURE__ */ jsx("p", { style: { fontSize: "0.8rem", color: "#e55", margin: 0, fontWeight: 400 }, children: errorMsg }),
|
|
2914
|
+
/* @__PURE__ */ jsxs(
|
|
2915
|
+
"button",
|
|
2916
|
+
{
|
|
2917
|
+
type: "submit",
|
|
2918
|
+
disabled: status === "loading",
|
|
2919
|
+
style: {
|
|
2920
|
+
width: "100%",
|
|
2921
|
+
padding: "0.875rem",
|
|
2922
|
+
background: theme.fg,
|
|
2923
|
+
color: theme.bg,
|
|
2924
|
+
border: "none",
|
|
2925
|
+
fontSize: "0.85rem",
|
|
2926
|
+
fontWeight: 500,
|
|
2927
|
+
cursor: status === "loading" ? "wait" : "pointer",
|
|
2928
|
+
letterSpacing: "0.08em",
|
|
2929
|
+
textTransform: "uppercase",
|
|
2930
|
+
fontFamily: "inherit",
|
|
2931
|
+
display: "flex",
|
|
2932
|
+
alignItems: "center",
|
|
2933
|
+
justifyContent: "center",
|
|
2934
|
+
gap: "0.5rem",
|
|
2935
|
+
opacity: status === "loading" ? 0.7 : 1,
|
|
2936
|
+
transition: "opacity 0.2s"
|
|
2937
|
+
},
|
|
2938
|
+
children: [
|
|
2939
|
+
status === "loading" && /* @__PURE__ */ jsx("span", { style: {
|
|
2940
|
+
display: "inline-block",
|
|
2941
|
+
width: 16,
|
|
2942
|
+
height: 16,
|
|
2943
|
+
border: `2px solid ${theme.bg}40`,
|
|
2944
|
+
borderTopColor: theme.bg,
|
|
2945
|
+
borderRadius: "50%",
|
|
2946
|
+
animation: "lc-spin 0.8s linear infinite"
|
|
2947
|
+
} }),
|
|
2948
|
+
buttonText
|
|
2949
|
+
]
|
|
2950
|
+
}
|
|
2951
|
+
)
|
|
2952
|
+
] })
|
|
2953
|
+
] }) })
|
|
2954
|
+
] });
|
|
2723
2955
|
}
|
|
2724
2956
|
function SocialLinksSection({ section, theme }) {
|
|
2725
2957
|
const { links } = section.content;
|
|
@@ -2842,15 +3074,16 @@ function QRLandingPage({
|
|
|
2842
3074
|
const logoUrl = data.qr_code.logo_url || data.store?.logo_url;
|
|
2843
3075
|
const storeName = data.store?.name;
|
|
2844
3076
|
const sorted = [...sections].sort((a, b) => a.order - b.order);
|
|
3077
|
+
const tracking = { gatewayUrl, code };
|
|
2845
3078
|
return /* @__PURE__ */ jsxs("div", { style: { minHeight: "100dvh", background: theme.bg, color: theme.fg, fontFamily }, children: [
|
|
2846
3079
|
lp?.custom_css && /* @__PURE__ */ jsx("style", { children: lp.custom_css }),
|
|
2847
3080
|
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
3081
|
sorted.map((section) => {
|
|
2849
|
-
const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
|
|
3082
|
+
const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme, tracking }, section.id);
|
|
2850
3083
|
if (renderSection) {
|
|
2851
3084
|
return /* @__PURE__ */ jsx("div", { children: renderSection(section, defaultRenderer) }, section.id);
|
|
2852
3085
|
}
|
|
2853
|
-
return /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
|
|
3086
|
+
return /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme, tracking }, section.id);
|
|
2854
3087
|
}),
|
|
2855
3088
|
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
3089
|
storeName,
|
|
@@ -3100,10 +3333,11 @@ function LandingPage({
|
|
|
3100
3333
|
if (state === "expired") return /* @__PURE__ */ jsx(DefaultExpired2, {});
|
|
3101
3334
|
if (state === "error") return /* @__PURE__ */ jsx(DefaultError2, { message: errorMsg });
|
|
3102
3335
|
if (!data) return null;
|
|
3103
|
-
return /* @__PURE__ */ jsx(PageLayout, { data, renderSection });
|
|
3336
|
+
return /* @__PURE__ */ jsx(PageLayout, { data, gatewayUrl, renderSection });
|
|
3104
3337
|
}
|
|
3105
3338
|
function PageLayout({
|
|
3106
3339
|
data,
|
|
3340
|
+
gatewayUrl,
|
|
3107
3341
|
renderSection
|
|
3108
3342
|
}) {
|
|
3109
3343
|
const { landing_page: lp, store } = data;
|
|
@@ -3119,15 +3353,16 @@ function PageLayout({
|
|
|
3119
3353
|
const fontFamily = lp.font_family || theme.fontDisplay || "system-ui, -apple-system, sans-serif";
|
|
3120
3354
|
const logoUrl = store?.logo_url;
|
|
3121
3355
|
const sorted = [...lp.sections].sort((a, b) => a.order - b.order);
|
|
3356
|
+
const sectionData = { ...data, gatewayUrl, landing_page: { slug: lp.slug } };
|
|
3122
3357
|
return /* @__PURE__ */ jsxs("div", { style: { minHeight: "100dvh", background: theme.bg, color: theme.fg, fontFamily }, children: [
|
|
3123
3358
|
lp.custom_css && /* @__PURE__ */ jsx("style", { children: lp.custom_css }),
|
|
3124
3359
|
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
3360
|
sorted.map((section) => {
|
|
3126
|
-
const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
|
|
3361
|
+
const defaultRenderer = () => /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme }, section.id);
|
|
3127
3362
|
if (renderSection) {
|
|
3128
3363
|
return /* @__PURE__ */ jsx("div", { children: renderSection(section, defaultRenderer) }, section.id);
|
|
3129
3364
|
}
|
|
3130
|
-
return /* @__PURE__ */ jsx(SectionRenderer, { section, data, theme }, section.id);
|
|
3365
|
+
return /* @__PURE__ */ jsx(SectionRenderer, { section, data: sectionData, theme }, section.id);
|
|
3131
3366
|
}),
|
|
3132
3367
|
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
3368
|
"Powered by ",
|