@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/advanced.d.mts +2 -2
- package/dist/advanced.d.ts +2 -2
- package/dist/{client-6MsOWo8f.d.mts → client-D1rHAIZY.d.mts} +1 -1
- package/dist/{client-CVJ0S99a.d.ts → client-Dklt51q-.d.ts} +1 -1
- package/dist/{index-mrKi_VbR.d.mts → index-DKLWJwJd.d.mts} +1 -1
- package/dist/{index-B_JHO-ER.d.ts → index-DQp1xkcl.d.ts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +54 -0
- package/dist/index.mjs +54 -1
- package/dist/{payment-CLIWNMaP.d.mts → payment-BKjX2fAs.d.mts} +2 -1
- package/dist/{payment-CLIWNMaP.d.ts → payment-BKjX2fAs.d.ts} +2 -1
- package/dist/react.d.mts +29 -3
- package/dist/react.d.ts +29 -3
- package/dist/react.js +859 -603
- package/dist/react.mjs +681 -426
- package/dist/utils.d.mts +2 -2
- package/dist/utils.d.ts +2 -2
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React3, { createContext, useContext, useState, useEffect, useRef, useMemo, useCallback, useSyncExternalStore } from 'react';
|
|
2
2
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
// src/react/index.tsx
|
|
@@ -362,12 +362,13 @@ function getSelections(item) {
|
|
|
362
362
|
}
|
|
363
363
|
return void 0;
|
|
364
364
|
}
|
|
365
|
-
function mapItem(item) {
|
|
365
|
+
function mapItem(item, fx) {
|
|
366
|
+
const amt = (value) => fx ? String(fx.convertPrice(value)) : String(value);
|
|
366
367
|
const result = {
|
|
367
368
|
name: item.name,
|
|
368
369
|
quantity: item.quantity,
|
|
369
|
-
unit_price:
|
|
370
|
-
total_price:
|
|
370
|
+
unit_price: amt(item.base_price),
|
|
371
|
+
total_price: amt(item.total_price),
|
|
371
372
|
line_type: item.line_type
|
|
372
373
|
};
|
|
373
374
|
if (item.image_url) result.image_url = item.image_url;
|
|
@@ -380,7 +381,7 @@ function mapItem(item) {
|
|
|
380
381
|
if (item.add_on_options?.length) {
|
|
381
382
|
result.add_ons = item.add_on_options.map((opt) => ({
|
|
382
383
|
name: opt.name,
|
|
383
|
-
price:
|
|
384
|
+
price: amt(opt.price ?? "0")
|
|
384
385
|
}));
|
|
385
386
|
}
|
|
386
387
|
if (item.special_instructions) {
|
|
@@ -388,359 +389,18 @@ function mapItem(item) {
|
|
|
388
389
|
}
|
|
389
390
|
return result;
|
|
390
391
|
}
|
|
391
|
-
function transformToCheckoutCart(cart) {
|
|
392
|
+
function transformToCheckoutCart(cart, fx) {
|
|
393
|
+
const amt = (value) => fx ? String(fx.convertPrice(value)) : String(value);
|
|
392
394
|
return {
|
|
393
|
-
items: cart.items.map(mapItem),
|
|
394
|
-
subtotal:
|
|
395
|
-
tax_amount:
|
|
396
|
-
total_discounts:
|
|
397
|
-
service_charge:
|
|
398
|
-
total:
|
|
399
|
-
currency: cart.pricing.currency
|
|
395
|
+
items: cart.items.map((item) => mapItem(item, fx)),
|
|
396
|
+
subtotal: amt(cart.pricing.subtotal),
|
|
397
|
+
tax_amount: amt(cart.pricing.tax_amount),
|
|
398
|
+
total_discounts: amt(cart.pricing.total_discounts),
|
|
399
|
+
service_charge: amt(cart.pricing.service_charge),
|
|
400
|
+
total: amt(cart.pricing.total_price),
|
|
401
|
+
currency: fx?.displayCurrency ?? cart.pricing.currency
|
|
400
402
|
};
|
|
401
403
|
}
|
|
402
|
-
var SPACE = { sm: 8};
|
|
403
|
-
function shellColors(isDark, primaryColor) {
|
|
404
|
-
return {
|
|
405
|
-
text: isDark ? "#f4f4f5" : "#1a1a1a",
|
|
406
|
-
textSecondary: isDark ? "#a1a1aa" : "#52525b",
|
|
407
|
-
textMuted: isDark ? "#71717a" : "#a1a1aa",
|
|
408
|
-
border: isDark ? "#27272a" : "#e4e4e7",
|
|
409
|
-
surface: isDark ? "#18181b" : "#fafafa",
|
|
410
|
-
error: "#dc2626",
|
|
411
|
-
primary: primaryColor
|
|
412
|
-
};
|
|
413
|
-
}
|
|
414
|
-
function statusToLabel(status) {
|
|
415
|
-
if (!status) {
|
|
416
|
-
return "";
|
|
417
|
-
}
|
|
418
|
-
if (status === "preparing") {
|
|
419
|
-
return "Preparing checkout";
|
|
420
|
-
}
|
|
421
|
-
if (status === "recovering") {
|
|
422
|
-
return "Resuming payment";
|
|
423
|
-
}
|
|
424
|
-
if (status === "processing") {
|
|
425
|
-
return "Processing payment";
|
|
426
|
-
}
|
|
427
|
-
if (status === "awaiting_authorization") {
|
|
428
|
-
return "Waiting for authorization";
|
|
429
|
-
}
|
|
430
|
-
if (status === "polling") {
|
|
431
|
-
return "Confirming payment";
|
|
432
|
-
}
|
|
433
|
-
if (status === "finalizing") {
|
|
434
|
-
return "Finalizing order";
|
|
435
|
-
}
|
|
436
|
-
if (status === "success") {
|
|
437
|
-
return "Payment complete";
|
|
438
|
-
}
|
|
439
|
-
return "Payment failed";
|
|
440
|
-
}
|
|
441
|
-
function CimplifyCheckout({
|
|
442
|
-
client,
|
|
443
|
-
businessId,
|
|
444
|
-
cartId,
|
|
445
|
-
locationId,
|
|
446
|
-
linkUrl,
|
|
447
|
-
orderTypes,
|
|
448
|
-
enrollInLink = true,
|
|
449
|
-
onComplete,
|
|
450
|
-
onError,
|
|
451
|
-
onStatusChange,
|
|
452
|
-
appearance,
|
|
453
|
-
demoMode,
|
|
454
|
-
className
|
|
455
|
-
}) {
|
|
456
|
-
const resolvedOrderTypes = useMemo(
|
|
457
|
-
() => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
|
|
458
|
-
[orderTypes]
|
|
459
|
-
);
|
|
460
|
-
const [orderType, setOrderType] = useState(resolvedOrderTypes[0] || "pickup");
|
|
461
|
-
const [status, setStatus] = useState(null);
|
|
462
|
-
const [statusText, setStatusText] = useState("");
|
|
463
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
464
|
-
const [isInitializing, setIsInitializing] = useState(false);
|
|
465
|
-
const [errorMessage, setErrorMessage] = useState(null);
|
|
466
|
-
const [resolvedBusinessId, setResolvedBusinessId] = useState(businessId ?? null);
|
|
467
|
-
const [resolvedCartId, setResolvedCartId] = useState(cartId ?? null);
|
|
468
|
-
const [resolvedCart, setResolvedCart] = useState(null);
|
|
469
|
-
const checkoutMountRef = useRef(null);
|
|
470
|
-
const elementsRef = useRef(null);
|
|
471
|
-
const activeCheckoutRef = useRef(null);
|
|
472
|
-
const initialAppearanceRef = useRef(appearance);
|
|
473
|
-
const hasWarnedInlineAppearanceRef = useRef(false);
|
|
474
|
-
const isMountedRef = useRef(true);
|
|
475
|
-
const demoRunRef = useRef(0);
|
|
476
|
-
const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
|
|
477
|
-
const isTestMode = client.isTestMode();
|
|
478
|
-
const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
|
|
479
|
-
const isDark = appearance?.theme === "dark";
|
|
480
|
-
const emitStatus = React2.useEffectEvent(
|
|
481
|
-
(nextStatus, context = {}) => {
|
|
482
|
-
setStatus(nextStatus);
|
|
483
|
-
setStatusText(context.display_text || "");
|
|
484
|
-
onStatusChange?.(nextStatus, context);
|
|
485
|
-
}
|
|
486
|
-
);
|
|
487
|
-
const fireError = React2.useEffectEvent(
|
|
488
|
-
(error) => {
|
|
489
|
-
onError?.(error);
|
|
490
|
-
}
|
|
491
|
-
);
|
|
492
|
-
useEffect(() => {
|
|
493
|
-
if (!resolvedOrderTypes.includes(orderType)) {
|
|
494
|
-
setOrderType(resolvedOrderTypes[0] || "pickup");
|
|
495
|
-
}
|
|
496
|
-
}, [resolvedOrderTypes, orderType]);
|
|
497
|
-
useEffect(() => {
|
|
498
|
-
if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
|
|
499
|
-
hasWarnedInlineAppearanceRef.current = true;
|
|
500
|
-
console.warn(
|
|
501
|
-
"[Cimplify] `appearance` prop reference changed after mount. Elements keep the initial appearance to avoid iframe remount. Memoize appearance with useMemo() to remove this warning."
|
|
502
|
-
);
|
|
503
|
-
}
|
|
504
|
-
}, [appearance]);
|
|
505
|
-
useEffect(() => {
|
|
506
|
-
let cancelled = false;
|
|
507
|
-
async function bootstrap() {
|
|
508
|
-
if (isDemoCheckout) {
|
|
509
|
-
if (!cancelled) {
|
|
510
|
-
setResolvedBusinessId(businessId ?? null);
|
|
511
|
-
setResolvedCartId(cartId ?? "cart_demo");
|
|
512
|
-
setIsInitializing(false);
|
|
513
|
-
setErrorMessage(null);
|
|
514
|
-
}
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
const needsBusinessResolve = !businessId;
|
|
518
|
-
const needsCartResolve = !cartId;
|
|
519
|
-
if (!needsBusinessResolve && !needsCartResolve) {
|
|
520
|
-
if (!cancelled) {
|
|
521
|
-
setResolvedBusinessId(businessId || null);
|
|
522
|
-
setResolvedCartId(cartId || null);
|
|
523
|
-
setIsInitializing(false);
|
|
524
|
-
setErrorMessage(null);
|
|
525
|
-
}
|
|
526
|
-
client.cart.get().then((cartResult) => {
|
|
527
|
-
if (!cancelled && cartResult.ok && cartResult.value) {
|
|
528
|
-
setResolvedCart(cartResult.value);
|
|
529
|
-
}
|
|
530
|
-
}).catch(() => {
|
|
531
|
-
});
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
if (!cancelled) {
|
|
535
|
-
setIsInitializing(true);
|
|
536
|
-
setErrorMessage(null);
|
|
537
|
-
}
|
|
538
|
-
let nextBusinessId = businessId ?? null;
|
|
539
|
-
if (!nextBusinessId) {
|
|
540
|
-
try {
|
|
541
|
-
nextBusinessId = await client.resolveBusinessId();
|
|
542
|
-
} catch {
|
|
543
|
-
if (!cancelled) {
|
|
544
|
-
const message = "Unable to initialize checkout business context.";
|
|
545
|
-
setResolvedBusinessId(null);
|
|
546
|
-
setResolvedCartId(null);
|
|
547
|
-
setErrorMessage(message);
|
|
548
|
-
setIsInitializing(false);
|
|
549
|
-
fireError({ code: "BUSINESS_ID_REQUIRED", message });
|
|
550
|
-
}
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
let nextCartId = cartId ?? null;
|
|
555
|
-
if (!nextCartId) {
|
|
556
|
-
const cartResult = await client.cart.get();
|
|
557
|
-
if (!cartResult.ok || !cartResult.value?.id || cartResult.value.items.length === 0) {
|
|
558
|
-
if (!cancelled) {
|
|
559
|
-
const message = "Your cart is empty. Add items before checkout.";
|
|
560
|
-
setResolvedBusinessId(nextBusinessId);
|
|
561
|
-
setResolvedCartId(null);
|
|
562
|
-
setErrorMessage(message);
|
|
563
|
-
setIsInitializing(false);
|
|
564
|
-
fireError({ code: "CART_EMPTY", message });
|
|
565
|
-
}
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
nextCartId = cartResult.value.id;
|
|
569
|
-
if (!cancelled) {
|
|
570
|
-
setResolvedCart(cartResult.value);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
if (!cancelled) {
|
|
574
|
-
setResolvedBusinessId(nextBusinessId);
|
|
575
|
-
setResolvedCartId(nextCartId);
|
|
576
|
-
setIsInitializing(false);
|
|
577
|
-
setErrorMessage(null);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
void bootstrap();
|
|
581
|
-
return () => {
|
|
582
|
-
cancelled = true;
|
|
583
|
-
};
|
|
584
|
-
}, [businessId, cartId, client, isDemoCheckout]);
|
|
585
|
-
useEffect(() => {
|
|
586
|
-
return () => {
|
|
587
|
-
isMountedRef.current = false;
|
|
588
|
-
demoRunRef.current += 1;
|
|
589
|
-
activeCheckoutRef.current?.abort();
|
|
590
|
-
activeCheckoutRef.current = null;
|
|
591
|
-
};
|
|
592
|
-
}, []);
|
|
593
|
-
const handleSubmit = React2.useEffectEvent(async () => {
|
|
594
|
-
if (isSubmitting || isInitializing || !resolvedCartId) {
|
|
595
|
-
if (!resolvedCartId && !isInitializing) {
|
|
596
|
-
const message = "Your cart is empty. Add items before checkout.";
|
|
597
|
-
setErrorMessage(message);
|
|
598
|
-
fireError({ code: "CART_EMPTY", message });
|
|
599
|
-
}
|
|
600
|
-
return;
|
|
601
|
-
}
|
|
602
|
-
setErrorMessage(null);
|
|
603
|
-
setIsSubmitting(true);
|
|
604
|
-
emitStatus("preparing", { display_text: statusToLabel("preparing") });
|
|
605
|
-
if (isDemoCheckout) {
|
|
606
|
-
const runId = demoRunRef.current + 1;
|
|
607
|
-
demoRunRef.current = runId;
|
|
608
|
-
const wait = async (ms) => {
|
|
609
|
-
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
610
|
-
return isMountedRef.current && runId === demoRunRef.current;
|
|
611
|
-
};
|
|
612
|
-
try {
|
|
613
|
-
if (!await wait(400)) return;
|
|
614
|
-
emitStatus("processing", { display_text: statusToLabel("processing") });
|
|
615
|
-
if (!await wait(900)) return;
|
|
616
|
-
emitStatus("polling", { display_text: statusToLabel("polling") });
|
|
617
|
-
if (!await wait(1200)) return;
|
|
618
|
-
const result = {
|
|
619
|
-
success: true,
|
|
620
|
-
order: {
|
|
621
|
-
id: `ord_demo_${Date.now()}`,
|
|
622
|
-
order_number: `DEMO-${Math.random().toString(36).slice(2, 8).toUpperCase()}`,
|
|
623
|
-
status: "confirmed",
|
|
624
|
-
total: "0.00",
|
|
625
|
-
currency: "USD"
|
|
626
|
-
}
|
|
627
|
-
};
|
|
628
|
-
emitStatus("success", {
|
|
629
|
-
order_id: result.order?.id,
|
|
630
|
-
order_number: result.order?.order_number,
|
|
631
|
-
display_text: statusToLabel("success")
|
|
632
|
-
});
|
|
633
|
-
onComplete(result);
|
|
634
|
-
} finally {
|
|
635
|
-
if (isMountedRef.current && runId === demoRunRef.current) {
|
|
636
|
-
setIsSubmitting(false);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
if (!elementsRef.current) {
|
|
642
|
-
const message = "Checkout is still initializing. Please try again.";
|
|
643
|
-
setErrorMessage(message);
|
|
644
|
-
fireError({ code: "CHECKOUT_NOT_READY", message });
|
|
645
|
-
setIsSubmitting(false);
|
|
646
|
-
return;
|
|
647
|
-
}
|
|
648
|
-
const checkout = elementsRef.current.processCheckout({
|
|
649
|
-
cart_id: resolvedCartId,
|
|
650
|
-
location_id: locationId ?? client.getLocationId() ?? void 0,
|
|
651
|
-
order_type: orderType,
|
|
652
|
-
enroll_in_link: enrollInLink,
|
|
653
|
-
on_status_change: emitStatus
|
|
654
|
-
});
|
|
655
|
-
activeCheckoutRef.current = checkout;
|
|
656
|
-
try {
|
|
657
|
-
const result = await checkout;
|
|
658
|
-
if (result.success) {
|
|
659
|
-
onComplete(result);
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
const code = result.error?.code || "CHECKOUT_FAILED";
|
|
663
|
-
const message = result.error?.message || "Payment failed.";
|
|
664
|
-
setErrorMessage(message);
|
|
665
|
-
fireError({ code, message });
|
|
666
|
-
} finally {
|
|
667
|
-
if (isMountedRef.current) {
|
|
668
|
-
activeCheckoutRef.current = null;
|
|
669
|
-
setIsSubmitting(false);
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
});
|
|
673
|
-
useEffect(() => {
|
|
674
|
-
if (isDemoCheckout || !resolvedBusinessId) {
|
|
675
|
-
elementsRef.current = null;
|
|
676
|
-
return;
|
|
677
|
-
}
|
|
678
|
-
const elements = client.elements(resolvedBusinessId, {
|
|
679
|
-
appearance: initialAppearanceRef.current,
|
|
680
|
-
linkUrl
|
|
681
|
-
});
|
|
682
|
-
elementsRef.current = elements;
|
|
683
|
-
const checkout = elements.create("checkout", {
|
|
684
|
-
orderTypes: resolvedOrderTypes,
|
|
685
|
-
defaultOrderType: resolvedOrderTypes[0]
|
|
686
|
-
});
|
|
687
|
-
if (checkoutMountRef.current) {
|
|
688
|
-
checkout.mount(checkoutMountRef.current);
|
|
689
|
-
}
|
|
690
|
-
checkout.on("ready", () => {
|
|
691
|
-
if (resolvedCart) {
|
|
692
|
-
checkout.setCart(transformToCheckoutCart(resolvedCart));
|
|
693
|
-
}
|
|
694
|
-
});
|
|
695
|
-
checkout.on("order_type_changed", (data) => {
|
|
696
|
-
const typed = data;
|
|
697
|
-
if (typed.orderType) {
|
|
698
|
-
setOrderType(typed.orderType);
|
|
699
|
-
}
|
|
700
|
-
});
|
|
701
|
-
checkout.on("request_submit", () => {
|
|
702
|
-
void handleSubmit();
|
|
703
|
-
});
|
|
704
|
-
return () => {
|
|
705
|
-
activeCheckoutRef.current?.abort();
|
|
706
|
-
activeCheckoutRef.current = null;
|
|
707
|
-
elements.destroy();
|
|
708
|
-
elementsRef.current = null;
|
|
709
|
-
};
|
|
710
|
-
}, [client, resolvedBusinessId, isDemoCheckout]);
|
|
711
|
-
useEffect(() => {
|
|
712
|
-
if (!resolvedCart || !elementsRef.current) return;
|
|
713
|
-
const checkoutElement = elementsRef.current.getElement("checkout");
|
|
714
|
-
if (checkoutElement) {
|
|
715
|
-
checkoutElement.setCart(transformToCheckoutCart(resolvedCart));
|
|
716
|
-
}
|
|
717
|
-
}, [resolvedCart]);
|
|
718
|
-
const colors = shellColors(isDark ?? false, primaryColor);
|
|
719
|
-
if (isInitializing) {
|
|
720
|
-
return /* @__PURE__ */ jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsx("p", { "data-cimplify-status": "", style: { fontSize: 13, color: colors.textSecondary }, children: "Preparing checkout..." }) });
|
|
721
|
-
}
|
|
722
|
-
if (!isDemoCheckout && (!resolvedBusinessId || !resolvedCartId)) {
|
|
723
|
-
return /* @__PURE__ */ jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsx("p", { "data-cimplify-error": "", style: { fontSize: 13, color: colors.error }, children: errorMessage || "Unable to initialize checkout. Please refresh and try again." }) });
|
|
724
|
-
}
|
|
725
|
-
return /* @__PURE__ */ jsxs("div", { className, "data-cimplify-checkout": "", children: [
|
|
726
|
-
isTestMode && !isDemoCheckout && /* @__PURE__ */ jsx(
|
|
727
|
-
"p",
|
|
728
|
-
{
|
|
729
|
-
"data-cimplify-test-mode": "",
|
|
730
|
-
style: {
|
|
731
|
-
marginBottom: "10px",
|
|
732
|
-
fontSize: "12px",
|
|
733
|
-
fontWeight: 600,
|
|
734
|
-
color: "#92400e"
|
|
735
|
-
},
|
|
736
|
-
children: "Test mode - no real charges"
|
|
737
|
-
}
|
|
738
|
-
),
|
|
739
|
-
/* @__PURE__ */ jsx("div", { "data-cimplify-section": "checkout", children: /* @__PURE__ */ jsx("div", { ref: isDemoCheckout ? void 0 : checkoutMountRef }) }),
|
|
740
|
-
status && /* @__PURE__ */ jsx("p", { "data-cimplify-status": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.textSecondary }, children: statusText || statusToLabel(status) }),
|
|
741
|
-
errorMessage && /* @__PURE__ */ jsx("p", { "data-cimplify-error": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.error }, children: errorMessage })
|
|
742
|
-
] });
|
|
743
|
-
}
|
|
744
404
|
|
|
745
405
|
// src/types/common.ts
|
|
746
406
|
function money(value) {
|
|
@@ -749,6 +409,59 @@ function money(value) {
|
|
|
749
409
|
function moneyFromNumber(value) {
|
|
750
410
|
return value.toFixed(2);
|
|
751
411
|
}
|
|
412
|
+
var SUPPORTED_CURRENCY_CODES = /* @__PURE__ */ new Set([
|
|
413
|
+
"USD",
|
|
414
|
+
"EUR",
|
|
415
|
+
"GBP",
|
|
416
|
+
"JPY",
|
|
417
|
+
"CNY",
|
|
418
|
+
"CHF",
|
|
419
|
+
"CAD",
|
|
420
|
+
"AUD",
|
|
421
|
+
"GHS",
|
|
422
|
+
"NGN",
|
|
423
|
+
"KES",
|
|
424
|
+
"ZAR",
|
|
425
|
+
"XOF",
|
|
426
|
+
"XAF",
|
|
427
|
+
"EGP",
|
|
428
|
+
"TZS",
|
|
429
|
+
"UGX",
|
|
430
|
+
"RWF",
|
|
431
|
+
"ETB",
|
|
432
|
+
"ZMW",
|
|
433
|
+
"BWP",
|
|
434
|
+
"MUR",
|
|
435
|
+
"NAD",
|
|
436
|
+
"MWK",
|
|
437
|
+
"AOA",
|
|
438
|
+
"CDF",
|
|
439
|
+
"GMD",
|
|
440
|
+
"GNF",
|
|
441
|
+
"LRD",
|
|
442
|
+
"SLL",
|
|
443
|
+
"MZN",
|
|
444
|
+
"BIF",
|
|
445
|
+
"INR",
|
|
446
|
+
"BRL",
|
|
447
|
+
"MXN",
|
|
448
|
+
"KRW",
|
|
449
|
+
"TRY",
|
|
450
|
+
"THB",
|
|
451
|
+
"MYR",
|
|
452
|
+
"PHP",
|
|
453
|
+
"IDR",
|
|
454
|
+
"VND",
|
|
455
|
+
"SGD",
|
|
456
|
+
"HKD",
|
|
457
|
+
"TWD",
|
|
458
|
+
"AED",
|
|
459
|
+
"SAR",
|
|
460
|
+
"ILS"
|
|
461
|
+
]);
|
|
462
|
+
function isSupportedCurrency(code) {
|
|
463
|
+
return SUPPORTED_CURRENCY_CODES.has(code);
|
|
464
|
+
}
|
|
752
465
|
function currencyCode(value) {
|
|
753
466
|
return value;
|
|
754
467
|
}
|
|
@@ -1354,6 +1067,97 @@ var MOBILE_MONEY_PROVIDER = {
|
|
|
1354
1067
|
};
|
|
1355
1068
|
|
|
1356
1069
|
// src/utils/price.ts
|
|
1070
|
+
var CURRENCY_SYMBOLS = {
|
|
1071
|
+
// Major world currencies
|
|
1072
|
+
USD: "$",
|
|
1073
|
+
EUR: "\u20AC",
|
|
1074
|
+
GBP: "\xA3",
|
|
1075
|
+
JPY: "\xA5",
|
|
1076
|
+
CNY: "\xA5",
|
|
1077
|
+
CHF: "CHF",
|
|
1078
|
+
CAD: "C$",
|
|
1079
|
+
AUD: "A$",
|
|
1080
|
+
NZD: "NZ$",
|
|
1081
|
+
HKD: "HK$",
|
|
1082
|
+
SGD: "S$",
|
|
1083
|
+
INR: "\u20B9",
|
|
1084
|
+
BRL: "R$",
|
|
1085
|
+
MXN: "MX$",
|
|
1086
|
+
KRW: "\u20A9",
|
|
1087
|
+
RUB: "\u20BD",
|
|
1088
|
+
TRY: "\u20BA",
|
|
1089
|
+
THB: "\u0E3F",
|
|
1090
|
+
PLN: "z\u0142",
|
|
1091
|
+
SEK: "kr",
|
|
1092
|
+
NOK: "kr",
|
|
1093
|
+
DKK: "kr",
|
|
1094
|
+
CZK: "K\u010D",
|
|
1095
|
+
HUF: "Ft",
|
|
1096
|
+
ILS: "\u20AA",
|
|
1097
|
+
AED: "\u062F.\u0625",
|
|
1098
|
+
SAR: "\uFDFC",
|
|
1099
|
+
MYR: "RM",
|
|
1100
|
+
PHP: "\u20B1",
|
|
1101
|
+
IDR: "Rp",
|
|
1102
|
+
VND: "\u20AB",
|
|
1103
|
+
TWD: "NT$",
|
|
1104
|
+
// African currencies
|
|
1105
|
+
GHS: "GH\u20B5",
|
|
1106
|
+
NGN: "\u20A6",
|
|
1107
|
+
KES: "KSh",
|
|
1108
|
+
ZAR: "R",
|
|
1109
|
+
XOF: "CFA",
|
|
1110
|
+
XAF: "FCFA",
|
|
1111
|
+
EGP: "E\xA3",
|
|
1112
|
+
MAD: "MAD",
|
|
1113
|
+
TZS: "TSh",
|
|
1114
|
+
UGX: "USh",
|
|
1115
|
+
RWF: "FRw",
|
|
1116
|
+
ETB: "Br",
|
|
1117
|
+
ZMW: "ZK",
|
|
1118
|
+
BWP: "P",
|
|
1119
|
+
MUR: "\u20A8",
|
|
1120
|
+
SCR: "\u20A8",
|
|
1121
|
+
NAD: "N$",
|
|
1122
|
+
SZL: "E",
|
|
1123
|
+
LSL: "L",
|
|
1124
|
+
MWK: "MK",
|
|
1125
|
+
AOA: "Kz",
|
|
1126
|
+
CDF: "FC",
|
|
1127
|
+
GMD: "D",
|
|
1128
|
+
GNF: "FG",
|
|
1129
|
+
LRD: "L$",
|
|
1130
|
+
SLL: "Le",
|
|
1131
|
+
MZN: "MT",
|
|
1132
|
+
SDG: "SDG",
|
|
1133
|
+
SSP: "SSP",
|
|
1134
|
+
SOS: "Sh.So.",
|
|
1135
|
+
DJF: "Fdj",
|
|
1136
|
+
ERN: "Nfk",
|
|
1137
|
+
CVE: "$",
|
|
1138
|
+
STN: "Db",
|
|
1139
|
+
KMF: "CF",
|
|
1140
|
+
BIF: "FBu"
|
|
1141
|
+
};
|
|
1142
|
+
function getCurrencySymbol(currencyCode2) {
|
|
1143
|
+
return CURRENCY_SYMBOLS[currencyCode2.toUpperCase()] || currencyCode2;
|
|
1144
|
+
}
|
|
1145
|
+
function formatPrice(amount, currency = "GHS", locale = "en-US") {
|
|
1146
|
+
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
1147
|
+
if (isNaN(numAmount)) {
|
|
1148
|
+
return `${getCurrencySymbol(currency)}0.00`;
|
|
1149
|
+
}
|
|
1150
|
+
try {
|
|
1151
|
+
return new Intl.NumberFormat(locale, {
|
|
1152
|
+
style: "currency",
|
|
1153
|
+
currency: currency.toUpperCase(),
|
|
1154
|
+
minimumFractionDigits: 2,
|
|
1155
|
+
maximumFractionDigits: 2
|
|
1156
|
+
}).format(numAmount);
|
|
1157
|
+
} catch {
|
|
1158
|
+
return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1357
1161
|
function parsePrice(value) {
|
|
1358
1162
|
if (value === void 0 || value === null) {
|
|
1359
1163
|
return 0;
|
|
@@ -4314,6 +4118,8 @@ function createCimplifyClient(config = {}) {
|
|
|
4314
4118
|
return new CimplifyClient(config);
|
|
4315
4119
|
}
|
|
4316
4120
|
var LOCATION_STORAGE_KEY = "cimplify_location_id";
|
|
4121
|
+
var DISPLAY_CURRENCY_STORAGE_KEY = "cimplify_display_currency";
|
|
4122
|
+
var FX_REFRESH_INTERVAL = 12e4;
|
|
4317
4123
|
var DEFAULT_CURRENCY = "USD";
|
|
4318
4124
|
var DEFAULT_COUNTRY = "US";
|
|
4319
4125
|
function createDefaultClient() {
|
|
@@ -4342,6 +4148,27 @@ function setStoredLocationId(locationId) {
|
|
|
4342
4148
|
}
|
|
4343
4149
|
window.localStorage.setItem(LOCATION_STORAGE_KEY, locationId);
|
|
4344
4150
|
}
|
|
4151
|
+
function getStoredDisplayCurrency() {
|
|
4152
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4153
|
+
return null;
|
|
4154
|
+
}
|
|
4155
|
+
const value = window.localStorage.getItem(DISPLAY_CURRENCY_STORAGE_KEY);
|
|
4156
|
+
if (!value) {
|
|
4157
|
+
return null;
|
|
4158
|
+
}
|
|
4159
|
+
const normalized = value.trim().toUpperCase();
|
|
4160
|
+
return normalized.length > 0 ? normalized : null;
|
|
4161
|
+
}
|
|
4162
|
+
function setStoredDisplayCurrency(currency) {
|
|
4163
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4164
|
+
return;
|
|
4165
|
+
}
|
|
4166
|
+
if (!currency) {
|
|
4167
|
+
window.localStorage.removeItem(DISPLAY_CURRENCY_STORAGE_KEY);
|
|
4168
|
+
return;
|
|
4169
|
+
}
|
|
4170
|
+
window.localStorage.setItem(DISPLAY_CURRENCY_STORAGE_KEY, currency.toUpperCase());
|
|
4171
|
+
}
|
|
4345
4172
|
function resolveInitialLocation(locations) {
|
|
4346
4173
|
if (locations.length === 0) {
|
|
4347
4174
|
return null;
|
|
@@ -4371,6 +4198,60 @@ function CimplifyProvider({
|
|
|
4371
4198
|
onLocationChangeRef.current = onLocationChange;
|
|
4372
4199
|
}, [onLocationChange]);
|
|
4373
4200
|
const isDemoMode = resolvedClient.getPublicKey().trim().length === 0;
|
|
4201
|
+
const baseCurrency = business?.default_currency || DEFAULT_CURRENCY;
|
|
4202
|
+
const [displayCurrencyOverride, setDisplayCurrencyOverride] = useState(
|
|
4203
|
+
() => getStoredDisplayCurrency()
|
|
4204
|
+
);
|
|
4205
|
+
const [fxRate, setFxRate] = useState(null);
|
|
4206
|
+
const displayCurrency = displayCurrencyOverride && displayCurrencyOverride !== baseCurrency ? displayCurrencyOverride : baseCurrency;
|
|
4207
|
+
const setDisplayCurrency = useCallback(
|
|
4208
|
+
(currency) => {
|
|
4209
|
+
const normalized = currency?.trim().toUpperCase() || null;
|
|
4210
|
+
if (normalized && !isSupportedCurrency(normalized)) {
|
|
4211
|
+
return;
|
|
4212
|
+
}
|
|
4213
|
+
setDisplayCurrencyOverride(normalized);
|
|
4214
|
+
setStoredDisplayCurrency(normalized);
|
|
4215
|
+
if (!normalized || normalized === baseCurrency) {
|
|
4216
|
+
setFxRate(null);
|
|
4217
|
+
}
|
|
4218
|
+
},
|
|
4219
|
+
[baseCurrency]
|
|
4220
|
+
);
|
|
4221
|
+
useEffect(() => {
|
|
4222
|
+
if (displayCurrency === baseCurrency || isDemoMode) {
|
|
4223
|
+
setFxRate(null);
|
|
4224
|
+
return;
|
|
4225
|
+
}
|
|
4226
|
+
let cancelled = false;
|
|
4227
|
+
async function fetchRate() {
|
|
4228
|
+
const result = await resolvedClient.fx.getRate(
|
|
4229
|
+
baseCurrency,
|
|
4230
|
+
displayCurrency
|
|
4231
|
+
);
|
|
4232
|
+
if (cancelled) return;
|
|
4233
|
+
if (result.ok) {
|
|
4234
|
+
setFxRate(result.value.rate);
|
|
4235
|
+
} else {
|
|
4236
|
+
setFxRate(null);
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
void fetchRate();
|
|
4240
|
+
const intervalId = setInterval(() => void fetchRate(), FX_REFRESH_INTERVAL);
|
|
4241
|
+
return () => {
|
|
4242
|
+
cancelled = true;
|
|
4243
|
+
clearInterval(intervalId);
|
|
4244
|
+
};
|
|
4245
|
+
}, [resolvedClient, baseCurrency, displayCurrency, isDemoMode]);
|
|
4246
|
+
const convertPrice = useCallback(
|
|
4247
|
+
(amount) => {
|
|
4248
|
+
const num = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
4249
|
+
if (isNaN(num)) return 0;
|
|
4250
|
+
if (!fxRate || displayCurrency === baseCurrency) return num;
|
|
4251
|
+
return Math.round(num * fxRate * 100) / 100;
|
|
4252
|
+
},
|
|
4253
|
+
[fxRate, displayCurrency, baseCurrency]
|
|
4254
|
+
);
|
|
4374
4255
|
const setCurrentLocation = useCallback(
|
|
4375
4256
|
(location) => {
|
|
4376
4257
|
setCurrentLocationState(location);
|
|
@@ -4386,89 +4267,463 @@ function CimplifyProvider({
|
|
|
4386
4267
|
setIsReady(false);
|
|
4387
4268
|
if (isDemoMode) {
|
|
4388
4269
|
if (!cancelled) {
|
|
4389
|
-
setBusiness(null);
|
|
4390
|
-
setLocations([]);
|
|
4391
|
-
setCurrentLocationState(null);
|
|
4392
|
-
resolvedClient.setLocationId(null);
|
|
4393
|
-
setStoredLocationId(null);
|
|
4394
|
-
setIsReady(true);
|
|
4270
|
+
setBusiness(null);
|
|
4271
|
+
setLocations([]);
|
|
4272
|
+
setCurrentLocationState(null);
|
|
4273
|
+
resolvedClient.setLocationId(null);
|
|
4274
|
+
setStoredLocationId(null);
|
|
4275
|
+
setIsReady(true);
|
|
4276
|
+
}
|
|
4277
|
+
return;
|
|
4278
|
+
}
|
|
4279
|
+
const [businessResult, locationsResult] = await Promise.all([
|
|
4280
|
+
resolvedClient.business.getInfo(),
|
|
4281
|
+
resolvedClient.business.getLocations()
|
|
4282
|
+
]);
|
|
4283
|
+
if (cancelled) {
|
|
4284
|
+
return;
|
|
4285
|
+
}
|
|
4286
|
+
const nextBusiness = businessResult.ok ? businessResult.value : null;
|
|
4287
|
+
const nextLocations = locationsResult.ok && Array.isArray(locationsResult.value) ? locationsResult.value : [];
|
|
4288
|
+
const initialLocation = resolveInitialLocation(nextLocations);
|
|
4289
|
+
setBusiness(nextBusiness);
|
|
4290
|
+
if (nextBusiness?.id) {
|
|
4291
|
+
resolvedClient.setBusinessId(nextBusiness.id);
|
|
4292
|
+
}
|
|
4293
|
+
setLocations(nextLocations);
|
|
4294
|
+
if (initialLocation) {
|
|
4295
|
+
setCurrentLocationState(initialLocation);
|
|
4296
|
+
resolvedClient.setLocationId(initialLocation.id);
|
|
4297
|
+
setStoredLocationId(initialLocation.id);
|
|
4298
|
+
} else {
|
|
4299
|
+
setCurrentLocationState(null);
|
|
4300
|
+
resolvedClient.setLocationId(null);
|
|
4301
|
+
setStoredLocationId(null);
|
|
4302
|
+
}
|
|
4303
|
+
setIsReady(true);
|
|
4304
|
+
}
|
|
4305
|
+
bootstrap().catch(() => {
|
|
4306
|
+
if (cancelled) {
|
|
4307
|
+
return;
|
|
4308
|
+
}
|
|
4309
|
+
setBusiness(null);
|
|
4310
|
+
setLocations([]);
|
|
4311
|
+
setCurrentLocationState(null);
|
|
4312
|
+
resolvedClient.setLocationId(null);
|
|
4313
|
+
setStoredLocationId(null);
|
|
4314
|
+
setIsReady(true);
|
|
4315
|
+
});
|
|
4316
|
+
return () => {
|
|
4317
|
+
cancelled = true;
|
|
4318
|
+
};
|
|
4319
|
+
}, [resolvedClient, isDemoMode]);
|
|
4320
|
+
const contextValue = useMemo(
|
|
4321
|
+
() => ({
|
|
4322
|
+
client: resolvedClient,
|
|
4323
|
+
business,
|
|
4324
|
+
currency: baseCurrency,
|
|
4325
|
+
country: business?.country_code || DEFAULT_COUNTRY,
|
|
4326
|
+
locations,
|
|
4327
|
+
currentLocation,
|
|
4328
|
+
setCurrentLocation,
|
|
4329
|
+
isReady,
|
|
4330
|
+
isDemoMode,
|
|
4331
|
+
baseCurrency,
|
|
4332
|
+
displayCurrency,
|
|
4333
|
+
setDisplayCurrency,
|
|
4334
|
+
convertPrice,
|
|
4335
|
+
fxRate
|
|
4336
|
+
}),
|
|
4337
|
+
[
|
|
4338
|
+
resolvedClient,
|
|
4339
|
+
business,
|
|
4340
|
+
baseCurrency,
|
|
4341
|
+
locations,
|
|
4342
|
+
currentLocation,
|
|
4343
|
+
setCurrentLocation,
|
|
4344
|
+
isReady,
|
|
4345
|
+
isDemoMode,
|
|
4346
|
+
displayCurrency,
|
|
4347
|
+
setDisplayCurrency,
|
|
4348
|
+
convertPrice,
|
|
4349
|
+
fxRate
|
|
4350
|
+
]
|
|
4351
|
+
);
|
|
4352
|
+
return /* @__PURE__ */ jsx(CimplifyContext.Provider, { value: contextValue, children });
|
|
4353
|
+
}
|
|
4354
|
+
function useCimplify() {
|
|
4355
|
+
const context = useContext(CimplifyContext);
|
|
4356
|
+
if (!context) {
|
|
4357
|
+
throw new Error("useCimplify must be used within CimplifyProvider");
|
|
4358
|
+
}
|
|
4359
|
+
return context;
|
|
4360
|
+
}
|
|
4361
|
+
function useOptionalCimplify() {
|
|
4362
|
+
return useContext(CimplifyContext);
|
|
4363
|
+
}
|
|
4364
|
+
var SPACE = { sm: 8};
|
|
4365
|
+
function shellColors(isDark, primaryColor) {
|
|
4366
|
+
return {
|
|
4367
|
+
text: isDark ? "#f4f4f5" : "#1a1a1a",
|
|
4368
|
+
textSecondary: isDark ? "#a1a1aa" : "#52525b",
|
|
4369
|
+
textMuted: isDark ? "#71717a" : "#a1a1aa",
|
|
4370
|
+
border: isDark ? "#27272a" : "#e4e4e7",
|
|
4371
|
+
surface: isDark ? "#18181b" : "#fafafa",
|
|
4372
|
+
error: "#dc2626",
|
|
4373
|
+
primary: primaryColor
|
|
4374
|
+
};
|
|
4375
|
+
}
|
|
4376
|
+
function statusToLabel(status) {
|
|
4377
|
+
if (!status) {
|
|
4378
|
+
return "";
|
|
4379
|
+
}
|
|
4380
|
+
if (status === "preparing") {
|
|
4381
|
+
return "Preparing checkout";
|
|
4382
|
+
}
|
|
4383
|
+
if (status === "recovering") {
|
|
4384
|
+
return "Resuming payment";
|
|
4385
|
+
}
|
|
4386
|
+
if (status === "processing") {
|
|
4387
|
+
return "Processing payment";
|
|
4388
|
+
}
|
|
4389
|
+
if (status === "awaiting_authorization") {
|
|
4390
|
+
return "Waiting for authorization";
|
|
4391
|
+
}
|
|
4392
|
+
if (status === "polling") {
|
|
4393
|
+
return "Confirming payment";
|
|
4394
|
+
}
|
|
4395
|
+
if (status === "finalizing") {
|
|
4396
|
+
return "Finalizing order";
|
|
4397
|
+
}
|
|
4398
|
+
if (status === "success") {
|
|
4399
|
+
return "Payment complete";
|
|
4400
|
+
}
|
|
4401
|
+
return "Payment failed";
|
|
4402
|
+
}
|
|
4403
|
+
function CimplifyCheckout({
|
|
4404
|
+
client,
|
|
4405
|
+
businessId,
|
|
4406
|
+
cartId,
|
|
4407
|
+
locationId,
|
|
4408
|
+
linkUrl,
|
|
4409
|
+
orderTypes,
|
|
4410
|
+
enrollInLink = true,
|
|
4411
|
+
onComplete,
|
|
4412
|
+
onError,
|
|
4413
|
+
onStatusChange,
|
|
4414
|
+
appearance,
|
|
4415
|
+
demoMode,
|
|
4416
|
+
className
|
|
4417
|
+
}) {
|
|
4418
|
+
const resolvedOrderTypes = useMemo(
|
|
4419
|
+
() => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
|
|
4420
|
+
[orderTypes]
|
|
4421
|
+
);
|
|
4422
|
+
const [orderType, setOrderType] = useState(resolvedOrderTypes[0] || "pickup");
|
|
4423
|
+
const [status, setStatus] = useState(null);
|
|
4424
|
+
const [statusText, setStatusText] = useState("");
|
|
4425
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
4426
|
+
const [isInitializing, setIsInitializing] = useState(false);
|
|
4427
|
+
const [errorMessage, setErrorMessage] = useState(null);
|
|
4428
|
+
const [resolvedBusinessId, setResolvedBusinessId] = useState(businessId ?? null);
|
|
4429
|
+
const [resolvedCartId, setResolvedCartId] = useState(cartId ?? null);
|
|
4430
|
+
const [resolvedCart, setResolvedCart] = useState(null);
|
|
4431
|
+
const checkoutMountRef = useRef(null);
|
|
4432
|
+
const elementsRef = useRef(null);
|
|
4433
|
+
const activeCheckoutRef = useRef(null);
|
|
4434
|
+
const initialAppearanceRef = useRef(appearance);
|
|
4435
|
+
const hasWarnedInlineAppearanceRef = useRef(false);
|
|
4436
|
+
const isMountedRef = useRef(true);
|
|
4437
|
+
const demoRunRef = useRef(0);
|
|
4438
|
+
const isDemoCheckout = demoMode ?? client.getPublicKey().trim().length === 0;
|
|
4439
|
+
const isTestMode = client.isTestMode();
|
|
4440
|
+
const cimplifyCtx = useOptionalCimplify();
|
|
4441
|
+
const fxOptions = useMemo(() => {
|
|
4442
|
+
if (!cimplifyCtx?.fxRate) return void 0;
|
|
4443
|
+
if (cimplifyCtx.displayCurrency === cimplifyCtx.baseCurrency) return void 0;
|
|
4444
|
+
return {
|
|
4445
|
+
displayCurrency: cimplifyCtx.displayCurrency,
|
|
4446
|
+
convertPrice: cimplifyCtx.convertPrice
|
|
4447
|
+
};
|
|
4448
|
+
}, [cimplifyCtx?.fxRate, cimplifyCtx?.displayCurrency, cimplifyCtx?.baseCurrency, cimplifyCtx?.convertPrice]);
|
|
4449
|
+
const fxOptionsRef = useRef(fxOptions);
|
|
4450
|
+
fxOptionsRef.current = fxOptions;
|
|
4451
|
+
const resolvedCartRef = useRef(resolvedCart);
|
|
4452
|
+
resolvedCartRef.current = resolvedCart;
|
|
4453
|
+
const primaryColor = appearance?.variables?.primaryColor || "#0a2540";
|
|
4454
|
+
const isDark = appearance?.theme === "dark";
|
|
4455
|
+
const emitStatus = React3.useEffectEvent(
|
|
4456
|
+
(nextStatus, context = {}) => {
|
|
4457
|
+
setStatus(nextStatus);
|
|
4458
|
+
setStatusText(context.display_text || "");
|
|
4459
|
+
onStatusChange?.(nextStatus, context);
|
|
4460
|
+
}
|
|
4461
|
+
);
|
|
4462
|
+
const fireError = React3.useEffectEvent(
|
|
4463
|
+
(error) => {
|
|
4464
|
+
onError?.(error);
|
|
4465
|
+
}
|
|
4466
|
+
);
|
|
4467
|
+
useEffect(() => {
|
|
4468
|
+
if (!resolvedOrderTypes.includes(orderType)) {
|
|
4469
|
+
setOrderType(resolvedOrderTypes[0] || "pickup");
|
|
4470
|
+
}
|
|
4471
|
+
}, [resolvedOrderTypes, orderType]);
|
|
4472
|
+
useEffect(() => {
|
|
4473
|
+
if (appearance && appearance !== initialAppearanceRef.current && !hasWarnedInlineAppearanceRef.current) {
|
|
4474
|
+
hasWarnedInlineAppearanceRef.current = true;
|
|
4475
|
+
console.warn(
|
|
4476
|
+
"[Cimplify] `appearance` prop reference changed after mount. Elements keep the initial appearance to avoid iframe remount. Memoize appearance with useMemo() to remove this warning."
|
|
4477
|
+
);
|
|
4478
|
+
}
|
|
4479
|
+
}, [appearance]);
|
|
4480
|
+
useEffect(() => {
|
|
4481
|
+
let cancelled = false;
|
|
4482
|
+
async function bootstrap() {
|
|
4483
|
+
if (isDemoCheckout) {
|
|
4484
|
+
if (!cancelled) {
|
|
4485
|
+
setResolvedBusinessId(businessId ?? null);
|
|
4486
|
+
setResolvedCartId(cartId ?? "cart_demo");
|
|
4487
|
+
setIsInitializing(false);
|
|
4488
|
+
setErrorMessage(null);
|
|
4489
|
+
}
|
|
4490
|
+
return;
|
|
4491
|
+
}
|
|
4492
|
+
const needsBusinessResolve = !businessId;
|
|
4493
|
+
const needsCartResolve = !cartId;
|
|
4494
|
+
if (!needsBusinessResolve && !needsCartResolve) {
|
|
4495
|
+
if (!cancelled) {
|
|
4496
|
+
setResolvedBusinessId(businessId || null);
|
|
4497
|
+
setResolvedCartId(cartId || null);
|
|
4498
|
+
setIsInitializing(false);
|
|
4499
|
+
setErrorMessage(null);
|
|
4500
|
+
}
|
|
4501
|
+
client.cart.get().then((cartResult) => {
|
|
4502
|
+
if (!cancelled && cartResult.ok && cartResult.value) {
|
|
4503
|
+
setResolvedCart(cartResult.value);
|
|
4504
|
+
}
|
|
4505
|
+
}).catch(() => {
|
|
4506
|
+
});
|
|
4507
|
+
return;
|
|
4508
|
+
}
|
|
4509
|
+
if (!cancelled) {
|
|
4510
|
+
setIsInitializing(true);
|
|
4511
|
+
setErrorMessage(null);
|
|
4512
|
+
}
|
|
4513
|
+
let nextBusinessId = businessId ?? null;
|
|
4514
|
+
if (!nextBusinessId) {
|
|
4515
|
+
try {
|
|
4516
|
+
nextBusinessId = await client.resolveBusinessId();
|
|
4517
|
+
} catch {
|
|
4518
|
+
if (!cancelled) {
|
|
4519
|
+
const message = "Unable to initialize checkout business context.";
|
|
4520
|
+
setResolvedBusinessId(null);
|
|
4521
|
+
setResolvedCartId(null);
|
|
4522
|
+
setErrorMessage(message);
|
|
4523
|
+
setIsInitializing(false);
|
|
4524
|
+
fireError({ code: "BUSINESS_ID_REQUIRED", message });
|
|
4525
|
+
}
|
|
4526
|
+
return;
|
|
4527
|
+
}
|
|
4528
|
+
}
|
|
4529
|
+
let nextCartId = cartId ?? null;
|
|
4530
|
+
if (!nextCartId) {
|
|
4531
|
+
const cartResult = await client.cart.get();
|
|
4532
|
+
if (!cartResult.ok || !cartResult.value?.id || cartResult.value.items.length === 0) {
|
|
4533
|
+
if (!cancelled) {
|
|
4534
|
+
const message = "Your cart is empty. Add items before checkout.";
|
|
4535
|
+
setResolvedBusinessId(nextBusinessId);
|
|
4536
|
+
setResolvedCartId(null);
|
|
4537
|
+
setErrorMessage(message);
|
|
4538
|
+
setIsInitializing(false);
|
|
4539
|
+
fireError({ code: "CART_EMPTY", message });
|
|
4540
|
+
}
|
|
4541
|
+
return;
|
|
4542
|
+
}
|
|
4543
|
+
nextCartId = cartResult.value.id;
|
|
4544
|
+
if (!cancelled) {
|
|
4545
|
+
setResolvedCart(cartResult.value);
|
|
4395
4546
|
}
|
|
4396
|
-
return;
|
|
4397
4547
|
}
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
return;
|
|
4548
|
+
if (!cancelled) {
|
|
4549
|
+
setResolvedBusinessId(nextBusinessId);
|
|
4550
|
+
setResolvedCartId(nextCartId);
|
|
4551
|
+
setIsInitializing(false);
|
|
4552
|
+
setErrorMessage(null);
|
|
4404
4553
|
}
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4554
|
+
}
|
|
4555
|
+
void bootstrap();
|
|
4556
|
+
return () => {
|
|
4557
|
+
cancelled = true;
|
|
4558
|
+
};
|
|
4559
|
+
}, [businessId, cartId, client, isDemoCheckout]);
|
|
4560
|
+
useEffect(() => {
|
|
4561
|
+
return () => {
|
|
4562
|
+
isMountedRef.current = false;
|
|
4563
|
+
demoRunRef.current += 1;
|
|
4564
|
+
activeCheckoutRef.current?.abort();
|
|
4565
|
+
activeCheckoutRef.current = null;
|
|
4566
|
+
};
|
|
4567
|
+
}, []);
|
|
4568
|
+
const handleSubmit = React3.useEffectEvent(async () => {
|
|
4569
|
+
if (isSubmitting || isInitializing || !resolvedCartId) {
|
|
4570
|
+
if (!resolvedCartId && !isInitializing) {
|
|
4571
|
+
const message = "Your cart is empty. Add items before checkout.";
|
|
4572
|
+
setErrorMessage(message);
|
|
4573
|
+
fireError({ code: "CART_EMPTY", message });
|
|
4411
4574
|
}
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4575
|
+
return;
|
|
4576
|
+
}
|
|
4577
|
+
setErrorMessage(null);
|
|
4578
|
+
setIsSubmitting(true);
|
|
4579
|
+
emitStatus("preparing", { display_text: statusToLabel("preparing") });
|
|
4580
|
+
if (isDemoCheckout) {
|
|
4581
|
+
const runId = demoRunRef.current + 1;
|
|
4582
|
+
demoRunRef.current = runId;
|
|
4583
|
+
const wait = async (ms) => {
|
|
4584
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
4585
|
+
return isMountedRef.current && runId === demoRunRef.current;
|
|
4586
|
+
};
|
|
4587
|
+
try {
|
|
4588
|
+
if (!await wait(400)) return;
|
|
4589
|
+
emitStatus("processing", { display_text: statusToLabel("processing") });
|
|
4590
|
+
if (!await wait(900)) return;
|
|
4591
|
+
emitStatus("polling", { display_text: statusToLabel("polling") });
|
|
4592
|
+
if (!await wait(1200)) return;
|
|
4593
|
+
const result = {
|
|
4594
|
+
success: true,
|
|
4595
|
+
order: {
|
|
4596
|
+
id: `ord_demo_${Date.now()}`,
|
|
4597
|
+
order_number: `DEMO-${Math.random().toString(36).slice(2, 8).toUpperCase()}`,
|
|
4598
|
+
status: "confirmed",
|
|
4599
|
+
total: "0.00",
|
|
4600
|
+
currency: "USD"
|
|
4601
|
+
}
|
|
4602
|
+
};
|
|
4603
|
+
emitStatus("success", {
|
|
4604
|
+
order_id: result.order?.id,
|
|
4605
|
+
order_number: result.order?.order_number,
|
|
4606
|
+
display_text: statusToLabel("success")
|
|
4607
|
+
});
|
|
4608
|
+
onComplete(result);
|
|
4609
|
+
} finally {
|
|
4610
|
+
if (isMountedRef.current && runId === demoRunRef.current) {
|
|
4611
|
+
setIsSubmitting(false);
|
|
4612
|
+
}
|
|
4421
4613
|
}
|
|
4422
|
-
|
|
4614
|
+
return;
|
|
4423
4615
|
}
|
|
4424
|
-
|
|
4425
|
-
|
|
4616
|
+
if (!elementsRef.current) {
|
|
4617
|
+
const message = "Checkout is still initializing. Please try again.";
|
|
4618
|
+
setErrorMessage(message);
|
|
4619
|
+
fireError({ code: "CHECKOUT_NOT_READY", message });
|
|
4620
|
+
setIsSubmitting(false);
|
|
4621
|
+
return;
|
|
4622
|
+
}
|
|
4623
|
+
const checkout = elementsRef.current.processCheckout({
|
|
4624
|
+
cart_id: resolvedCartId,
|
|
4625
|
+
location_id: locationId ?? client.getLocationId() ?? void 0,
|
|
4626
|
+
order_type: orderType,
|
|
4627
|
+
enroll_in_link: enrollInLink,
|
|
4628
|
+
on_status_change: emitStatus,
|
|
4629
|
+
pay_currency: fxOptions?.displayCurrency
|
|
4630
|
+
});
|
|
4631
|
+
activeCheckoutRef.current = checkout;
|
|
4632
|
+
try {
|
|
4633
|
+
const result = await checkout;
|
|
4634
|
+
if (result.success) {
|
|
4635
|
+
onComplete(result);
|
|
4426
4636
|
return;
|
|
4427
4637
|
}
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4638
|
+
const code = result.error?.code || "CHECKOUT_FAILED";
|
|
4639
|
+
const message = result.error?.message || "Payment failed.";
|
|
4640
|
+
setErrorMessage(message);
|
|
4641
|
+
fireError({ code, message });
|
|
4642
|
+
} finally {
|
|
4643
|
+
if (isMountedRef.current) {
|
|
4644
|
+
activeCheckoutRef.current = null;
|
|
4645
|
+
setIsSubmitting(false);
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
});
|
|
4649
|
+
useEffect(() => {
|
|
4650
|
+
if (isDemoCheckout || !resolvedBusinessId) {
|
|
4651
|
+
elementsRef.current = null;
|
|
4652
|
+
return;
|
|
4653
|
+
}
|
|
4654
|
+
const elements = client.elements(resolvedBusinessId, {
|
|
4655
|
+
appearance: initialAppearanceRef.current,
|
|
4656
|
+
linkUrl
|
|
4657
|
+
});
|
|
4658
|
+
elementsRef.current = elements;
|
|
4659
|
+
const checkout = elements.create("checkout", {
|
|
4660
|
+
orderTypes: resolvedOrderTypes,
|
|
4661
|
+
defaultOrderType: resolvedOrderTypes[0]
|
|
4662
|
+
});
|
|
4663
|
+
if (checkoutMountRef.current) {
|
|
4664
|
+
checkout.mount(checkoutMountRef.current);
|
|
4665
|
+
}
|
|
4666
|
+
checkout.on("ready", () => {
|
|
4667
|
+
const cart = resolvedCartRef.current;
|
|
4668
|
+
if (cart) {
|
|
4669
|
+
checkout.setCart(transformToCheckoutCart(cart, fxOptionsRef.current));
|
|
4670
|
+
}
|
|
4671
|
+
});
|
|
4672
|
+
checkout.on("order_type_changed", (data) => {
|
|
4673
|
+
const typed = data;
|
|
4674
|
+
if (typed.orderType) {
|
|
4675
|
+
setOrderType(typed.orderType);
|
|
4676
|
+
}
|
|
4677
|
+
});
|
|
4678
|
+
checkout.on("request_submit", () => {
|
|
4679
|
+
void handleSubmit();
|
|
4434
4680
|
});
|
|
4435
4681
|
return () => {
|
|
4436
|
-
|
|
4682
|
+
activeCheckoutRef.current?.abort();
|
|
4683
|
+
activeCheckoutRef.current = null;
|
|
4684
|
+
elements.destroy();
|
|
4685
|
+
elementsRef.current = null;
|
|
4437
4686
|
};
|
|
4438
|
-
}, [
|
|
4439
|
-
|
|
4440
|
-
()
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
isDemoMode
|
|
4450
|
-
}),
|
|
4451
|
-
[
|
|
4452
|
-
resolvedClient,
|
|
4453
|
-
business,
|
|
4454
|
-
locations,
|
|
4455
|
-
currentLocation,
|
|
4456
|
-
setCurrentLocation,
|
|
4457
|
-
isReady,
|
|
4458
|
-
isDemoMode
|
|
4459
|
-
]
|
|
4460
|
-
);
|
|
4461
|
-
return /* @__PURE__ */ jsx(CimplifyContext.Provider, { value: contextValue, children });
|
|
4462
|
-
}
|
|
4463
|
-
function useCimplify() {
|
|
4464
|
-
const context = useContext(CimplifyContext);
|
|
4465
|
-
if (!context) {
|
|
4466
|
-
throw new Error("useCimplify must be used within CimplifyProvider");
|
|
4687
|
+
}, [client, resolvedBusinessId, isDemoCheckout]);
|
|
4688
|
+
useEffect(() => {
|
|
4689
|
+
if (!resolvedCart || !elementsRef.current) return;
|
|
4690
|
+
const checkoutElement = elementsRef.current.getElement("checkout");
|
|
4691
|
+
if (checkoutElement) {
|
|
4692
|
+
checkoutElement.setCart(transformToCheckoutCart(resolvedCart, fxOptions));
|
|
4693
|
+
}
|
|
4694
|
+
}, [resolvedCart, fxOptions]);
|
|
4695
|
+
const colors = shellColors(isDark ?? false, primaryColor);
|
|
4696
|
+
if (isInitializing) {
|
|
4697
|
+
return /* @__PURE__ */ jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsx("p", { "data-cimplify-status": "", style: { fontSize: 13, color: colors.textSecondary }, children: "Preparing checkout..." }) });
|
|
4467
4698
|
}
|
|
4468
|
-
|
|
4699
|
+
if (!isDemoCheckout && (!resolvedBusinessId || !resolvedCartId)) {
|
|
4700
|
+
return /* @__PURE__ */ jsx("div", { className, "data-cimplify-checkout": "", children: /* @__PURE__ */ jsx("p", { "data-cimplify-error": "", style: { fontSize: 13, color: colors.error }, children: errorMessage || "Unable to initialize checkout. Please refresh and try again." }) });
|
|
4701
|
+
}
|
|
4702
|
+
return /* @__PURE__ */ jsxs("div", { className, "data-cimplify-checkout": "", children: [
|
|
4703
|
+
isTestMode && !isDemoCheckout && /* @__PURE__ */ jsx(
|
|
4704
|
+
"p",
|
|
4705
|
+
{
|
|
4706
|
+
"data-cimplify-test-mode": "",
|
|
4707
|
+
style: {
|
|
4708
|
+
marginBottom: "10px",
|
|
4709
|
+
fontSize: "12px",
|
|
4710
|
+
fontWeight: 600,
|
|
4711
|
+
color: "#92400e"
|
|
4712
|
+
},
|
|
4713
|
+
children: "Test mode - no real charges"
|
|
4714
|
+
}
|
|
4715
|
+
),
|
|
4716
|
+
/* @__PURE__ */ jsx("div", { "data-cimplify-section": "checkout", children: /* @__PURE__ */ jsx("div", { ref: isDemoCheckout ? void 0 : checkoutMountRef }) }),
|
|
4717
|
+
status && /* @__PURE__ */ jsx("p", { "data-cimplify-status": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.textSecondary }, children: statusText || statusToLabel(status) }),
|
|
4718
|
+
errorMessage && /* @__PURE__ */ jsx("p", { "data-cimplify-error": "", style: { marginTop: SPACE.sm, fontSize: 13, color: colors.error }, children: errorMessage })
|
|
4719
|
+
] });
|
|
4469
4720
|
}
|
|
4470
|
-
function
|
|
4471
|
-
|
|
4721
|
+
function Price({ amount, className, prefix }) {
|
|
4722
|
+
const { displayCurrency, convertPrice } = useCimplify();
|
|
4723
|
+
return /* @__PURE__ */ jsxs("span", { className, children: [
|
|
4724
|
+
prefix,
|
|
4725
|
+
formatPrice(convertPrice(amount), displayCurrency)
|
|
4726
|
+
] });
|
|
4472
4727
|
}
|
|
4473
4728
|
var productsCache = /* @__PURE__ */ new Map();
|
|
4474
4729
|
var productsInflight = /* @__PURE__ */ new Map();
|
|
@@ -6499,4 +6754,4 @@ function useCheckout() {
|
|
|
6499
6754
|
return { submit, process, isLoading };
|
|
6500
6755
|
}
|
|
6501
6756
|
|
|
6502
|
-
export { Ad, AdProvider, AddressElement, AuthElement, CimplifyCheckout, CimplifyProvider, ElementsProvider, PaymentElement, useAds, useBundle, useCart, useCategories, useCheckout, useCimplify, useCollection, useCollections, useComposite, useElements, useElementsReady, useLocations, useOptionalCimplify, useOrder, useProduct, useProducts, useQuote, useSearch };
|
|
6757
|
+
export { Ad, AdProvider, AddressElement, AuthElement, CimplifyCheckout, CimplifyProvider, ElementsProvider, PaymentElement, Price, useAds, useBundle, useCart, useCategories, useCheckout, useCimplify, useCollection, useCollections, useComposite, useElements, useElementsReady, useLocations, useOptionalCimplify, useOrder, useProduct, useProducts, useQuote, useSearch };
|