@cimplify/sdk 0.8.7 → 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 +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +955 -879
- package/dist/react.mjs +748 -672
- 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,463 +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
|
-
|
|
745
|
-
// src/utils/price.ts
|
|
746
|
-
var CURRENCY_SYMBOLS = {
|
|
747
|
-
// Major world currencies
|
|
748
|
-
USD: "$",
|
|
749
|
-
EUR: "\u20AC",
|
|
750
|
-
GBP: "\xA3",
|
|
751
|
-
JPY: "\xA5",
|
|
752
|
-
CNY: "\xA5",
|
|
753
|
-
CHF: "CHF",
|
|
754
|
-
CAD: "C$",
|
|
755
|
-
AUD: "A$",
|
|
756
|
-
NZD: "NZ$",
|
|
757
|
-
HKD: "HK$",
|
|
758
|
-
SGD: "S$",
|
|
759
|
-
INR: "\u20B9",
|
|
760
|
-
BRL: "R$",
|
|
761
|
-
MXN: "MX$",
|
|
762
|
-
KRW: "\u20A9",
|
|
763
|
-
RUB: "\u20BD",
|
|
764
|
-
TRY: "\u20BA",
|
|
765
|
-
THB: "\u0E3F",
|
|
766
|
-
PLN: "z\u0142",
|
|
767
|
-
SEK: "kr",
|
|
768
|
-
NOK: "kr",
|
|
769
|
-
DKK: "kr",
|
|
770
|
-
CZK: "K\u010D",
|
|
771
|
-
HUF: "Ft",
|
|
772
|
-
ILS: "\u20AA",
|
|
773
|
-
AED: "\u062F.\u0625",
|
|
774
|
-
SAR: "\uFDFC",
|
|
775
|
-
MYR: "RM",
|
|
776
|
-
PHP: "\u20B1",
|
|
777
|
-
IDR: "Rp",
|
|
778
|
-
VND: "\u20AB",
|
|
779
|
-
TWD: "NT$",
|
|
780
|
-
// African currencies
|
|
781
|
-
GHS: "GH\u20B5",
|
|
782
|
-
NGN: "\u20A6",
|
|
783
|
-
KES: "KSh",
|
|
784
|
-
ZAR: "R",
|
|
785
|
-
XOF: "CFA",
|
|
786
|
-
XAF: "FCFA",
|
|
787
|
-
EGP: "E\xA3",
|
|
788
|
-
MAD: "MAD",
|
|
789
|
-
TZS: "TSh",
|
|
790
|
-
UGX: "USh",
|
|
791
|
-
RWF: "FRw",
|
|
792
|
-
ETB: "Br",
|
|
793
|
-
ZMW: "ZK",
|
|
794
|
-
BWP: "P",
|
|
795
|
-
MUR: "\u20A8",
|
|
796
|
-
SCR: "\u20A8",
|
|
797
|
-
NAD: "N$",
|
|
798
|
-
SZL: "E",
|
|
799
|
-
LSL: "L",
|
|
800
|
-
MWK: "MK",
|
|
801
|
-
AOA: "Kz",
|
|
802
|
-
CDF: "FC",
|
|
803
|
-
GMD: "D",
|
|
804
|
-
GNF: "FG",
|
|
805
|
-
LRD: "L$",
|
|
806
|
-
SLL: "Le",
|
|
807
|
-
MZN: "MT",
|
|
808
|
-
SDG: "SDG",
|
|
809
|
-
SSP: "SSP",
|
|
810
|
-
SOS: "Sh.So.",
|
|
811
|
-
DJF: "Fdj",
|
|
812
|
-
ERN: "Nfk",
|
|
813
|
-
CVE: "$",
|
|
814
|
-
STN: "Db",
|
|
815
|
-
KMF: "CF",
|
|
816
|
-
BIF: "FBu"
|
|
817
|
-
};
|
|
818
|
-
function getCurrencySymbol(currencyCode2) {
|
|
819
|
-
return CURRENCY_SYMBOLS[currencyCode2.toUpperCase()] || currencyCode2;
|
|
820
|
-
}
|
|
821
|
-
function formatPrice(amount, currency = "GHS", locale = "en-US") {
|
|
822
|
-
const numAmount = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
823
|
-
if (isNaN(numAmount)) {
|
|
824
|
-
return `${getCurrencySymbol(currency)}0.00`;
|
|
825
|
-
}
|
|
826
|
-
try {
|
|
827
|
-
return new Intl.NumberFormat(locale, {
|
|
828
|
-
style: "currency",
|
|
829
|
-
currency: currency.toUpperCase(),
|
|
830
|
-
minimumFractionDigits: 2,
|
|
831
|
-
maximumFractionDigits: 2
|
|
832
|
-
}).format(numAmount);
|
|
833
|
-
} catch {
|
|
834
|
-
return `${getCurrencySymbol(currency)}${numAmount.toFixed(2)}`;
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
function parsePrice(value) {
|
|
838
|
-
if (value === void 0 || value === null) {
|
|
839
|
-
return 0;
|
|
840
|
-
}
|
|
841
|
-
if (typeof value === "number") {
|
|
842
|
-
return isNaN(value) ? 0 : value;
|
|
843
|
-
}
|
|
844
|
-
const cleaned = value.replace(/[^\d.-]/g, "");
|
|
845
|
-
const parsed = parseFloat(cleaned);
|
|
846
|
-
return isNaN(parsed) ? 0 : parsed;
|
|
847
|
-
}
|
|
848
404
|
|
|
849
405
|
// src/types/common.ts
|
|
850
406
|
function money(value) {
|
|
@@ -853,6 +409,59 @@ function money(value) {
|
|
|
853
409
|
function moneyFromNumber(value) {
|
|
854
410
|
return value.toFixed(2);
|
|
855
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
|
+
}
|
|
856
465
|
function currencyCode(value) {
|
|
857
466
|
return value;
|
|
858
467
|
}
|
|
@@ -1448,14 +1057,118 @@ var CartOperations = class {
|
|
|
1448
1057
|
});
|
|
1449
1058
|
return ok(found);
|
|
1450
1059
|
}
|
|
1451
|
-
};
|
|
1452
|
-
|
|
1453
|
-
// src/constants.ts
|
|
1454
|
-
var MOBILE_MONEY_PROVIDER = {
|
|
1455
|
-
MTN: "mtn",
|
|
1456
|
-
VODAFONE: "vodafone",
|
|
1457
|
-
AIRTEL: "airtel"
|
|
1458
|
-
};
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
// src/constants.ts
|
|
1063
|
+
var MOBILE_MONEY_PROVIDER = {
|
|
1064
|
+
MTN: "mtn",
|
|
1065
|
+
VODAFONE: "vodafone",
|
|
1066
|
+
AIRTEL: "airtel"
|
|
1067
|
+
};
|
|
1068
|
+
|
|
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
|
+
}
|
|
1161
|
+
function parsePrice(value) {
|
|
1162
|
+
if (value === void 0 || value === null) {
|
|
1163
|
+
return 0;
|
|
1164
|
+
}
|
|
1165
|
+
if (typeof value === "number") {
|
|
1166
|
+
return isNaN(value) ? 0 : value;
|
|
1167
|
+
}
|
|
1168
|
+
const cleaned = value.replace(/[^\d.-]/g, "");
|
|
1169
|
+
const parsed = parseFloat(cleaned);
|
|
1170
|
+
return isNaN(parsed) ? 0 : parsed;
|
|
1171
|
+
}
|
|
1459
1172
|
|
|
1460
1173
|
// src/utils/payment.ts
|
|
1461
1174
|
var PAYMENT_SUCCESS_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -4400,247 +4113,610 @@ var CimplifyClient = class {
|
|
|
4400
4113
|
}
|
|
4401
4114
|
return createElements(this, businessId ?? this.businessId ?? void 0, options);
|
|
4402
4115
|
}
|
|
4403
|
-
};
|
|
4404
|
-
function createCimplifyClient(config = {}) {
|
|
4405
|
-
return new CimplifyClient(config);
|
|
4116
|
+
};
|
|
4117
|
+
function createCimplifyClient(config = {}) {
|
|
4118
|
+
return new CimplifyClient(config);
|
|
4119
|
+
}
|
|
4120
|
+
var LOCATION_STORAGE_KEY = "cimplify_location_id";
|
|
4121
|
+
var DISPLAY_CURRENCY_STORAGE_KEY = "cimplify_display_currency";
|
|
4122
|
+
var FX_REFRESH_INTERVAL = 12e4;
|
|
4123
|
+
var DEFAULT_CURRENCY = "USD";
|
|
4124
|
+
var DEFAULT_COUNTRY = "US";
|
|
4125
|
+
function createDefaultClient() {
|
|
4126
|
+
const processRef = globalThis.process;
|
|
4127
|
+
const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
|
|
4128
|
+
return createCimplifyClient({ publicKey: envPublicKey });
|
|
4129
|
+
}
|
|
4130
|
+
function getStoredLocationId() {
|
|
4131
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4132
|
+
return null;
|
|
4133
|
+
}
|
|
4134
|
+
const value = window.localStorage.getItem(LOCATION_STORAGE_KEY);
|
|
4135
|
+
if (!value) {
|
|
4136
|
+
return null;
|
|
4137
|
+
}
|
|
4138
|
+
const normalized = value.trim();
|
|
4139
|
+
return normalized.length > 0 ? normalized : null;
|
|
4140
|
+
}
|
|
4141
|
+
function setStoredLocationId(locationId) {
|
|
4142
|
+
if (typeof window === "undefined" || !window.localStorage) {
|
|
4143
|
+
return;
|
|
4144
|
+
}
|
|
4145
|
+
if (!locationId) {
|
|
4146
|
+
window.localStorage.removeItem(LOCATION_STORAGE_KEY);
|
|
4147
|
+
return;
|
|
4148
|
+
}
|
|
4149
|
+
window.localStorage.setItem(LOCATION_STORAGE_KEY, locationId);
|
|
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
|
+
}
|
|
4172
|
+
function resolveInitialLocation(locations) {
|
|
4173
|
+
if (locations.length === 0) {
|
|
4174
|
+
return null;
|
|
4175
|
+
}
|
|
4176
|
+
const storedId = getStoredLocationId();
|
|
4177
|
+
if (storedId) {
|
|
4178
|
+
const matched = locations.find((location) => location.id === storedId);
|
|
4179
|
+
if (matched) {
|
|
4180
|
+
return matched;
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
return locations[0];
|
|
4184
|
+
}
|
|
4185
|
+
var CimplifyContext = createContext(null);
|
|
4186
|
+
function CimplifyProvider({
|
|
4187
|
+
client,
|
|
4188
|
+
children,
|
|
4189
|
+
onLocationChange
|
|
4190
|
+
}) {
|
|
4191
|
+
const resolvedClient = useMemo(() => client ?? createDefaultClient(), [client]);
|
|
4192
|
+
const onLocationChangeRef = useRef(onLocationChange);
|
|
4193
|
+
const [business, setBusiness] = useState(null);
|
|
4194
|
+
const [locations, setLocations] = useState([]);
|
|
4195
|
+
const [currentLocation, setCurrentLocationState] = useState(null);
|
|
4196
|
+
const [isReady, setIsReady] = useState(false);
|
|
4197
|
+
useEffect(() => {
|
|
4198
|
+
onLocationChangeRef.current = onLocationChange;
|
|
4199
|
+
}, [onLocationChange]);
|
|
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
|
+
);
|
|
4255
|
+
const setCurrentLocation = useCallback(
|
|
4256
|
+
(location) => {
|
|
4257
|
+
setCurrentLocationState(location);
|
|
4258
|
+
resolvedClient.setLocationId(location.id);
|
|
4259
|
+
setStoredLocationId(location.id);
|
|
4260
|
+
onLocationChangeRef.current?.(location);
|
|
4261
|
+
},
|
|
4262
|
+
[resolvedClient]
|
|
4263
|
+
);
|
|
4264
|
+
useEffect(() => {
|
|
4265
|
+
let cancelled = false;
|
|
4266
|
+
async function bootstrap() {
|
|
4267
|
+
setIsReady(false);
|
|
4268
|
+
if (isDemoMode) {
|
|
4269
|
+
if (!cancelled) {
|
|
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;
|
|
4406
4360
|
}
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
var FX_REFRESH_INTERVAL = 12e4;
|
|
4410
|
-
var DEFAULT_CURRENCY = "USD";
|
|
4411
|
-
var DEFAULT_COUNTRY = "US";
|
|
4412
|
-
function createDefaultClient() {
|
|
4413
|
-
const processRef = globalThis.process;
|
|
4414
|
-
const envPublicKey = processRef?.env?.NEXT_PUBLIC_CIMPLIFY_PUBLIC_KEY || "";
|
|
4415
|
-
return createCimplifyClient({ publicKey: envPublicKey });
|
|
4361
|
+
function useOptionalCimplify() {
|
|
4362
|
+
return useContext(CimplifyContext);
|
|
4416
4363
|
}
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
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
|
+
};
|
|
4427
4375
|
}
|
|
4428
|
-
function
|
|
4429
|
-
if (
|
|
4430
|
-
return;
|
|
4376
|
+
function statusToLabel(status) {
|
|
4377
|
+
if (!status) {
|
|
4378
|
+
return "";
|
|
4431
4379
|
}
|
|
4432
|
-
if (
|
|
4433
|
-
|
|
4434
|
-
return;
|
|
4380
|
+
if (status === "preparing") {
|
|
4381
|
+
return "Preparing checkout";
|
|
4435
4382
|
}
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
function getStoredDisplayCurrency() {
|
|
4439
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
4440
|
-
return null;
|
|
4383
|
+
if (status === "recovering") {
|
|
4384
|
+
return "Resuming payment";
|
|
4441
4385
|
}
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
return null;
|
|
4386
|
+
if (status === "processing") {
|
|
4387
|
+
return "Processing payment";
|
|
4445
4388
|
}
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
}
|
|
4449
|
-
function setStoredDisplayCurrency(currency) {
|
|
4450
|
-
if (typeof window === "undefined" || !window.localStorage) {
|
|
4451
|
-
return;
|
|
4389
|
+
if (status === "awaiting_authorization") {
|
|
4390
|
+
return "Waiting for authorization";
|
|
4452
4391
|
}
|
|
4453
|
-
if (
|
|
4454
|
-
|
|
4455
|
-
return;
|
|
4392
|
+
if (status === "polling") {
|
|
4393
|
+
return "Confirming payment";
|
|
4456
4394
|
}
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
function resolveInitialLocation(locations) {
|
|
4460
|
-
if (locations.length === 0) {
|
|
4461
|
-
return null;
|
|
4395
|
+
if (status === "finalizing") {
|
|
4396
|
+
return "Finalizing order";
|
|
4462
4397
|
}
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
const matched = locations.find((location) => location.id === storedId);
|
|
4466
|
-
if (matched) {
|
|
4467
|
-
return matched;
|
|
4468
|
-
}
|
|
4398
|
+
if (status === "success") {
|
|
4399
|
+
return "Payment complete";
|
|
4469
4400
|
}
|
|
4470
|
-
return
|
|
4401
|
+
return "Payment failed";
|
|
4471
4402
|
}
|
|
4472
|
-
|
|
4473
|
-
function CimplifyProvider({
|
|
4403
|
+
function CimplifyCheckout({
|
|
4474
4404
|
client,
|
|
4475
|
-
|
|
4476
|
-
|
|
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
|
|
4477
4417
|
}) {
|
|
4478
|
-
const
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
const [locations, setLocations] = useState([]);
|
|
4482
|
-
const [currentLocation, setCurrentLocationState] = useState(null);
|
|
4483
|
-
const [isReady, setIsReady] = useState(false);
|
|
4484
|
-
useEffect(() => {
|
|
4485
|
-
onLocationChangeRef.current = onLocationChange;
|
|
4486
|
-
}, [onLocationChange]);
|
|
4487
|
-
const isDemoMode = resolvedClient.getPublicKey().trim().length === 0;
|
|
4488
|
-
const baseCurrency = business?.default_currency || DEFAULT_CURRENCY;
|
|
4489
|
-
const [displayCurrencyOverride, setDisplayCurrencyOverride] = useState(
|
|
4490
|
-
() => getStoredDisplayCurrency()
|
|
4418
|
+
const resolvedOrderTypes = useMemo(
|
|
4419
|
+
() => orderTypes && orderTypes.length > 0 ? orderTypes : ["pickup", "delivery"],
|
|
4420
|
+
[orderTypes]
|
|
4491
4421
|
);
|
|
4492
|
-
const [
|
|
4493
|
-
const
|
|
4494
|
-
const
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
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
|
+
}
|
|
4504
4466
|
);
|
|
4505
4467
|
useEffect(() => {
|
|
4506
|
-
if (
|
|
4507
|
-
|
|
4508
|
-
return;
|
|
4468
|
+
if (!resolvedOrderTypes.includes(orderType)) {
|
|
4469
|
+
setOrderType(resolvedOrderTypes[0] || "pickup");
|
|
4509
4470
|
}
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
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."
|
|
4515
4477
|
);
|
|
4516
|
-
|
|
4517
|
-
|
|
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);
|
|
4546
|
+
}
|
|
4547
|
+
}
|
|
4548
|
+
if (!cancelled) {
|
|
4549
|
+
setResolvedBusinessId(nextBusinessId);
|
|
4550
|
+
setResolvedCartId(nextCartId);
|
|
4551
|
+
setIsInitializing(false);
|
|
4552
|
+
setErrorMessage(null);
|
|
4518
4553
|
}
|
|
4519
4554
|
}
|
|
4520
|
-
void
|
|
4521
|
-
const intervalId = setInterval(() => void fetchRate(), FX_REFRESH_INTERVAL);
|
|
4555
|
+
void bootstrap();
|
|
4522
4556
|
return () => {
|
|
4523
4557
|
cancelled = true;
|
|
4524
|
-
clearInterval(intervalId);
|
|
4525
4558
|
};
|
|
4526
|
-
}, [
|
|
4527
|
-
const convertPrice = useCallback(
|
|
4528
|
-
(amount) => {
|
|
4529
|
-
const num = typeof amount === "string" ? parseFloat(amount) : amount;
|
|
4530
|
-
if (isNaN(num)) return 0;
|
|
4531
|
-
if (!fxRate || displayCurrency === baseCurrency) return num;
|
|
4532
|
-
return Math.round(num * fxRate * 100) / 100;
|
|
4533
|
-
},
|
|
4534
|
-
[fxRate, displayCurrency, baseCurrency]
|
|
4535
|
-
);
|
|
4536
|
-
const setCurrentLocation = useCallback(
|
|
4537
|
-
(location) => {
|
|
4538
|
-
setCurrentLocationState(location);
|
|
4539
|
-
resolvedClient.setLocationId(location.id);
|
|
4540
|
-
setStoredLocationId(location.id);
|
|
4541
|
-
onLocationChangeRef.current?.(location);
|
|
4542
|
-
},
|
|
4543
|
-
[resolvedClient]
|
|
4544
|
-
);
|
|
4559
|
+
}, [businessId, cartId, client, isDemoCheckout]);
|
|
4545
4560
|
useEffect(() => {
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
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 });
|
|
4574
|
+
}
|
|
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);
|
|
4557
4612
|
}
|
|
4558
|
-
return;
|
|
4559
4613
|
}
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4614
|
+
return;
|
|
4615
|
+
}
|
|
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);
|
|
4565
4636
|
return;
|
|
4566
4637
|
}
|
|
4567
|
-
const
|
|
4568
|
-
const
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
if (initialLocation) {
|
|
4576
|
-
setCurrentLocationState(initialLocation);
|
|
4577
|
-
resolvedClient.setLocationId(initialLocation.id);
|
|
4578
|
-
setStoredLocationId(initialLocation.id);
|
|
4579
|
-
} else {
|
|
4580
|
-
setCurrentLocationState(null);
|
|
4581
|
-
resolvedClient.setLocationId(null);
|
|
4582
|
-
setStoredLocationId(null);
|
|
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);
|
|
4583
4646
|
}
|
|
4584
|
-
setIsReady(true);
|
|
4585
4647
|
}
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
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));
|
|
4589
4670
|
}
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
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();
|
|
4596
4680
|
});
|
|
4597
4681
|
return () => {
|
|
4598
|
-
|
|
4682
|
+
activeCheckoutRef.current?.abort();
|
|
4683
|
+
activeCheckoutRef.current = null;
|
|
4684
|
+
elements.destroy();
|
|
4685
|
+
elementsRef.current = null;
|
|
4599
4686
|
};
|
|
4600
|
-
}, [
|
|
4601
|
-
|
|
4602
|
-
()
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
isDemoMode,
|
|
4612
|
-
baseCurrency,
|
|
4613
|
-
displayCurrency,
|
|
4614
|
-
setDisplayCurrency,
|
|
4615
|
-
convertPrice,
|
|
4616
|
-
fxRate
|
|
4617
|
-
}),
|
|
4618
|
-
[
|
|
4619
|
-
resolvedClient,
|
|
4620
|
-
business,
|
|
4621
|
-
baseCurrency,
|
|
4622
|
-
locations,
|
|
4623
|
-
currentLocation,
|
|
4624
|
-
setCurrentLocation,
|
|
4625
|
-
isReady,
|
|
4626
|
-
isDemoMode,
|
|
4627
|
-
displayCurrency,
|
|
4628
|
-
setDisplayCurrency,
|
|
4629
|
-
convertPrice,
|
|
4630
|
-
fxRate
|
|
4631
|
-
]
|
|
4632
|
-
);
|
|
4633
|
-
return /* @__PURE__ */ jsx(CimplifyContext.Provider, { value: contextValue, children });
|
|
4634
|
-
}
|
|
4635
|
-
function useCimplify() {
|
|
4636
|
-
const context = useContext(CimplifyContext);
|
|
4637
|
-
if (!context) {
|
|
4638
|
-
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..." }) });
|
|
4639
4698
|
}
|
|
4640
|
-
|
|
4641
|
-
}
|
|
4642
|
-
|
|
4643
|
-
return
|
|
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
|
+
] });
|
|
4644
4720
|
}
|
|
4645
4721
|
function Price({ amount, className, prefix }) {
|
|
4646
4722
|
const { displayCurrency, convertPrice } = useCimplify();
|