@cimplify/sdk 0.8.6 → 0.8.8

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/react.js CHANGED
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var React2 = require('react');
3
+ var React3 = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
5
 
6
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
7
 
8
- var React2__default = /*#__PURE__*/_interopDefault(React2);
8
+ var React3__default = /*#__PURE__*/_interopDefault(React3);
9
9
 
10
10
  // src/react/index.tsx
11
11
 
@@ -201,7 +201,7 @@ function deriveAdsApiUrl() {
201
201
  }
202
202
  return "https://api.cimplify.io";
203
203
  }
204
- var AdContext = React2.createContext({
204
+ var AdContext = React3.createContext({
205
205
  siteId: null,
206
206
  config: null,
207
207
  isLoading: true,
@@ -209,7 +209,7 @@ var AdContext = React2.createContext({
209
209
  apiBase: "https://api.cimplify.io"
210
210
  });
211
211
  function useAds() {
212
- return React2.useContext(AdContext);
212
+ return React3.useContext(AdContext);
213
213
  }
214
214
  function AdProvider({
215
215
  siteId,
@@ -218,10 +218,10 @@ function AdProvider({
218
218
  children
219
219
  }) {
220
220
  const resolvedApiBase = apiBase || deriveAdsApiUrl();
221
- const [config, setConfig] = React2.useState(null);
222
- const [isLoading, setIsLoading] = React2.useState(true);
223
- const [identity, setIdentity] = React2.useState(null);
224
- React2.useEffect(() => {
221
+ const [config, setConfig] = React3.useState(null);
222
+ const [isLoading, setIsLoading] = React3.useState(true);
223
+ const [identity, setIdentity] = React3.useState(null);
224
+ React3.useEffect(() => {
225
225
  const userIdentity = getUserIdentity(authenticatedAccountId);
226
226
  setIdentity(userIdentity);
227
227
  fetch(`${resolvedApiBase}/ads/config/${siteId}`).then((r) => r.json()).then((data) => {
@@ -244,11 +244,11 @@ function Ad({
244
244
  onClick
245
245
  }) {
246
246
  const { siteId, config, isLoading, identity, apiBase } = useAds();
247
- const [ad, setAd] = React2.useState(null);
248
- const [error, setError] = React2.useState(false);
249
- const impressionTracked = React2.useRef(false);
250
- const containerRef = React2.useRef(null);
251
- React2.useEffect(() => {
247
+ const [ad, setAd] = React3.useState(null);
248
+ const [error, setError] = React3.useState(false);
249
+ const impressionTracked = React3.useRef(false);
250
+ const containerRef = React3.useRef(null);
251
+ React3.useEffect(() => {
252
252
  if (isLoading || !config?.enabled || !siteId || !identity) return;
253
253
  const path = typeof window !== "undefined" ? window.location.pathname : "/";
254
254
  const referrer = typeof document !== "undefined" ? document.referrer : "";
@@ -291,7 +291,7 @@ function Ad({
291
291
  }
292
292
  }).catch(() => setError(true));
293
293
  }, [siteId, config, isLoading, slot, identity, apiBase]);
294
- React2.useEffect(() => {
294
+ React3.useEffect(() => {
295
295
  if (!ad || impressionTracked.current || typeof window === "undefined" || !identity) return;
296
296
  const observer = new IntersectionObserver(
297
297
  ([entry]) => {
@@ -368,12 +368,13 @@ function getSelections(item) {
368
368
  }
369
369
  return void 0;
370
370
  }
371
- function mapItem(item) {
371
+ function mapItem(item, fx) {
372
+ const amt = (value) => fx ? String(fx.convertPrice(value)) : String(value);
372
373
  const result = {
373
374
  name: item.name,
374
375
  quantity: item.quantity,
375
- unit_price: String(item.base_price),
376
- total_price: String(item.total_price),
376
+ unit_price: amt(item.base_price),
377
+ total_price: amt(item.total_price),
377
378
  line_type: item.line_type
378
379
  };
379
380
  if (item.image_url) result.image_url = item.image_url;
@@ -386,7 +387,7 @@ function mapItem(item) {
386
387
  if (item.add_on_options?.length) {
387
388
  result.add_ons = item.add_on_options.map((opt) => ({
388
389
  name: opt.name,
389
- price: String(opt.price ?? "0")
390
+ price: amt(opt.price ?? "0")
390
391
  }));
391
392
  }
392
393
  if (item.special_instructions) {
@@ -394,359 +395,18 @@ function mapItem(item) {
394
395
  }
395
396
  return result;
396
397
  }
397
- function transformToCheckoutCart(cart) {
398
+ function transformToCheckoutCart(cart, fx) {
399
+ const amt = (value) => fx ? String(fx.convertPrice(value)) : String(value);
398
400
  return {
399
- items: cart.items.map(mapItem),
400
- subtotal: String(cart.pricing.subtotal),
401
- tax_amount: String(cart.pricing.tax_amount),
402
- total_discounts: String(cart.pricing.total_discounts),
403
- service_charge: String(cart.pricing.service_charge),
404
- total: String(cart.pricing.total_price),
405
- currency: cart.pricing.currency
401
+ items: cart.items.map((item) => mapItem(item, fx)),
402
+ subtotal: amt(cart.pricing.subtotal),
403
+ tax_amount: amt(cart.pricing.tax_amount),
404
+ total_discounts: amt(cart.pricing.total_discounts),
405
+ service_charge: amt(cart.pricing.service_charge),
406
+ total: amt(cart.pricing.total_price),
407
+ currency: fx?.displayCurrency ?? cart.pricing.currency
406
408
  };
407
409
  }
408
- var SPACE = { sm: 8};
409
- function shellColors(isDark, primaryColor) {
410
- return {
411
- text: isDark ? "#f4f4f5" : "#1a1a1a",
412
- textSecondary: isDark ? "#a1a1aa" : "#52525b",
413
- textMuted: isDark ? "#71717a" : "#a1a1aa",
414
- border: isDark ? "#27272a" : "#e4e4e7",
415
- surface: isDark ? "#18181b" : "#fafafa",
416
- error: "#dc2626",
417
- primary: primaryColor
418
- };
419
- }
420
- function statusToLabel(status) {
421
- if (!status) {
422
- return "";
423
- }
424
- if (status === "preparing") {
425
- return "Preparing checkout";
426
- }
427
- if (status === "recovering") {
428
- return "Resuming payment";
429
- }
430
- if (status === "processing") {
431
- return "Processing payment";
432
- }
433
- if (status === "awaiting_authorization") {
434
- return "Waiting for authorization";
435
- }
436
- if (status === "polling") {
437
- return "Confirming payment";
438
- }
439
- if (status === "finalizing") {
440
- return "Finalizing order";
441
- }
442
- if (status === "success") {
443
- return "Payment complete";
444
- }
445
- return "Payment failed";
446
- }
447
- function CimplifyCheckout({
448
- client,
449
- businessId,
450
- cartId,
451
- locationId,
452
- linkUrl,
453
- orderTypes,
454
- enrollInLink = true,
455
- onComplete,
456
- onError,
457
- onStatusChange,
458
- appearance,
459
- demoMode,
460
- className
461
- }) {
462
- const resolvedOrderTypes = React2.useMemo(
463
- () => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
464
- [orderTypes]
465
- );
466
- const [orderType, setOrderType] = React2.useState(resolvedOrderTypes[0] || "pickup");
467
- const [status, setStatus] = React2.useState(null);
468
- const [statusText, setStatusText] = React2.useState("");
469
- const [isSubmitting, setIsSubmitting] = React2.useState(false);
470
- const [isInitializing, setIsInitializing] = React2.useState(false);
471
- const [errorMessage, setErrorMessage] = React2.useState(null);
472
- const [resolvedBusinessId, setResolvedBusinessId] = React2.useState(businessId ?? null);
473
- const [resolvedCartId, setResolvedCartId] = React2.useState(cartId ?? null);
474
- const [resolvedCart, setResolvedCart] = React2.useState(null);
475
- const checkoutMountRef = React2.useRef(null);
476
- const elementsRef = React2.useRef(null);
477
- const activeCheckoutRef = React2.useRef(null);
478
- const initialAppearanceRef = React2.useRef(appearance);
479
- const hasWarnedInlineAppearanceRef = React2.useRef(false);
480
- const isMountedRef = React2.useRef(true);
481
- const demoRunRef = React2.useRef(0);
482
- const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
483
- const isTestMode = client.isTestMode();
484
- const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
485
- const isDark = appearance?.theme === "dark";
486
- const emitStatus = React2__default.default.useEffectEvent(
487
- (nextStatus, context = {}) => {
488
- setStatus(nextStatus);
489
- setStatusText(context.display_text || "");
490
- onStatusChange?.(nextStatus, context);
491
- }
492
- );
493
- const fireError = React2__default.default.useEffectEvent(
494
- (error) => {
495
- onError?.(error);
496
- }
497
- );
498
- React2.useEffect(() => {
499
- if (!resolvedOrderTypes.includes(orderType)) {
500
- setOrderType(resolvedOrderTypes[0] || "pickup");
501
- }
502
- }, [resolvedOrderTypes, orderType]);
503
- React2.useEffect(() => {
504
- if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
505
- hasWarnedInlineAppearanceRef.current = true;
506
- console.warn(
507
- "[Cimplify] `appearance` prop reference changed after mount. Elements keep the initial appearance to avoid iframe remount. Memoize appearance with useMemo() to remove this warning."
508
- );
509
- }
510
- }, [appearance]);
511
- React2.useEffect(() => {
512
- let cancelled = false;
513
- async function bootstrap() {
514
- if (isDemoCheckout) {
515
- if (!cancelled) {
516
- setResolvedBusinessId(businessId ?? null);
517
- setResolvedCartId(cartId ?? "cart_demo");
518
- setIsInitializing(false);
519
- setErrorMessage(null);
520
- }
521
- return;
522
- }
523
- const needsBusinessResolve = !businessId;
524
- const needsCartResolve = !cartId;
525
- if (!needsBusinessResolve && !needsCartResolve) {
526
- if (!cancelled) {
527
- setResolvedBusinessId(businessId || null);
528
- setResolvedCartId(cartId || null);
529
- setIsInitializing(false);
530
- setErrorMessage(null);
531
- }
532
- client.cart.get().then((cartResult) => {
533
- if (!cancelled && cartResult.ok && cartResult.value) {
534
- setResolvedCart(cartResult.value);
535
- }
536
- }).catch(() => {
537
- });
538
- return;
539
- }
540
- if (!cancelled) {
541
- setIsInitializing(true);
542
- setErrorMessage(null);
543
- }
544
- let nextBusinessId = businessId ?? null;
545
- if (!nextBusinessId) {
546
- try {
547
- nextBusinessId = await client.resolveBusinessId();
548
- } catch {
549
- if (!cancelled) {
550
- const message = "Unable to initialize checkout business context.";
551
- setResolvedBusinessId(null);
552
- setResolvedCartId(null);
553
- setErrorMessage(message);
554
- setIsInitializing(false);
555
- fireError({ code: "BUSINESS_ID_REQUIRED", message });
556
- }
557
- return;
558
- }
559
- }
560
- let nextCartId = cartId ?? null;
561
- if (!nextCartId) {
562
- const cartResult = await client.cart.get();
563
- if (!cartResult.ok || !cartResult.value?.id || cartResult.value.items.length === 0) {
564
- if (!cancelled) {
565
- const message = "Your cart is empty. Add items before checkout.";
566
- setResolvedBusinessId(nextBusinessId);
567
- setResolvedCartId(null);
568
- setErrorMessage(message);
569
- setIsInitializing(false);
570
- fireError({ code: "CART_EMPTY", message });
571
- }
572
- return;
573
- }
574
- nextCartId = cartResult.value.id;
575
- if (!cancelled) {
576
- setResolvedCart(cartResult.value);
577
- }
578
- }
579
- if (!cancelled) {
580
- setResolvedBusinessId(nextBusinessId);
581
- setResolvedCartId(nextCartId);
582
- setIsInitializing(false);
583
- setErrorMessage(null);
584
- }
585
- }
586
- void bootstrap();
587
- return () => {
588
- cancelled = true;
589
- };
590
- }, [businessId, cartId, client, isDemoCheckout]);
591
- React2.useEffect(() => {
592
- return () => {
593
- isMountedRef.current = false;
594
- demoRunRef.current += 1;
595
- activeCheckoutRef.current?.abort();
596
- activeCheckoutRef.current = null;
597
- };
598
- }, []);
599
- const handleSubmit = React2__default.default.useEffectEvent(async () => {
600
- if (isSubmitting || isInitializing || !resolvedCartId) {
601
- if (!resolvedCartId && !isInitializing) {
602
- const message = "Your cart is empty. Add items before checkout.";
603
- setErrorMessage(message);
604
- fireError({ code: "CART_EMPTY", message });
605
- }
606
- return;
607
- }
608
- setErrorMessage(null);
609
- setIsSubmitting(true);
610
- emitStatus("preparing", { display_text: statusToLabel("preparing") });
611
- if (isDemoCheckout) {
612
- const runId = demoRunRef.current + 1;
613
- demoRunRef.current = runId;
614
- const wait = async (ms) => {
615
- await new Promise((resolve) => setTimeout(resolve, ms));
616
- return isMountedRef.current && runId === demoRunRef.current;
617
- };
618
- try {
619
- if (!await wait(400)) return;
620
- emitStatus("processing", { display_text: statusToLabel("processing") });
621
- if (!await wait(900)) return;
622
- emitStatus("polling", { display_text: statusToLabel("polling") });
623
- if (!await wait(1200)) return;
624
- const result = {
625
- success: true,
626
- order: {
627
- id: `ord_demo_${Date.now()}`,
628
- order_number: `DEMO-${Math.random().toString(36).slice(2, 8).toUpperCase()}`,
629
- status: "confirmed",
630
- total: "0.00",
631
- currency: "USD"
632
- }
633
- };
634
- emitStatus("success", {
635
- order_id: result.order?.id,
636
- order_number: result.order?.order_number,
637
- display_text: statusToLabel("success")
638
- });
639
- onComplete(result);
640
- } finally {
641
- if (isMountedRef.current && runId === demoRunRef.current) {
642
- setIsSubmitting(false);
643
- }
644
- }
645
- return;
646
- }
647
- if (!elementsRef.current) {
648
- const message = "Checkout is still initializing. Please try again.";
649
- setErrorMessage(message);
650
- fireError({ code: "CHECKOUT_NOT_READY", message });
651
- setIsSubmitting(false);
652
- return;
653
- }
654
- const checkout = elementsRef.current.processCheckout({
655
- cart_id: resolvedCartId,
656
- location_id: locationId ?? client.getLocationId() ?? void 0,
657
- order_type: orderType,
658
- enroll_in_link: enrollInLink,
659
- on_status_change: emitStatus
660
- });
661
- activeCheckoutRef.current = checkout;
662
- try {
663
- const result = await checkout;
664
- if (result.success) {
665
- onComplete(result);
666
- return;
667
- }
668
- const code = result.error?.code || "CHECKOUT_FAILED";
669
- const message = result.error?.message || "Payment failed.";
670
- setErrorMessage(message);
671
- fireError({ code, message });
672
- } finally {
673
- if (isMountedRef.current) {
674
- activeCheckoutRef.current = null;
675
- setIsSubmitting(false);
676
- }
677
- }
678
- });
679
- React2.useEffect(() => {
680
- if (isDemoCheckout || !resolvedBusinessId) {
681
- elementsRef.current = null;
682
- return;
683
- }
684
- const elements = client.elements(resolvedBusinessId, {
685
- appearance: initialAppearanceRef.current,
686
- linkUrl
687
- });
688
- elementsRef.current = elements;
689
- const checkout = elements.create("checkout", {
690
- orderTypes: resolvedOrderTypes,
691
- defaultOrderType: resolvedOrderTypes[0]
692
- });
693
- if (checkoutMountRef.current) {
694
- checkout.mount(checkoutMountRef.current);
695
- }
696
- checkout.on("ready", () => {
697
- if (resolvedCart) {
698
- checkout.setCart(transformToCheckoutCart(resolvedCart));
699
- }
700
- });
701
- checkout.on("order_type_changed", (data) => {
702
- const typed = data;
703
- if (typed.orderType) {
704
- setOrderType(typed.orderType);
705
- }
706
- });
707
- checkout.on("request_submit", () => {
708
- void handleSubmit();
709
- });
710
- return () => {
711
- activeCheckoutRef.current?.abort();
712
- activeCheckoutRef.current = null;
713
- elements.destroy();
714
- elementsRef.current = null;
715
- };
716
- }, [client, resolvedBusinessId, isDemoCheckout]);
717
- React2.useEffect(() => {
718
- if (!resolvedCart || !elementsRef.current) return;
719
- const checkoutElement = elementsRef.current.getElement("checkout");
720
- if (checkoutElement) {
721
- checkoutElement.setCart(transformToCheckoutCart(resolvedCart));
722
- }
723
- }, [resolvedCart]);
724
- const colors = shellColors(isDark ?? false, primaryColor);
725
- if (isInitializing) {
726
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { fontSize: 13, color: colors.textSecondary }, children: "Preparing checkout..." }) });
727
- }
728
- if (!isDemoCheckout && (!resolvedBusinessId || !resolvedCartId)) {
729
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { fontSize: 13, color: colors.error }, children: errorMessage || "Unable to initialize checkout. Please refresh and try again." }) });
730
- }
731
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-cimplify-checkout": "", children: [
732
- isTestMode && !isDemoCheckout && /* @__PURE__ */ jsxRuntime.jsx(
733
- "p",
734
- {
735
- "data-cimplify-test-mode": "",
736
- style: {
737
- marginBottom: "10px",
738
- fontSize: "12px",
739
- fontWeight: 600,
740
- color: "#92400e"
741
- },
742
- children: "Test mode - no real charges"
743
- }
744
- ),
745
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-section": "checkout", children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: isDemoCheckout ? void 0 : checkoutMountRef }) }),
746
- status && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.textSecondary }, children: statusText || statusToLabel(status) }),
747
- errorMessage && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.error }, children: errorMessage })
748
- ] });
749
- }
750
410
 
751
411
  // src/types/common.ts
752
412
  function money(value) {
@@ -755,6 +415,59 @@ function money(value) {
755
415
  function moneyFromNumber(value) {
756
416
  return value.toFixed(2);
757
417
  }
418
+ var SUPPORTED_CURRENCY_CODES = /* @__PURE__ */ new Set([
419
+ "USD",
420
+ "EUR",
421
+ "GBP",
422
+ "JPY",
423
+ "CNY",
424
+ "CHF",
425
+ "CAD",
426
+ "AUD",
427
+ "GHS",
428
+ "NGN",
429
+ "KES",
430
+ "ZAR",
431
+ "XOF",
432
+ "XAF",
433
+ "EGP",
434
+ "TZS",
435
+ "UGX",
436
+ "RWF",
437
+ "ETB",
438
+ "ZMW",
439
+ "BWP",
440
+ "MUR",
441
+ "NAD",
442
+ "MWK",
443
+ "AOA",
444
+ "CDF",
445
+ "GMD",
446
+ "GNF",
447
+ "LRD",
448
+ "SLL",
449
+ "MZN",
450
+ "BIF",
451
+ "INR",
452
+ "BRL",
453
+ "MXN",
454
+ "KRW",
455
+ "TRY",
456
+ "THB",
457
+ "MYR",
458
+ "PHP",
459
+ "IDR",
460
+ "VND",
461
+ "SGD",
462
+ "HKD",
463
+ "TWD",
464
+ "AED",
465
+ "SAR",
466
+ "ILS"
467
+ ]);
468
+ function isSupportedCurrency(code) {
469
+ return SUPPORTED_CURRENCY_CODES.has(code);
470
+ }
758
471
  function currencyCode(value) {
759
472
  return value;
760
473
  }
@@ -1360,6 +1073,97 @@ var MOBILE_MONEY_PROVIDER = {
1360
1073
  };
1361
1074
 
1362
1075
  // src/utils/price.ts
1076
+ var CURRENCY_SYMBOLS = {
1077
+ // Major world currencies
1078
+ USD: "$",
1079
+ EUR: "\u20AC",
1080
+ GBP: "\xA3",
1081
+ JPY: "\xA5",
1082
+ CNY: "\xA5",
1083
+ CHF: "CHF",
1084
+ CAD: "C$",
1085
+ AUD: "A$",
1086
+ NZD: "NZ$",
1087
+ HKD: "HK$",
1088
+ SGD: "S$",
1089
+ INR: "\u20B9",
1090
+ BRL: "R$",
1091
+ MXN: "MX$",
1092
+ KRW: "\u20A9",
1093
+ RUB: "\u20BD",
1094
+ TRY: "\u20BA",
1095
+ THB: "\u0E3F",
1096
+ PLN: "z\u0142",
1097
+ SEK: "kr",
1098
+ NOK: "kr",
1099
+ DKK: "kr",
1100
+ CZK: "K\u010D",
1101
+ HUF: "Ft",
1102
+ ILS: "\u20AA",
1103
+ AED: "\u062F.\u0625",
1104
+ SAR: "\uFDFC",
1105
+ MYR: "RM",
1106
+ PHP: "\u20B1",
1107
+ IDR: "Rp",
1108
+ VND: "\u20AB",
1109
+ TWD: "NT$",
1110
+ // African currencies
1111
+ GHS: "GH\u20B5",
1112
+ NGN: "\u20A6",
1113
+ KES: "KSh",
1114
+ ZAR: "R",
1115
+ XOF: "CFA",
1116
+ XAF: "FCFA",
1117
+ EGP: "E\xA3",
1118
+ MAD: "MAD",
1119
+ TZS: "TSh",
1120
+ UGX: "USh",
1121
+ RWF: "FRw",
1122
+ ETB: "Br",
1123
+ ZMW: "ZK",
1124
+ BWP: "P",
1125
+ MUR: "\u20A8",
1126
+ SCR: "\u20A8",
1127
+ NAD: "N$",
1128
+ SZL: "E",
1129
+ LSL: "L",
1130
+ MWK: "MK",
1131
+ AOA: "Kz",
1132
+ CDF: "FC",
1133
+ GMD: "D",
1134
+ GNF: "FG",
1135
+ LRD: "L$",
1136
+ SLL: "Le",
1137
+ MZN: "MT",
1138
+ SDG: "SDG",
1139
+ SSP: "SSP",
1140
+ SOS: "Sh.So.",
1141
+ DJF: "Fdj",
1142
+ ERN: "Nfk",
1143
+ CVE: "$",
1144
+ STN: "Db",
1145
+ KMF: "CF",
1146
+ BIF: "FBu"
1147
+ };
1148
+ function getCurrencySymbol(currencyCode2) {
1149
+ return CURRENCY_SYMBOLS[currencyCode2.toUpperCase()] || currencyCode2;
1150
+ }
1151
+ function formatPrice(amount, currency = "GHS", locale = "en-US") {
1152
+ const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
1153
+ if (isNaN(numAmount)) {
1154
+ return `${getCurrencySymbol(currency)}0.00`;
1155
+ }
1156
+ try {
1157
+ return new Intl.NumberFormat(locale, {
1158
+ style: "currency",
1159
+ currency: currency.toUpperCase(),
1160
+ minimumFractionDigits: 2,
1161
+ maximumFractionDigits: 2
1162
+ }).format(numAmount);
1163
+ } catch {
1164
+ return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
1165
+ }
1166
+ }
1363
1167
  function parsePrice(value) {
1364
1168
  if (value === void 0 || value === null) {
1365
1169
  return 0;
@@ -4320,6 +4124,8 @@ function createCimplifyClient(config = {}) {
4320
4124
  return new CimplifyClient(config);
4321
4125
  }
4322
4126
  var LOCATION_STORAGE_KEY = "cimplify_location_id";
4127
+ var DISPLAY_CURRENCY_STORAGE_KEY = "cimplify_display_currency";
4128
+ var FX_REFRESH_INTERVAL = 12e4;
4323
4129
  var DEFAULT_CURRENCY = "USD";
4324
4130
  var DEFAULT_COUNTRY = "US";
4325
4131
  function createDefaultClient() {
@@ -4348,6 +4154,27 @@ function setStoredLocationId(locationId) {
4348
4154
  }
4349
4155
  window.localStorage.setItem(LOCATION_STORAGE_KEY, locationId);
4350
4156
  }
4157
+ function getStoredDisplayCurrency() {
4158
+ if (typeof window === "undefined" || !window.localStorage) {
4159
+ return null;
4160
+ }
4161
+ const value = window.localStorage.getItem(DISPLAY_CURRENCY_STORAGE_KEY);
4162
+ if (!value) {
4163
+ return null;
4164
+ }
4165
+ const normalized = value.trim().toUpperCase();
4166
+ return normalized.length > 0 ? normalized : null;
4167
+ }
4168
+ function setStoredDisplayCurrency(currency) {
4169
+ if (typeof window === "undefined" || !window.localStorage) {
4170
+ return;
4171
+ }
4172
+ if (!currency) {
4173
+ window.localStorage.removeItem(DISPLAY_CURRENCY_STORAGE_KEY);
4174
+ return;
4175
+ }
4176
+ window.localStorage.setItem(DISPLAY_CURRENCY_STORAGE_KEY, currency.toUpperCase());
4177
+ }
4351
4178
  function resolveInitialLocation(locations) {
4352
4179
  if (locations.length === 0) {
4353
4180
  return null;
@@ -4361,23 +4188,77 @@ function resolveInitialLocation(locations) {
4361
4188
  }
4362
4189
  return locations[0];
4363
4190
  }
4364
- var CimplifyContext = React2.createContext(null);
4191
+ var CimplifyContext = React3.createContext(null);
4365
4192
  function CimplifyProvider({
4366
4193
  client,
4367
4194
  children,
4368
4195
  onLocationChange
4369
4196
  }) {
4370
- const resolvedClient = React2.useMemo(() => client ?? createDefaultClient(), [client]);
4371
- const onLocationChangeRef = React2.useRef(onLocationChange);
4372
- const [business, setBusiness] = React2.useState(null);
4373
- const [locations, setLocations] = React2.useState([]);
4374
- const [currentLocation, setCurrentLocationState] = React2.useState(null);
4375
- const [isReady, setIsReady] = React2.useState(false);
4376
- React2.useEffect(() => {
4197
+ const resolvedClient = React3.useMemo(() => client ?? createDefaultClient(), [client]);
4198
+ const onLocationChangeRef = React3.useRef(onLocationChange);
4199
+ const [business, setBusiness] = React3.useState(null);
4200
+ const [locations, setLocations] = React3.useState([]);
4201
+ const [currentLocation, setCurrentLocationState] = React3.useState(null);
4202
+ const [isReady, setIsReady] = React3.useState(false);
4203
+ React3.useEffect(() => {
4377
4204
  onLocationChangeRef.current = onLocationChange;
4378
4205
  }, [onLocationChange]);
4379
4206
  const isDemoMode = resolvedClient.getPublicKey().trim().length === 0;
4380
- const setCurrentLocation = React2.useCallback(
4207
+ const baseCurrency = business?.default_currency || DEFAULT_CURRENCY;
4208
+ const [displayCurrencyOverride, setDisplayCurrencyOverride] = React3.useState(
4209
+ () => getStoredDisplayCurrency()
4210
+ );
4211
+ const [fxRate, setFxRate] = React3.useState(null);
4212
+ const displayCurrency = displayCurrencyOverride && displayCurrencyOverride !== baseCurrency ? displayCurrencyOverride : baseCurrency;
4213
+ const setDisplayCurrency = React3.useCallback(
4214
+ (currency) => {
4215
+ const normalized = currency?.trim().toUpperCase() || null;
4216
+ if (normalized && !isSupportedCurrency(normalized)) {
4217
+ return;
4218
+ }
4219
+ setDisplayCurrencyOverride(normalized);
4220
+ setStoredDisplayCurrency(normalized);
4221
+ if (!normalized || normalized === baseCurrency) {
4222
+ setFxRate(null);
4223
+ }
4224
+ },
4225
+ [baseCurrency]
4226
+ );
4227
+ React3.useEffect(() => {
4228
+ if (displayCurrency === baseCurrency || isDemoMode) {
4229
+ setFxRate(null);
4230
+ return;
4231
+ }
4232
+ let cancelled = false;
4233
+ async function fetchRate() {
4234
+ const result = await resolvedClient.fx.getRate(
4235
+ baseCurrency,
4236
+ displayCurrency
4237
+ );
4238
+ if (cancelled) return;
4239
+ if (result.ok) {
4240
+ setFxRate(result.value.rate);
4241
+ } else {
4242
+ setFxRate(null);
4243
+ }
4244
+ }
4245
+ void fetchRate();
4246
+ const intervalId = setInterval(() => void fetchRate(), FX_REFRESH_INTERVAL);
4247
+ return () => {
4248
+ cancelled = true;
4249
+ clearInterval(intervalId);
4250
+ };
4251
+ }, [resolvedClient, baseCurrency, displayCurrency, isDemoMode]);
4252
+ const convertPrice = React3.useCallback(
4253
+ (amount) => {
4254
+ const num = typeof amount === "string" ? parseFloat(amount) : amount;
4255
+ if (isNaN(num)) return 0;
4256
+ if (!fxRate || displayCurrency === baseCurrency) return num;
4257
+ return Math.round(num * fxRate * 100) / 100;
4258
+ },
4259
+ [fxRate, displayCurrency, baseCurrency]
4260
+ );
4261
+ const setCurrentLocation = React3.useCallback(
4381
4262
  (location) => {
4382
4263
  setCurrentLocationState(location);
4383
4264
  resolvedClient.setLocationId(location.id);
@@ -4386,7 +4267,7 @@ function CimplifyProvider({
4386
4267
  },
4387
4268
  [resolvedClient]
4388
4269
  );
4389
- React2.useEffect(() => {
4270
+ React3.useEffect(() => {
4390
4271
  let cancelled = false;
4391
4272
  async function bootstrap() {
4392
4273
  setIsReady(false);
@@ -4401,80 +4282,454 @@ function CimplifyProvider({
4401
4282
  }
4402
4283
  return;
4403
4284
  }
4404
- const [businessResult, locationsResult] = await Promise.all([
4405
- resolvedClient.business.getInfo(),
4406
- resolvedClient.business.getLocations()
4407
- ]);
4408
- if (cancelled) {
4409
- return;
4285
+ const [businessResult, locationsResult] = await Promise.all([
4286
+ resolvedClient.business.getInfo(),
4287
+ resolvedClient.business.getLocations()
4288
+ ]);
4289
+ if (cancelled) {
4290
+ return;
4291
+ }
4292
+ const nextBusiness = businessResult.ok ? businessResult.value : null;
4293
+ const nextLocations = locationsResult.ok && Array.isArray(locationsResult.value) ? locationsResult.value : [];
4294
+ const initialLocation = resolveInitialLocation(nextLocations);
4295
+ setBusiness(nextBusiness);
4296
+ if (nextBusiness?.id) {
4297
+ resolvedClient.setBusinessId(nextBusiness.id);
4298
+ }
4299
+ setLocations(nextLocations);
4300
+ if (initialLocation) {
4301
+ setCurrentLocationState(initialLocation);
4302
+ resolvedClient.setLocationId(initialLocation.id);
4303
+ setStoredLocationId(initialLocation.id);
4304
+ } else {
4305
+ setCurrentLocationState(null);
4306
+ resolvedClient.setLocationId(null);
4307
+ setStoredLocationId(null);
4308
+ }
4309
+ setIsReady(true);
4310
+ }
4311
+ bootstrap().catch(() => {
4312
+ if (cancelled) {
4313
+ return;
4314
+ }
4315
+ setBusiness(null);
4316
+ setLocations([]);
4317
+ setCurrentLocationState(null);
4318
+ resolvedClient.setLocationId(null);
4319
+ setStoredLocationId(null);
4320
+ setIsReady(true);
4321
+ });
4322
+ return () => {
4323
+ cancelled = true;
4324
+ };
4325
+ }, [resolvedClient, isDemoMode]);
4326
+ const contextValue = React3.useMemo(
4327
+ () => ({
4328
+ client: resolvedClient,
4329
+ business,
4330
+ currency: baseCurrency,
4331
+ country: business?.country_code || DEFAULT_COUNTRY,
4332
+ locations,
4333
+ currentLocation,
4334
+ setCurrentLocation,
4335
+ isReady,
4336
+ isDemoMode,
4337
+ baseCurrency,
4338
+ displayCurrency,
4339
+ setDisplayCurrency,
4340
+ convertPrice,
4341
+ fxRate
4342
+ }),
4343
+ [
4344
+ resolvedClient,
4345
+ business,
4346
+ baseCurrency,
4347
+ locations,
4348
+ currentLocation,
4349
+ setCurrentLocation,
4350
+ isReady,
4351
+ isDemoMode,
4352
+ displayCurrency,
4353
+ setDisplayCurrency,
4354
+ convertPrice,
4355
+ fxRate
4356
+ ]
4357
+ );
4358
+ return /* @__PURE__ */ jsxRuntime.jsx(CimplifyContext.Provider, { value: contextValue, children });
4359
+ }
4360
+ function useCimplify() {
4361
+ const context = React3.useContext(CimplifyContext);
4362
+ if (!context) {
4363
+ throw new Error("useCimplify must be used within CimplifyProvider");
4364
+ }
4365
+ return context;
4366
+ }
4367
+ function useOptionalCimplify() {
4368
+ return React3.useContext(CimplifyContext);
4369
+ }
4370
+ var SPACE = { sm: 8};
4371
+ function shellColors(isDark, primaryColor) {
4372
+ return {
4373
+ text: isDark ? "#f4f4f5" : "#1a1a1a",
4374
+ textSecondary: isDark ? "#a1a1aa" : "#52525b",
4375
+ textMuted: isDark ? "#71717a" : "#a1a1aa",
4376
+ border: isDark ? "#27272a" : "#e4e4e7",
4377
+ surface: isDark ? "#18181b" : "#fafafa",
4378
+ error: "#dc2626",
4379
+ primary: primaryColor
4380
+ };
4381
+ }
4382
+ function statusToLabel(status) {
4383
+ if (!status) {
4384
+ return "";
4385
+ }
4386
+ if (status === "preparing") {
4387
+ return "Preparing checkout";
4388
+ }
4389
+ if (status === "recovering") {
4390
+ return "Resuming payment";
4391
+ }
4392
+ if (status === "processing") {
4393
+ return "Processing payment";
4394
+ }
4395
+ if (status === "awaiting_authorization") {
4396
+ return "Waiting for authorization";
4397
+ }
4398
+ if (status === "polling") {
4399
+ return "Confirming payment";
4400
+ }
4401
+ if (status === "finalizing") {
4402
+ return "Finalizing order";
4403
+ }
4404
+ if (status === "success") {
4405
+ return "Payment complete";
4406
+ }
4407
+ return "Payment failed";
4408
+ }
4409
+ function CimplifyCheckout({
4410
+ client,
4411
+ businessId,
4412
+ cartId,
4413
+ locationId,
4414
+ linkUrl,
4415
+ orderTypes,
4416
+ enrollInLink = true,
4417
+ onComplete,
4418
+ onError,
4419
+ onStatusChange,
4420
+ appearance,
4421
+ demoMode,
4422
+ className
4423
+ }) {
4424
+ const resolvedOrderTypes = React3.useMemo(
4425
+ () => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
4426
+ [orderTypes]
4427
+ );
4428
+ const [orderType, setOrderType] = React3.useState(resolvedOrderTypes[0] || "pickup");
4429
+ const [status, setStatus] = React3.useState(null);
4430
+ const [statusText, setStatusText] = React3.useState("");
4431
+ const [isSubmitting, setIsSubmitting] = React3.useState(false);
4432
+ const [isInitializing, setIsInitializing] = React3.useState(false);
4433
+ const [errorMessage, setErrorMessage] = React3.useState(null);
4434
+ const [resolvedBusinessId, setResolvedBusinessId] = React3.useState(businessId ?? null);
4435
+ const [resolvedCartId, setResolvedCartId] = React3.useState(cartId ?? null);
4436
+ const [resolvedCart, setResolvedCart] = React3.useState(null);
4437
+ const checkoutMountRef = React3.useRef(null);
4438
+ const elementsRef = React3.useRef(null);
4439
+ const activeCheckoutRef = React3.useRef(null);
4440
+ const initialAppearanceRef = React3.useRef(appearance);
4441
+ const hasWarnedInlineAppearanceRef = React3.useRef(false);
4442
+ const isMountedRef = React3.useRef(true);
4443
+ const demoRunRef = React3.useRef(0);
4444
+ const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
4445
+ const isTestMode = client.isTestMode();
4446
+ const cimplifyCtx = useOptionalCimplify();
4447
+ const fxOptions = React3.useMemo(() => {
4448
+ if (!cimplifyCtx?.fxRate) return void 0;
4449
+ if (cimplifyCtx.displayCurrency === cimplifyCtx.baseCurrency) return void 0;
4450
+ return {
4451
+ displayCurrency: cimplifyCtx.displayCurrency,
4452
+ convertPrice: cimplifyCtx.convertPrice
4453
+ };
4454
+ }, [cimplifyCtx?.fxRate, cimplifyCtx?.displayCurrency, cimplifyCtx?.baseCurrency, cimplifyCtx?.convertPrice]);
4455
+ const fxOptionsRef = React3.useRef(fxOptions);
4456
+ fxOptionsRef.current = fxOptions;
4457
+ const resolvedCartRef = React3.useRef(resolvedCart);
4458
+ resolvedCartRef.current = resolvedCart;
4459
+ const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
4460
+ const isDark = appearance?.theme === "dark";
4461
+ const emitStatus = React3__default.default.useEffectEvent(
4462
+ (nextStatus, context = {}) => {
4463
+ setStatus(nextStatus);
4464
+ setStatusText(context.display_text || "");
4465
+ onStatusChange?.(nextStatus, context);
4466
+ }
4467
+ );
4468
+ const fireError = React3__default.default.useEffectEvent(
4469
+ (error) => {
4470
+ onError?.(error);
4471
+ }
4472
+ );
4473
+ React3.useEffect(() => {
4474
+ if (!resolvedOrderTypes.includes(orderType)) {
4475
+ setOrderType(resolvedOrderTypes[0] || "pickup");
4476
+ }
4477
+ }, [resolvedOrderTypes, orderType]);
4478
+ React3.useEffect(() => {
4479
+ if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
4480
+ hasWarnedInlineAppearanceRef.current = true;
4481
+ console.warn(
4482
+ "[Cimplify] `appearance` prop reference changed after mount. Elements keep the initial appearance to avoid iframe remount. Memoize appearance with useMemo() to remove this warning."
4483
+ );
4484
+ }
4485
+ }, [appearance]);
4486
+ React3.useEffect(() => {
4487
+ let cancelled = false;
4488
+ async function bootstrap() {
4489
+ if (isDemoCheckout) {
4490
+ if (!cancelled) {
4491
+ setResolvedBusinessId(businessId ?? null);
4492
+ setResolvedCartId(cartId ?? "cart_demo");
4493
+ setIsInitializing(false);
4494
+ setErrorMessage(null);
4495
+ }
4496
+ return;
4497
+ }
4498
+ const needsBusinessResolve = !businessId;
4499
+ const needsCartResolve = !cartId;
4500
+ if (!needsBusinessResolve && !needsCartResolve) {
4501
+ if (!cancelled) {
4502
+ setResolvedBusinessId(businessId || null);
4503
+ setResolvedCartId(cartId || null);
4504
+ setIsInitializing(false);
4505
+ setErrorMessage(null);
4506
+ }
4507
+ client.cart.get().then((cartResult) => {
4508
+ if (!cancelled && cartResult.ok && cartResult.value) {
4509
+ setResolvedCart(cartResult.value);
4510
+ }
4511
+ }).catch(() => {
4512
+ });
4513
+ return;
4514
+ }
4515
+ if (!cancelled) {
4516
+ setIsInitializing(true);
4517
+ setErrorMessage(null);
4410
4518
  }
4411
- const nextBusiness = businessResult.ok ? businessResult.value : null;
4412
- const nextLocations = locationsResult.ok && Array.isArray(locationsResult.value) ? locationsResult.value : [];
4413
- const initialLocation = resolveInitialLocation(nextLocations);
4414
- setBusiness(nextBusiness);
4415
- if (nextBusiness?.id) {
4416
- resolvedClient.setBusinessId(nextBusiness.id);
4519
+ let nextBusinessId = businessId ?? null;
4520
+ if (!nextBusinessId) {
4521
+ try {
4522
+ nextBusinessId = await client.resolveBusinessId();
4523
+ } catch {
4524
+ if (!cancelled) {
4525
+ const message = "Unable to initialize checkout business context.";
4526
+ setResolvedBusinessId(null);
4527
+ setResolvedCartId(null);
4528
+ setErrorMessage(message);
4529
+ setIsInitializing(false);
4530
+ fireError({ code: "BUSINESS_ID_REQUIRED", message });
4531
+ }
4532
+ return;
4533
+ }
4417
4534
  }
4418
- setLocations(nextLocations);
4419
- if (initialLocation) {
4420
- setCurrentLocationState(initialLocation);
4421
- resolvedClient.setLocationId(initialLocation.id);
4422
- setStoredLocationId(initialLocation.id);
4423
- } else {
4424
- setCurrentLocationState(null);
4425
- resolvedClient.setLocationId(null);
4426
- setStoredLocationId(null);
4535
+ let nextCartId = cartId ?? null;
4536
+ if (!nextCartId) {
4537
+ const cartResult = await client.cart.get();
4538
+ if (!cartResult.ok || !cartResult.value?.id || cartResult.value.items.length === 0) {
4539
+ if (!cancelled) {
4540
+ const message = "Your cart is empty. Add items before checkout.";
4541
+ setResolvedBusinessId(nextBusinessId);
4542
+ setResolvedCartId(null);
4543
+ setErrorMessage(message);
4544
+ setIsInitializing(false);
4545
+ fireError({ code: "CART_EMPTY", message });
4546
+ }
4547
+ return;
4548
+ }
4549
+ nextCartId = cartResult.value.id;
4550
+ if (!cancelled) {
4551
+ setResolvedCart(cartResult.value);
4552
+ }
4553
+ }
4554
+ if (!cancelled) {
4555
+ setResolvedBusinessId(nextBusinessId);
4556
+ setResolvedCartId(nextCartId);
4557
+ setIsInitializing(false);
4558
+ setErrorMessage(null);
4427
4559
  }
4428
- setIsReady(true);
4429
4560
  }
4430
- bootstrap().catch(() => {
4431
- if (cancelled) {
4561
+ void bootstrap();
4562
+ return () => {
4563
+ cancelled = true;
4564
+ };
4565
+ }, [businessId, cartId, client, isDemoCheckout]);
4566
+ React3.useEffect(() => {
4567
+ return () => {
4568
+ isMountedRef.current = false;
4569
+ demoRunRef.current += 1;
4570
+ activeCheckoutRef.current?.abort();
4571
+ activeCheckoutRef.current = null;
4572
+ };
4573
+ }, []);
4574
+ const handleSubmit = React3__default.default.useEffectEvent(async () => {
4575
+ if (isSubmitting || isInitializing || !resolvedCartId) {
4576
+ if (!resolvedCartId && !isInitializing) {
4577
+ const message = "Your cart is empty. Add items before checkout.";
4578
+ setErrorMessage(message);
4579
+ fireError({ code: "CART_EMPTY", message });
4580
+ }
4581
+ return;
4582
+ }
4583
+ setErrorMessage(null);
4584
+ setIsSubmitting(true);
4585
+ emitStatus("preparing", { display_text: statusToLabel("preparing") });
4586
+ if (isDemoCheckout) {
4587
+ const runId = demoRunRef.current + 1;
4588
+ demoRunRef.current = runId;
4589
+ const wait = async (ms) => {
4590
+ await new Promise((resolve) => setTimeout(resolve, ms));
4591
+ return isMountedRef.current && runId === demoRunRef.current;
4592
+ };
4593
+ try {
4594
+ if (!await wait(400)) return;
4595
+ emitStatus("processing", { display_text: statusToLabel("processing") });
4596
+ if (!await wait(900)) return;
4597
+ emitStatus("polling", { display_text: statusToLabel("polling") });
4598
+ if (!await wait(1200)) return;
4599
+ const result = {
4600
+ success: true,
4601
+ order: {
4602
+ id: `ord_demo_${Date.now()}`,
4603
+ order_number: `DEMO-${Math.random().toString(36).slice(2, 8).toUpperCase()}`,
4604
+ status: "confirmed",
4605
+ total: "0.00",
4606
+ currency: "USD"
4607
+ }
4608
+ };
4609
+ emitStatus("success", {
4610
+ order_id: result.order?.id,
4611
+ order_number: result.order?.order_number,
4612
+ display_text: statusToLabel("success")
4613
+ });
4614
+ onComplete(result);
4615
+ } finally {
4616
+ if (isMountedRef.current && runId === demoRunRef.current) {
4617
+ setIsSubmitting(false);
4618
+ }
4619
+ }
4620
+ return;
4621
+ }
4622
+ if (!elementsRef.current) {
4623
+ const message = "Checkout is still initializing. Please try again.";
4624
+ setErrorMessage(message);
4625
+ fireError({ code: "CHECKOUT_NOT_READY", message });
4626
+ setIsSubmitting(false);
4627
+ return;
4628
+ }
4629
+ const checkout = elementsRef.current.processCheckout({
4630
+ cart_id: resolvedCartId,
4631
+ location_id: locationId ?? client.getLocationId() ?? void 0,
4632
+ order_type: orderType,
4633
+ enroll_in_link: enrollInLink,
4634
+ on_status_change: emitStatus,
4635
+ pay_currency: fxOptions?.displayCurrency
4636
+ });
4637
+ activeCheckoutRef.current = checkout;
4638
+ try {
4639
+ const result = await checkout;
4640
+ if (result.success) {
4641
+ onComplete(result);
4432
4642
  return;
4433
4643
  }
4434
- setBusiness(null);
4435
- setLocations([]);
4436
- setCurrentLocationState(null);
4437
- resolvedClient.setLocationId(null);
4438
- setStoredLocationId(null);
4439
- setIsReady(true);
4644
+ const code = result.error?.code || "CHECKOUT_FAILED";
4645
+ const message = result.error?.message || "Payment failed.";
4646
+ setErrorMessage(message);
4647
+ fireError({ code, message });
4648
+ } finally {
4649
+ if (isMountedRef.current) {
4650
+ activeCheckoutRef.current = null;
4651
+ setIsSubmitting(false);
4652
+ }
4653
+ }
4654
+ });
4655
+ React3.useEffect(() => {
4656
+ if (isDemoCheckout || !resolvedBusinessId) {
4657
+ elementsRef.current = null;
4658
+ return;
4659
+ }
4660
+ const elements = client.elements(resolvedBusinessId, {
4661
+ appearance: initialAppearanceRef.current,
4662
+ linkUrl
4663
+ });
4664
+ elementsRef.current = elements;
4665
+ const checkout = elements.create("checkout", {
4666
+ orderTypes: resolvedOrderTypes,
4667
+ defaultOrderType: resolvedOrderTypes[0]
4668
+ });
4669
+ if (checkoutMountRef.current) {
4670
+ checkout.mount(checkoutMountRef.current);
4671
+ }
4672
+ checkout.on("ready", () => {
4673
+ const cart = resolvedCartRef.current;
4674
+ if (cart) {
4675
+ checkout.setCart(transformToCheckoutCart(cart, fxOptionsRef.current));
4676
+ }
4677
+ });
4678
+ checkout.on("order_type_changed", (data) => {
4679
+ const typed = data;
4680
+ if (typed.orderType) {
4681
+ setOrderType(typed.orderType);
4682
+ }
4683
+ });
4684
+ checkout.on("request_submit", () => {
4685
+ void handleSubmit();
4440
4686
  });
4441
4687
  return () => {
4442
- cancelled = true;
4688
+ activeCheckoutRef.current?.abort();
4689
+ activeCheckoutRef.current = null;
4690
+ elements.destroy();
4691
+ elementsRef.current = null;
4443
4692
  };
4444
- }, [resolvedClient, isDemoMode]);
4445
- const contextValue = React2.useMemo(
4446
- () => ({
4447
- client: resolvedClient,
4448
- business,
4449
- currency: business?.default_currency || DEFAULT_CURRENCY,
4450
- country: business?.country_code || DEFAULT_COUNTRY,
4451
- locations,
4452
- currentLocation,
4453
- setCurrentLocation,
4454
- isReady,
4455
- isDemoMode
4456
- }),
4457
- [
4458
- resolvedClient,
4459
- business,
4460
- locations,
4461
- currentLocation,
4462
- setCurrentLocation,
4463
- isReady,
4464
- isDemoMode
4465
- ]
4466
- );
4467
- return /* @__PURE__ */ jsxRuntime.jsx(CimplifyContext.Provider, { value: contextValue, children });
4468
- }
4469
- function useCimplify() {
4470
- const context = React2.useContext(CimplifyContext);
4471
- if (!context) {
4472
- throw new Error("useCimplify must be used within CimplifyProvider");
4693
+ }, [client, resolvedBusinessId, isDemoCheckout]);
4694
+ React3.useEffect(() => {
4695
+ if (!resolvedCart || !elementsRef.current) return;
4696
+ const checkoutElement = elementsRef.current.getElement("checkout");
4697
+ if (checkoutElement) {
4698
+ checkoutElement.setCart(transformToCheckoutCart(resolvedCart, fxOptions));
4699
+ }
4700
+ }, [resolvedCart, fxOptions]);
4701
+ const colors = shellColors(isDark ?? false, primaryColor);
4702
+ if (isInitializing) {
4703
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { fontSize: 13, color: colors.textSecondary }, children: "Preparing checkout..." }) });
4473
4704
  }
4474
- return context;
4705
+ if (!isDemoCheckout && (!resolvedBusinessId || !resolvedCartId)) {
4706
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { fontSize: 13, color: colors.error }, children: errorMessage || "Unable to initialize checkout. Please refresh and try again." }) });
4707
+ }
4708
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, "data-cimplify-checkout": "", children: [
4709
+ isTestMode && !isDemoCheckout && /* @__PURE__ */ jsxRuntime.jsx(
4710
+ "p",
4711
+ {
4712
+ "data-cimplify-test-mode": "",
4713
+ style: {
4714
+ marginBottom: "10px",
4715
+ fontSize: "12px",
4716
+ fontWeight: 600,
4717
+ color: "#92400e"
4718
+ },
4719
+ children: "Test mode - no real charges"
4720
+ }
4721
+ ),
4722
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-section": "checkout", children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: isDemoCheckout ? void 0 : checkoutMountRef }) }),
4723
+ status && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-status": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.textSecondary }, children: statusText || statusToLabel(status) }),
4724
+ errorMessage && /* @__PURE__ */ jsxRuntime.jsx("p", { "data-cimplify-error": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.error }, children: errorMessage })
4725
+ ] });
4475
4726
  }
4476
- function useOptionalCimplify() {
4477
- return React2.useContext(CimplifyContext);
4727
+ function Price({ amount, className, prefix }) {
4728
+ const { displayCurrency, convertPrice } = useCimplify();
4729
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className, children: [
4730
+ prefix,
4731
+ formatPrice(convertPrice(amount), displayCurrency)
4732
+ ] });
4478
4733
  }
4479
4734
  var productsCache = /* @__PURE__ */ new Map();
4480
4735
  var productsInflight = /* @__PURE__ */ new Map();
@@ -4493,9 +4748,9 @@ function useProducts(options = {}) {
4493
4748
  }
4494
4749
  const enabled = options.enabled ?? true;
4495
4750
  const locationId = client.getLocationId();
4496
- const previousLocationIdRef = React2.useRef(locationId);
4497
- const requestIdRef = React2.useRef(0);
4498
- const queryOptions = React2.useMemo(
4751
+ const previousLocationIdRef = React3.useRef(locationId);
4752
+ const requestIdRef = React3.useRef(0);
4753
+ const queryOptions = React3.useMemo(
4499
4754
  () => ({
4500
4755
  category: options.category,
4501
4756
  collection: options.collection,
@@ -4505,25 +4760,25 @@ function useProducts(options = {}) {
4505
4760
  }),
4506
4761
  [options.category, options.collection, options.featured, options.limit, options.search]
4507
4762
  );
4508
- const cacheKey = React2.useMemo(
4763
+ const cacheKey = React3.useMemo(
4509
4764
  () => buildProductsCacheKey(client, locationId, queryOptions),
4510
4765
  [client, locationId, queryOptions]
4511
4766
  );
4512
4767
  const cached = productsCache.get(cacheKey);
4513
- const [products, setProducts] = React2.useState(cached?.products ?? []);
4514
- const [isComplete, setIsComplete] = React2.useState(cached?.is_complete ?? true);
4515
- const [totalAvailable, setTotalAvailable] = React2.useState(cached?.total_available);
4516
- const [pagination, setPagination] = React2.useState(cached?.pagination);
4517
- const [isLoading, setIsLoading] = React2.useState(enabled && !cached);
4518
- const [error, setError] = React2.useState(null);
4519
- React2.useEffect(() => {
4768
+ const [products, setProducts] = React3.useState(cached?.products ?? []);
4769
+ const [isComplete, setIsComplete] = React3.useState(cached?.is_complete ?? true);
4770
+ const [totalAvailable, setTotalAvailable] = React3.useState(cached?.total_available);
4771
+ const [pagination, setPagination] = React3.useState(cached?.pagination);
4772
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4773
+ const [error, setError] = React3.useState(null);
4774
+ React3.useEffect(() => {
4520
4775
  if (previousLocationIdRef.current !== locationId) {
4521
4776
  productsCache.clear();
4522
4777
  productsInflight.clear();
4523
4778
  previousLocationIdRef.current = locationId;
4524
4779
  }
4525
4780
  }, [locationId]);
4526
- const load = React2.useCallback(
4781
+ const load = React3.useCallback(
4527
4782
  async (force = false) => {
4528
4783
  if (!enabled) {
4529
4784
  setIsLoading(false);
@@ -4586,10 +4841,10 @@ function useProducts(options = {}) {
4586
4841
  },
4587
4842
  [cacheKey, client, enabled, queryOptions]
4588
4843
  );
4589
- React2.useEffect(() => {
4844
+ React3.useEffect(() => {
4590
4845
  void load(false);
4591
4846
  }, [load]);
4592
- const refetch = React2.useCallback(async () => {
4847
+ const refetch = React3.useCallback(async () => {
4593
4848
  productsCache.delete(cacheKey);
4594
4849
  await load(true);
4595
4850
  }, [cacheKey, load]);
@@ -4623,27 +4878,27 @@ function useProduct(slugOrId, options = {}) {
4623
4878
  }
4624
4879
  const enabled = options.enabled ?? true;
4625
4880
  const locationId = client.getLocationId();
4626
- const previousLocationIdRef = React2.useRef(locationId);
4627
- const requestIdRef = React2.useRef(0);
4628
- const normalizedSlugOrId = React2.useMemo(() => (slugOrId || "").trim(), [slugOrId]);
4629
- const cacheKey = React2.useMemo(
4881
+ const previousLocationIdRef = React3.useRef(locationId);
4882
+ const requestIdRef = React3.useRef(0);
4883
+ const normalizedSlugOrId = React3.useMemo(() => (slugOrId || "").trim(), [slugOrId]);
4884
+ const cacheKey = React3.useMemo(
4630
4885
  () => buildProductCacheKey(client, locationId, normalizedSlugOrId),
4631
4886
  [client, locationId, normalizedSlugOrId]
4632
4887
  );
4633
4888
  const cached = productCache.get(cacheKey);
4634
- const [product, setProduct] = React2.useState(cached?.product ?? null);
4635
- const [isLoading, setIsLoading] = React2.useState(
4889
+ const [product, setProduct] = React3.useState(cached?.product ?? null);
4890
+ const [isLoading, setIsLoading] = React3.useState(
4636
4891
  enabled && normalizedSlugOrId.length > 0 && !cached
4637
4892
  );
4638
- const [error, setError] = React2.useState(null);
4639
- React2.useEffect(() => {
4893
+ const [error, setError] = React3.useState(null);
4894
+ React3.useEffect(() => {
4640
4895
  if (previousLocationIdRef.current !== locationId) {
4641
4896
  productCache.clear();
4642
4897
  productInflight.clear();
4643
4898
  previousLocationIdRef.current = locationId;
4644
4899
  }
4645
4900
  }, [locationId]);
4646
- const load = React2.useCallback(
4901
+ const load = React3.useCallback(
4647
4902
  async (force = false) => {
4648
4903
  if (!enabled || normalizedSlugOrId.length === 0) {
4649
4904
  setProduct(null);
@@ -4696,10 +4951,10 @@ function useProduct(slugOrId, options = {}) {
4696
4951
  },
4697
4952
  [cacheKey, client, enabled, normalizedSlugOrId]
4698
4953
  );
4699
- React2.useEffect(() => {
4954
+ React3.useEffect(() => {
4700
4955
  void load(false);
4701
4956
  }, [load]);
4702
- const refetch = React2.useCallback(async () => {
4957
+ const refetch = React3.useCallback(async () => {
4703
4958
  productCache.delete(cacheKey);
4704
4959
  await load(true);
4705
4960
  }, [cacheKey, load]);
@@ -4717,12 +4972,12 @@ function useCategories(options = {}) {
4717
4972
  throw new Error("useCategories must be used within CimplifyProvider or passed { client }.");
4718
4973
  }
4719
4974
  const enabled = options.enabled ?? true;
4720
- const cacheKey = React2.useMemo(() => buildCategoriesCacheKey(client), [client]);
4975
+ const cacheKey = React3.useMemo(() => buildCategoriesCacheKey(client), [client]);
4721
4976
  const cached = categoriesCache.get(cacheKey);
4722
- const [categories, setCategories] = React2.useState(cached ?? []);
4723
- const [isLoading, setIsLoading] = React2.useState(enabled && !cached);
4724
- const [error, setError] = React2.useState(null);
4725
- const load = React2.useCallback(
4977
+ const [categories, setCategories] = React3.useState(cached ?? []);
4978
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
4979
+ const [error, setError] = React3.useState(null);
4980
+ const load = React3.useCallback(
4726
4981
  async (force = false) => {
4727
4982
  if (!enabled) {
4728
4983
  setIsLoading(false);
@@ -4766,10 +5021,10 @@ function useCategories(options = {}) {
4766
5021
  },
4767
5022
  [cacheKey, client, enabled]
4768
5023
  );
4769
- React2.useEffect(() => {
5024
+ React3.useEffect(() => {
4770
5025
  void load(false);
4771
5026
  }, [load]);
4772
- const refetch = React2.useCallback(async () => {
5027
+ const refetch = React3.useCallback(async () => {
4773
5028
  categoriesCache.delete(cacheKey);
4774
5029
  await load(true);
4775
5030
  }, [cacheKey, load]);
@@ -5290,7 +5545,7 @@ function useCart(options = {}) {
5290
5545
  const locationId = options.locationId ?? client.getLocationId();
5291
5546
  const isDemoMode = options.demoMode ?? context?.isDemoMode ?? client.getPublicKey().trim().length === 0;
5292
5547
  const currency = options.currency ?? context?.currency ?? "USD";
5293
- const store = React2.useMemo(
5548
+ const store = React3.useMemo(
5294
5549
  () => getOrCreateStore({
5295
5550
  client,
5296
5551
  locationId,
@@ -5299,43 +5554,43 @@ function useCart(options = {}) {
5299
5554
  }),
5300
5555
  [client, currency, isDemoMode, locationId]
5301
5556
  );
5302
- const snapshot = React2.useSyncExternalStore(
5557
+ const snapshot = React3.useSyncExternalStore(
5303
5558
  store.subscribe,
5304
5559
  store.getSnapshot,
5305
5560
  store.getSnapshot
5306
5561
  );
5307
- React2.useEffect(() => {
5562
+ React3.useEffect(() => {
5308
5563
  void store.initialize();
5309
5564
  }, [store]);
5310
- const addItem = React2.useCallback(
5565
+ const addItem = React3.useCallback(
5311
5566
  async (product, quantity, addOptions) => {
5312
5567
  await store.addItem(product, quantity, addOptions);
5313
5568
  },
5314
5569
  [store]
5315
5570
  );
5316
- const removeItem = React2.useCallback(
5571
+ const removeItem = React3.useCallback(
5317
5572
  async (itemId) => {
5318
5573
  await store.removeItem(itemId);
5319
5574
  },
5320
5575
  [store]
5321
5576
  );
5322
- const updateQuantity = React2.useCallback(
5577
+ const updateQuantity = React3.useCallback(
5323
5578
  async (itemId, quantity) => {
5324
5579
  await store.updateQuantity(itemId, quantity);
5325
5580
  },
5326
5581
  [store]
5327
5582
  );
5328
- const clearCart = React2.useCallback(async () => {
5583
+ const clearCart = React3.useCallback(async () => {
5329
5584
  await store.clearCart();
5330
5585
  }, [store]);
5331
- const sync = React2.useCallback(async () => {
5586
+ const sync = React3.useCallback(async () => {
5332
5587
  try {
5333
5588
  await store.sync();
5334
5589
  } catch (syncError) {
5335
5590
  throw syncError;
5336
5591
  }
5337
5592
  }, [store]);
5338
- const itemCount = React2.useMemo(
5593
+ const itemCount = React3.useMemo(
5339
5594
  () => snapshot.items.reduce((sum, item) => sum + item.quantity, 0),
5340
5595
  [snapshot.items]
5341
5596
  );
@@ -5366,22 +5621,22 @@ function useOrder(orderId, options = {}) {
5366
5621
  if (!client) {
5367
5622
  throw new Error("useOrder must be used within CimplifyProvider or passed { client }.");
5368
5623
  }
5369
- const normalizedOrderId = React2.useMemo(() => (orderId || "").trim(), [orderId]);
5624
+ const normalizedOrderId = React3.useMemo(() => (orderId || "").trim(), [orderId]);
5370
5625
  const enabled = options.enabled ?? true;
5371
5626
  const poll = options.poll ?? false;
5372
5627
  const pollInterval = options.pollInterval ?? 5e3;
5373
- const requestIdRef = React2.useRef(0);
5374
- const cacheKey = React2.useMemo(
5628
+ const requestIdRef = React3.useRef(0);
5629
+ const cacheKey = React3.useMemo(
5375
5630
  () => buildOrderCacheKey(client, normalizedOrderId),
5376
5631
  [client, normalizedOrderId]
5377
5632
  );
5378
5633
  const cached = orderCache.get(cacheKey);
5379
- const [order, setOrder] = React2.useState(cached?.order ?? null);
5380
- const [isLoading, setIsLoading] = React2.useState(
5634
+ const [order, setOrder] = React3.useState(cached?.order ?? null);
5635
+ const [isLoading, setIsLoading] = React3.useState(
5381
5636
  enabled && normalizedOrderId.length > 0 && !cached
5382
5637
  );
5383
- const [error, setError] = React2.useState(null);
5384
- const load = React2.useCallback(
5638
+ const [error, setError] = React3.useState(null);
5639
+ const load = React3.useCallback(
5385
5640
  async (force = false) => {
5386
5641
  if (!enabled || normalizedOrderId.length === 0) {
5387
5642
  setOrder(null);
@@ -5434,10 +5689,10 @@ function useOrder(orderId, options = {}) {
5434
5689
  },
5435
5690
  [cacheKey, client, enabled, normalizedOrderId]
5436
5691
  );
5437
- React2.useEffect(() => {
5692
+ React3.useEffect(() => {
5438
5693
  void load(false);
5439
5694
  }, [load]);
5440
- React2.useEffect(() => {
5695
+ React3.useEffect(() => {
5441
5696
  if (!poll || !enabled || normalizedOrderId.length === 0) {
5442
5697
  return;
5443
5698
  }
@@ -5448,7 +5703,7 @@ function useOrder(orderId, options = {}) {
5448
5703
  window.clearInterval(timer);
5449
5704
  };
5450
5705
  }, [enabled, load, normalizedOrderId.length, poll, pollInterval]);
5451
- const refetch = React2.useCallback(async () => {
5706
+ const refetch = React3.useCallback(async () => {
5452
5707
  orderCache.delete(cacheKey);
5453
5708
  await load(true);
5454
5709
  }, [cacheKey, load]);
@@ -5499,10 +5754,10 @@ function useLocations(options = {}) {
5499
5754
  };
5500
5755
  }
5501
5756
  const client = options.client;
5502
- const [locations, setLocations] = React2.useState([]);
5503
- const [currentLocation, setCurrentLocationState] = React2.useState(null);
5504
- const [isLoading, setIsLoading] = React2.useState(true);
5505
- const setCurrentLocation = React2.useCallback(
5757
+ const [locations, setLocations] = React3.useState([]);
5758
+ const [currentLocation, setCurrentLocationState] = React3.useState(null);
5759
+ const [isLoading, setIsLoading] = React3.useState(true);
5760
+ const setCurrentLocation = React3.useCallback(
5506
5761
  (location) => {
5507
5762
  setCurrentLocationState(location);
5508
5763
  if (client) {
@@ -5512,7 +5767,7 @@ function useLocations(options = {}) {
5512
5767
  },
5513
5768
  [client]
5514
5769
  );
5515
- React2.useEffect(() => {
5770
+ React3.useEffect(() => {
5516
5771
  if (!client) {
5517
5772
  setLocations([]);
5518
5773
  setCurrentLocationState(null);
@@ -5570,24 +5825,24 @@ function useCollections(options = {}) {
5570
5825
  }
5571
5826
  const enabled = options.enabled ?? true;
5572
5827
  const locationId = client.getLocationId();
5573
- const previousLocationIdRef = React2.useRef(locationId);
5574
- const requestIdRef = React2.useRef(0);
5575
- const cacheKey = React2.useMemo(
5828
+ const previousLocationIdRef = React3.useRef(locationId);
5829
+ const requestIdRef = React3.useRef(0);
5830
+ const cacheKey = React3.useMemo(
5576
5831
  () => buildCollectionsCacheKey(client, locationId),
5577
5832
  [client, locationId]
5578
5833
  );
5579
5834
  const cached = collectionsCache.get(cacheKey);
5580
- const [collections, setCollections] = React2.useState(cached?.collections ?? []);
5581
- const [isLoading, setIsLoading] = React2.useState(enabled && !cached);
5582
- const [error, setError] = React2.useState(null);
5583
- React2.useEffect(() => {
5835
+ const [collections, setCollections] = React3.useState(cached?.collections ?? []);
5836
+ const [isLoading, setIsLoading] = React3.useState(enabled && !cached);
5837
+ const [error, setError] = React3.useState(null);
5838
+ React3.useEffect(() => {
5584
5839
  if (previousLocationIdRef.current !== locationId) {
5585
5840
  collectionsCache.clear();
5586
5841
  collectionsInflight.clear();
5587
5842
  previousLocationIdRef.current = locationId;
5588
5843
  }
5589
5844
  }, [locationId]);
5590
- const load = React2.useCallback(
5845
+ const load = React3.useCallback(
5591
5846
  async (force = false) => {
5592
5847
  if (!enabled) {
5593
5848
  setIsLoading(false);
@@ -5637,10 +5892,10 @@ function useCollections(options = {}) {
5637
5892
  },
5638
5893
  [cacheKey, client, enabled]
5639
5894
  );
5640
- React2.useEffect(() => {
5895
+ React3.useEffect(() => {
5641
5896
  void load(false);
5642
5897
  }, [load]);
5643
- const refetch = React2.useCallback(async () => {
5898
+ const refetch = React3.useCallback(async () => {
5644
5899
  collectionsCache.delete(cacheKey);
5645
5900
  await load(true);
5646
5901
  }, [cacheKey, load]);
@@ -5666,28 +5921,28 @@ function useCollection(idOrSlug, options = {}) {
5666
5921
  }
5667
5922
  const enabled = options.enabled ?? true;
5668
5923
  const locationId = client.getLocationId();
5669
- const previousLocationIdRef = React2.useRef(locationId);
5670
- const requestIdRef = React2.useRef(0);
5671
- const normalizedIdOrSlug = React2.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
5672
- const cacheKey = React2.useMemo(
5924
+ const previousLocationIdRef = React3.useRef(locationId);
5925
+ const requestIdRef = React3.useRef(0);
5926
+ const normalizedIdOrSlug = React3.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
5927
+ const cacheKey = React3.useMemo(
5673
5928
  () => buildCollectionCacheKey(client, locationId, normalizedIdOrSlug),
5674
5929
  [client, locationId, normalizedIdOrSlug]
5675
5930
  );
5676
5931
  const cached = collectionCache.get(cacheKey);
5677
- const [collection, setCollection] = React2.useState(cached?.collection ?? null);
5678
- const [products, setProducts] = React2.useState(cached?.products ?? []);
5679
- const [isLoading, setIsLoading] = React2.useState(
5932
+ const [collection, setCollection] = React3.useState(cached?.collection ?? null);
5933
+ const [products, setProducts] = React3.useState(cached?.products ?? []);
5934
+ const [isLoading, setIsLoading] = React3.useState(
5680
5935
  enabled && normalizedIdOrSlug.length > 0 && !cached
5681
5936
  );
5682
- const [error, setError] = React2.useState(null);
5683
- React2.useEffect(() => {
5937
+ const [error, setError] = React3.useState(null);
5938
+ React3.useEffect(() => {
5684
5939
  if (previousLocationIdRef.current !== locationId) {
5685
5940
  collectionCache.clear();
5686
5941
  collectionInflight.clear();
5687
5942
  previousLocationIdRef.current = locationId;
5688
5943
  }
5689
5944
  }, [locationId]);
5690
- const load = React2.useCallback(
5945
+ const load = React3.useCallback(
5691
5946
  async (force = false) => {
5692
5947
  if (!enabled || normalizedIdOrSlug.length === 0) {
5693
5948
  setCollection(null);
@@ -5750,10 +6005,10 @@ function useCollection(idOrSlug, options = {}) {
5750
6005
  },
5751
6006
  [cacheKey, client, enabled, normalizedIdOrSlug]
5752
6007
  );
5753
- React2.useEffect(() => {
6008
+ React3.useEffect(() => {
5754
6009
  void load(false);
5755
6010
  }, [load]);
5756
- const refetch = React2.useCallback(async () => {
6011
+ const refetch = React3.useCallback(async () => {
5757
6012
  collectionCache.delete(cacheKey);
5758
6013
  await load(true);
5759
6014
  }, [cacheKey, load]);
@@ -5779,27 +6034,27 @@ function useBundle(idOrSlug, options = {}) {
5779
6034
  }
5780
6035
  const enabled = options.enabled ?? true;
5781
6036
  const locationId = client.getLocationId();
5782
- const previousLocationIdRef = React2.useRef(locationId);
5783
- const requestIdRef = React2.useRef(0);
5784
- const normalizedIdOrSlug = React2.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
5785
- const cacheKey = React2.useMemo(
6037
+ const previousLocationIdRef = React3.useRef(locationId);
6038
+ const requestIdRef = React3.useRef(0);
6039
+ const normalizedIdOrSlug = React3.useMemo(() => (idOrSlug || "").trim(), [idOrSlug]);
6040
+ const cacheKey = React3.useMemo(
5786
6041
  () => buildBundleCacheKey(client, locationId, normalizedIdOrSlug),
5787
6042
  [client, locationId, normalizedIdOrSlug]
5788
6043
  );
5789
6044
  const cached = bundleCache.get(cacheKey);
5790
- const [bundle, setBundle] = React2.useState(cached?.bundle ?? null);
5791
- const [isLoading, setIsLoading] = React2.useState(
6045
+ const [bundle, setBundle] = React3.useState(cached?.bundle ?? null);
6046
+ const [isLoading, setIsLoading] = React3.useState(
5792
6047
  enabled && normalizedIdOrSlug.length > 0 && !cached
5793
6048
  );
5794
- const [error, setError] = React2.useState(null);
5795
- React2.useEffect(() => {
6049
+ const [error, setError] = React3.useState(null);
6050
+ React3.useEffect(() => {
5796
6051
  if (previousLocationIdRef.current !== locationId) {
5797
6052
  bundleCache.clear();
5798
6053
  bundleInflight.clear();
5799
6054
  previousLocationIdRef.current = locationId;
5800
6055
  }
5801
6056
  }, [locationId]);
5802
- const load = React2.useCallback(
6057
+ const load = React3.useCallback(
5803
6058
  async (force = false) => {
5804
6059
  if (!enabled || normalizedIdOrSlug.length === 0) {
5805
6060
  setBundle(null);
@@ -5850,10 +6105,10 @@ function useBundle(idOrSlug, options = {}) {
5850
6105
  },
5851
6106
  [cacheKey, client, enabled, normalizedIdOrSlug]
5852
6107
  );
5853
- React2.useEffect(() => {
6108
+ React3.useEffect(() => {
5854
6109
  void load(false);
5855
6110
  }, [load]);
5856
- const refetch = React2.useCallback(async () => {
6111
+ const refetch = React3.useCallback(async () => {
5857
6112
  bundleCache.delete(cacheKey);
5858
6113
  await load(true);
5859
6114
  }, [cacheKey, load]);
@@ -5883,37 +6138,37 @@ function useComposite(idOrProductId, options = {}) {
5883
6138
  }
5884
6139
  const enabled = options.enabled ?? true;
5885
6140
  const locationId = client.getLocationId();
5886
- const previousLocationIdRef = React2.useRef(locationId);
5887
- const requestIdRef = React2.useRef(0);
5888
- const priceRequestIdRef = React2.useRef(0);
5889
- const normalizedIdOrProductId = React2.useMemo(
6141
+ const previousLocationIdRef = React3.useRef(locationId);
6142
+ const requestIdRef = React3.useRef(0);
6143
+ const priceRequestIdRef = React3.useRef(0);
6144
+ const normalizedIdOrProductId = React3.useMemo(
5890
6145
  () => (idOrProductId || "").trim(),
5891
6146
  [idOrProductId]
5892
6147
  );
5893
- const byProductId = React2.useMemo(
6148
+ const byProductId = React3.useMemo(
5894
6149
  () => shouldFetchByProductId(normalizedIdOrProductId, options.byProductId),
5895
6150
  [normalizedIdOrProductId, options.byProductId]
5896
6151
  );
5897
- const cacheKey = React2.useMemo(
6152
+ const cacheKey = React3.useMemo(
5898
6153
  () => buildCompositeCacheKey(client, locationId, normalizedIdOrProductId, byProductId),
5899
6154
  [byProductId, client, locationId, normalizedIdOrProductId]
5900
6155
  );
5901
6156
  const cached = compositeCache.get(cacheKey);
5902
- const [composite, setComposite] = React2.useState(cached?.composite ?? null);
5903
- const [isLoading, setIsLoading] = React2.useState(
6157
+ const [composite, setComposite] = React3.useState(cached?.composite ?? null);
6158
+ const [isLoading, setIsLoading] = React3.useState(
5904
6159
  enabled && normalizedIdOrProductId.length > 0 && !cached
5905
6160
  );
5906
- const [error, setError] = React2.useState(null);
5907
- const [priceResult, setPriceResult] = React2.useState(null);
5908
- const [isPriceLoading, setIsPriceLoading] = React2.useState(false);
5909
- React2.useEffect(() => {
6161
+ const [error, setError] = React3.useState(null);
6162
+ const [priceResult, setPriceResult] = React3.useState(null);
6163
+ const [isPriceLoading, setIsPriceLoading] = React3.useState(false);
6164
+ React3.useEffect(() => {
5910
6165
  if (previousLocationIdRef.current !== locationId) {
5911
6166
  compositeCache.clear();
5912
6167
  compositeInflight.clear();
5913
6168
  previousLocationIdRef.current = locationId;
5914
6169
  }
5915
6170
  }, [locationId]);
5916
- const load = React2.useCallback(
6171
+ const load = React3.useCallback(
5917
6172
  async (force = false) => {
5918
6173
  if (!enabled || normalizedIdOrProductId.length === 0) {
5919
6174
  setComposite(null);
@@ -5966,10 +6221,10 @@ function useComposite(idOrProductId, options = {}) {
5966
6221
  },
5967
6222
  [byProductId, cacheKey, client, enabled, normalizedIdOrProductId]
5968
6223
  );
5969
- React2.useEffect(() => {
6224
+ React3.useEffect(() => {
5970
6225
  void load(false);
5971
6226
  }, [load]);
5972
- const calculatePrice = React2.useCallback(
6227
+ const calculatePrice = React3.useCallback(
5973
6228
  async (selections, overrideLocationId) => {
5974
6229
  if (!composite) {
5975
6230
  return null;
@@ -6003,7 +6258,7 @@ function useComposite(idOrProductId, options = {}) {
6003
6258
  },
6004
6259
  [client, composite]
6005
6260
  );
6006
- const refetch = React2.useCallback(async () => {
6261
+ const refetch = React3.useCallback(async () => {
6007
6262
  compositeCache.delete(cacheKey);
6008
6263
  await load(true);
6009
6264
  }, [cacheKey, load]);
@@ -6018,13 +6273,13 @@ function useSearch(options = {}) {
6018
6273
  const minLength = Math.max(0, options.minLength ?? 2);
6019
6274
  const debounceMs = Math.max(0, options.debounceMs ?? 300);
6020
6275
  const limit = Math.max(1, options.limit ?? 20);
6021
- const [query, setQueryState] = React2.useState("");
6022
- const [results, setResults] = React2.useState([]);
6023
- const [isLoading, setIsLoading] = React2.useState(false);
6024
- const [error, setError] = React2.useState(null);
6025
- const requestIdRef = React2.useRef(0);
6026
- const timerRef = React2.useRef(null);
6027
- React2.useEffect(() => {
6276
+ const [query, setQueryState] = React3.useState("");
6277
+ const [results, setResults] = React3.useState([]);
6278
+ const [isLoading, setIsLoading] = React3.useState(false);
6279
+ const [error, setError] = React3.useState(null);
6280
+ const requestIdRef = React3.useRef(0);
6281
+ const timerRef = React3.useRef(null);
6282
+ React3.useEffect(() => {
6028
6283
  if (timerRef.current) {
6029
6284
  clearTimeout(timerRef.current);
6030
6285
  timerRef.current = null;
@@ -6071,10 +6326,10 @@ function useSearch(options = {}) {
6071
6326
  }
6072
6327
  };
6073
6328
  }, [client, debounceMs, limit, minLength, options.category, query]);
6074
- const setQuery = React2.useCallback((nextQuery) => {
6329
+ const setQuery = React3.useCallback((nextQuery) => {
6075
6330
  setQueryState(nextQuery);
6076
6331
  }, []);
6077
- const clear = React2.useCallback(() => {
6332
+ const clear = React3.useCallback(() => {
6078
6333
  requestIdRef.current += 1;
6079
6334
  if (timerRef.current) {
6080
6335
  clearTimeout(timerRef.current);
@@ -6130,28 +6385,28 @@ function useQuote(input, options = {}) {
6130
6385
  const autoRefresh = options.autoRefresh ?? true;
6131
6386
  const refreshBeforeExpiryMs = Math.max(0, options.refreshBeforeExpiryMs ?? 3e4);
6132
6387
  const locationId = client.getLocationId();
6133
- const requestIdRef = React2.useRef(0);
6134
- const refreshTimerRef = React2.useRef(null);
6135
- const expiryTimerRef = React2.useRef(null);
6136
- const inputSignature = React2.useMemo(() => JSON.stringify(input ?? null), [input]);
6137
- const normalizedInput = React2.useMemo(() => {
6388
+ const requestIdRef = React3.useRef(0);
6389
+ const refreshTimerRef = React3.useRef(null);
6390
+ const expiryTimerRef = React3.useRef(null);
6391
+ const inputSignature = React3.useMemo(() => JSON.stringify(input ?? null), [input]);
6392
+ const normalizedInput = React3.useMemo(() => {
6138
6393
  if (!input) {
6139
6394
  return null;
6140
6395
  }
6141
6396
  const normalized = normalizeInput(input, locationId);
6142
6397
  return normalized.product_id.length > 0 ? normalized : null;
6143
6398
  }, [inputSignature, locationId]);
6144
- const cacheKey = React2.useMemo(
6399
+ const cacheKey = React3.useMemo(
6145
6400
  () => buildQuoteCacheKey(client, locationId, inputSignature),
6146
6401
  [client, inputSignature, locationId]
6147
6402
  );
6148
6403
  const cached = quoteCache.get(cacheKey);
6149
- const [quote, setQuote] = React2.useState(cached?.quote ?? null);
6150
- const [isLoading, setIsLoading] = React2.useState(enabled && normalizedInput !== null && !cached);
6151
- const [error, setError] = React2.useState(null);
6152
- const [isExpired, setIsExpired] = React2.useState(isQuoteExpired(cached?.quote ?? null));
6153
- const [messages, setMessages] = React2.useState(cached?.quote?.ui_messages ?? []);
6154
- const load = React2.useCallback(
6404
+ const [quote, setQuote] = React3.useState(cached?.quote ?? null);
6405
+ const [isLoading, setIsLoading] = React3.useState(enabled && normalizedInput !== null && !cached);
6406
+ const [error, setError] = React3.useState(null);
6407
+ const [isExpired, setIsExpired] = React3.useState(isQuoteExpired(cached?.quote ?? null));
6408
+ const [messages, setMessages] = React3.useState(cached?.quote?.ui_messages ?? []);
6409
+ const load = React3.useCallback(
6155
6410
  async (force = false) => {
6156
6411
  if (!enabled || !normalizedInput) {
6157
6412
  setQuote(null);
@@ -6209,10 +6464,10 @@ function useQuote(input, options = {}) {
6209
6464
  },
6210
6465
  [cacheKey, client, enabled, normalizedInput]
6211
6466
  );
6212
- React2.useEffect(() => {
6467
+ React3.useEffect(() => {
6213
6468
  void load(false);
6214
6469
  }, [load]);
6215
- const refresh = React2.useCallback(async () => {
6470
+ const refresh = React3.useCallback(async () => {
6216
6471
  if (!enabled || !normalizedInput) {
6217
6472
  return;
6218
6473
  }
@@ -6249,7 +6504,7 @@ function useQuote(input, options = {}) {
6249
6504
  }
6250
6505
  }
6251
6506
  }, [cacheKey, client, enabled, load, normalizedInput, quote]);
6252
- React2.useEffect(() => {
6507
+ React3.useEffect(() => {
6253
6508
  if (expiryTimerRef.current) {
6254
6509
  clearTimeout(expiryTimerRef.current);
6255
6510
  expiryTimerRef.current = null;
@@ -6273,7 +6528,7 @@ function useQuote(input, options = {}) {
6273
6528
  }
6274
6529
  };
6275
6530
  }, [quote?.expires_at, quote?.quote_id]);
6276
- React2.useEffect(() => {
6531
+ React3.useEffect(() => {
6277
6532
  if (refreshTimerRef.current) {
6278
6533
  clearTimeout(refreshTimerRef.current);
6279
6534
  refreshTimerRef.current = null;
@@ -6298,15 +6553,15 @@ function useQuote(input, options = {}) {
6298
6553
  }, [autoRefresh, enabled, quote?.expires_at, quote?.quote_id, refresh, refreshBeforeExpiryMs]);
6299
6554
  return { quote, isLoading, error, refresh, isExpired, messages };
6300
6555
  }
6301
- var ElementsContext = React2.createContext({
6556
+ var ElementsContext = React3.createContext({
6302
6557
  elements: null,
6303
6558
  isReady: false
6304
6559
  });
6305
6560
  function useElements() {
6306
- return React2.useContext(ElementsContext).elements;
6561
+ return React3.useContext(ElementsContext).elements;
6307
6562
  }
6308
6563
  function useElementsReady() {
6309
- return React2.useContext(ElementsContext).isReady;
6564
+ return React3.useContext(ElementsContext).isReady;
6310
6565
  }
6311
6566
  function ElementsProvider({
6312
6567
  client,
@@ -6314,10 +6569,10 @@ function ElementsProvider({
6314
6569
  options,
6315
6570
  children
6316
6571
  }) {
6317
- const [elements, setElements] = React2.useState(null);
6318
- const [isReady, setIsReady] = React2.useState(false);
6319
- const initialOptionsRef = React2.useRef(options);
6320
- React2.useEffect(() => {
6572
+ const [elements, setElements] = React3.useState(null);
6573
+ const [isReady, setIsReady] = React3.useState(false);
6574
+ const initialOptionsRef = React3.useRef(options);
6575
+ React3.useEffect(() => {
6321
6576
  let cancelled = false;
6322
6577
  let instance = null;
6323
6578
  setIsReady(false);
@@ -6358,20 +6613,20 @@ function AuthElement({
6358
6613
  onRequiresOtp,
6359
6614
  onError
6360
6615
  }) {
6361
- const containerRef = React2.useRef(null);
6362
- const elementRef = React2.useRef(null);
6616
+ const containerRef = React3.useRef(null);
6617
+ const elementRef = React3.useRef(null);
6363
6618
  const elements = useElements();
6364
- const onReadyRef = React2.useRef(onReady);
6365
- const onAuthenticatedRef = React2.useRef(onAuthenticated);
6366
- const onRequiresOtpRef = React2.useRef(onRequiresOtp);
6367
- const onErrorRef = React2.useRef(onError);
6368
- React2.useEffect(() => {
6619
+ const onReadyRef = React3.useRef(onReady);
6620
+ const onAuthenticatedRef = React3.useRef(onAuthenticated);
6621
+ const onRequiresOtpRef = React3.useRef(onRequiresOtp);
6622
+ const onErrorRef = React3.useRef(onError);
6623
+ React3.useEffect(() => {
6369
6624
  onReadyRef.current = onReady;
6370
6625
  onAuthenticatedRef.current = onAuthenticated;
6371
6626
  onRequiresOtpRef.current = onRequiresOtp;
6372
6627
  onErrorRef.current = onError;
6373
6628
  }, [onReady, onAuthenticated, onRequiresOtp, onError]);
6374
- React2.useEffect(() => {
6629
+ React3.useEffect(() => {
6375
6630
  if (!elements || !containerRef.current) return;
6376
6631
  const element = elements.create(ELEMENT_TYPES.AUTH, { prefillEmail });
6377
6632
  elementRef.current = element;
@@ -6401,18 +6656,18 @@ function AddressElement({
6401
6656
  onChange,
6402
6657
  onError
6403
6658
  }) {
6404
- const containerRef = React2.useRef(null);
6405
- const elementRef = React2.useRef(null);
6659
+ const containerRef = React3.useRef(null);
6660
+ const elementRef = React3.useRef(null);
6406
6661
  const elements = useElements();
6407
- const onReadyRef = React2.useRef(onReady);
6408
- const onChangeRef = React2.useRef(onChange);
6409
- const onErrorRef = React2.useRef(onError);
6410
- React2.useEffect(() => {
6662
+ const onReadyRef = React3.useRef(onReady);
6663
+ const onChangeRef = React3.useRef(onChange);
6664
+ const onErrorRef = React3.useRef(onError);
6665
+ React3.useEffect(() => {
6411
6666
  onReadyRef.current = onReady;
6412
6667
  onChangeRef.current = onChange;
6413
6668
  onErrorRef.current = onError;
6414
6669
  }, [onReady, onChange, onError]);
6415
- React2.useEffect(() => {
6670
+ React3.useEffect(() => {
6416
6671
  if (!elements || !containerRef.current) return;
6417
6672
  const element = elements.create(ELEMENT_TYPES.ADDRESS, { mode });
6418
6673
  elementRef.current = element;
@@ -6439,18 +6694,18 @@ function PaymentElement({
6439
6694
  onChange,
6440
6695
  onError
6441
6696
  }) {
6442
- const containerRef = React2.useRef(null);
6443
- const elementRef = React2.useRef(null);
6697
+ const containerRef = React3.useRef(null);
6698
+ const elementRef = React3.useRef(null);
6444
6699
  const elements = useElements();
6445
- const onReadyRef = React2.useRef(onReady);
6446
- const onChangeRef = React2.useRef(onChange);
6447
- const onErrorRef = React2.useRef(onError);
6448
- React2.useEffect(() => {
6700
+ const onReadyRef = React3.useRef(onReady);
6701
+ const onChangeRef = React3.useRef(onChange);
6702
+ const onErrorRef = React3.useRef(onError);
6703
+ React3.useEffect(() => {
6449
6704
  onReadyRef.current = onReady;
6450
6705
  onChangeRef.current = onChange;
6451
6706
  onErrorRef.current = onError;
6452
6707
  }, [onReady, onChange, onError]);
6453
- React2.useEffect(() => {
6708
+ React3.useEffect(() => {
6454
6709
  if (!elements || !containerRef.current) return;
6455
6710
  const element = elements.create(ELEMENT_TYPES.PAYMENT, { amount, currency });
6456
6711
  elementRef.current = element;
@@ -6470,8 +6725,8 @@ function PaymentElement({
6470
6725
  }
6471
6726
  function useCheckout() {
6472
6727
  const elements = useElements();
6473
- const [isLoading, setIsLoading] = React2.useState(false);
6474
- const submit = React2.useCallback(
6728
+ const [isLoading, setIsLoading] = React3.useState(false);
6729
+ const submit = React3.useCallback(
6475
6730
  async (data) => {
6476
6731
  if (!elements) {
6477
6732
  return { success: false, error: { code: "NO_ELEMENTS", message: "Elements not initialized" } };
@@ -6485,7 +6740,7 @@ function useCheckout() {
6485
6740
  },
6486
6741
  [elements]
6487
6742
  );
6488
- const process = React2.useCallback(
6743
+ const process = React3.useCallback(
6489
6744
  async (options) => {
6490
6745
  if (!elements) {
6491
6746
  return {
@@ -6513,6 +6768,7 @@ exports.CimplifyCheckout = CimplifyCheckout;
6513
6768
  exports.CimplifyProvider = CimplifyProvider;
6514
6769
  exports.ElementsProvider = ElementsProvider;
6515
6770
  exports.PaymentElement = PaymentElement;
6771
+ exports.Price = Price;
6516
6772
  exports.useAds = useAds;
6517
6773
  exports.useBundle = useBundle;
6518
6774
  exports.useCart = useCart;