@doujins/payments-ui 0.1.15 → 0.1.17-alpha
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/index.cjs +1137 -371
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +306 -68
- package/dist/index.d.ts +306 -68
- package/dist/index.js +975 -213
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React4 = require('react');
|
|
4
4
|
var reactQuery = require('@tanstack/react-query');
|
|
5
5
|
var walletAdapterReact = require('@solana/wallet-adapter-react');
|
|
6
6
|
var walletAdapterReactUi = require('@solana/wallet-adapter-react-ui');
|
|
@@ -48,7 +48,7 @@ function _interopNamespace(e) {
|
|
|
48
48
|
return Object.freeze(n);
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
var
|
|
51
|
+
var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
|
|
52
52
|
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
53
53
|
var clsx2__default = /*#__PURE__*/_interopDefault(clsx2);
|
|
54
54
|
var countryList__default = /*#__PURE__*/_interopDefault(countryList);
|
|
@@ -281,6 +281,7 @@ var createClient = (config) => {
|
|
|
281
281
|
return normalizeList(result);
|
|
282
282
|
},
|
|
283
283
|
createPaymentMethod(payload) {
|
|
284
|
+
console.log("Creating payment method with payload:", payload);
|
|
284
285
|
return request("POST", "/me/payment-methods", {
|
|
285
286
|
body: payload
|
|
286
287
|
});
|
|
@@ -298,10 +299,10 @@ var createClient = (config) => {
|
|
|
298
299
|
},
|
|
299
300
|
checkout(payload, idempotencyKey) {
|
|
300
301
|
const key = idempotencyKey ?? crypto.randomUUID();
|
|
301
|
-
return request("POST", "/
|
|
302
|
+
return request("POST", "/checkout", {
|
|
302
303
|
body: payload,
|
|
303
304
|
headers: {
|
|
304
|
-
"Idempotency-Key": key
|
|
305
|
+
"X-Idempotency-Key": key
|
|
305
306
|
}
|
|
306
307
|
});
|
|
307
308
|
},
|
|
@@ -310,6 +311,36 @@ var createClient = (config) => {
|
|
|
310
311
|
body: feedback ? { feedback } : void 0
|
|
311
312
|
});
|
|
312
313
|
},
|
|
314
|
+
async listSubscriptions(params) {
|
|
315
|
+
const result = await request(
|
|
316
|
+
"GET",
|
|
317
|
+
"/me/subscriptions",
|
|
318
|
+
{
|
|
319
|
+
query: {
|
|
320
|
+
status: params?.status,
|
|
321
|
+
limit: params?.limit,
|
|
322
|
+
offset: params?.offset
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
return normalizeList(result);
|
|
327
|
+
},
|
|
328
|
+
updateSubscriptionPaymentMethod(payload) {
|
|
329
|
+
return request("PUT", "/me/subscriptions/payment-method", {
|
|
330
|
+
body: {
|
|
331
|
+
subscription_id: payload.subscription_id,
|
|
332
|
+
payment_method_id: payload.payment_method_id
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
resumeSubscription() {
|
|
337
|
+
return request("POST", "/me/subscriptions/resume");
|
|
338
|
+
},
|
|
339
|
+
changeSubscription(payload) {
|
|
340
|
+
return request("POST", "/me/subscriptions/change", {
|
|
341
|
+
body: payload
|
|
342
|
+
});
|
|
343
|
+
},
|
|
313
344
|
async getPaymentHistory(params) {
|
|
314
345
|
const result = await request("GET", "/me/payments", {
|
|
315
346
|
query: {
|
|
@@ -455,6 +486,19 @@ function DialogHeader({ className, ...props }) {
|
|
|
455
486
|
}
|
|
456
487
|
);
|
|
457
488
|
}
|
|
489
|
+
function DialogFooter({ className, ...props }) {
|
|
490
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
491
|
+
"div",
|
|
492
|
+
{
|
|
493
|
+
"data-slot": "dialog-footer",
|
|
494
|
+
className: cn(
|
|
495
|
+
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
|
|
496
|
+
className
|
|
497
|
+
),
|
|
498
|
+
...props
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
}
|
|
458
502
|
function DialogTitle({
|
|
459
503
|
className,
|
|
460
504
|
...props
|
|
@@ -521,7 +565,7 @@ var buttonVariants = classVarianceAuthority.cva(
|
|
|
521
565
|
}
|
|
522
566
|
}
|
|
523
567
|
);
|
|
524
|
-
var Button =
|
|
568
|
+
var Button = React4__namespace.forwardRef(
|
|
525
569
|
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
526
570
|
const Comp = asChild ? reactSlot.Slot : "button";
|
|
527
571
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -535,7 +579,7 @@ var Button = React15__namespace.forwardRef(
|
|
|
535
579
|
}
|
|
536
580
|
);
|
|
537
581
|
Button.displayName = "Button";
|
|
538
|
-
var Input =
|
|
582
|
+
var Input = React4__namespace.forwardRef(
|
|
539
583
|
({ className, type, ...props }, ref) => {
|
|
540
584
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
541
585
|
"input",
|
|
@@ -555,7 +599,7 @@ Input.displayName = "Input";
|
|
|
555
599
|
var labelVariants = classVarianceAuthority.cva(
|
|
556
600
|
"text-sm font-medium leading-none text-foreground peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
557
601
|
);
|
|
558
|
-
var Label =
|
|
602
|
+
var Label = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
559
603
|
LabelPrimitive__namespace.Root,
|
|
560
604
|
{
|
|
561
605
|
ref,
|
|
@@ -564,9 +608,9 @@ var Label = React15__namespace.forwardRef(({ className, ...props }, ref) => /* @
|
|
|
564
608
|
}
|
|
565
609
|
));
|
|
566
610
|
Label.displayName = LabelPrimitive__namespace.Root.displayName;
|
|
567
|
-
var Select =
|
|
611
|
+
var Select = SelectPrimitive__namespace.Root;
|
|
568
612
|
var SelectValue = SelectPrimitive__namespace.Value;
|
|
569
|
-
var SelectTrigger =
|
|
613
|
+
var SelectTrigger = React4__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
570
614
|
SelectPrimitive__namespace.Trigger,
|
|
571
615
|
{
|
|
572
616
|
ref,
|
|
@@ -582,7 +626,7 @@ var SelectTrigger = React15__namespace.forwardRef(({ className, children, ...pro
|
|
|
582
626
|
}
|
|
583
627
|
));
|
|
584
628
|
SelectTrigger.displayName = SelectPrimitive__namespace.Trigger.displayName;
|
|
585
|
-
var SelectScrollUpButton =
|
|
629
|
+
var SelectScrollUpButton = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
586
630
|
SelectPrimitive__namespace.ScrollUpButton,
|
|
587
631
|
{
|
|
588
632
|
ref,
|
|
@@ -595,7 +639,7 @@ var SelectScrollUpButton = React15__namespace.forwardRef(({ className, ...props
|
|
|
595
639
|
}
|
|
596
640
|
));
|
|
597
641
|
SelectScrollUpButton.displayName = SelectPrimitive__namespace.ScrollUpButton.displayName;
|
|
598
|
-
var SelectScrollDownButton =
|
|
642
|
+
var SelectScrollDownButton = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
599
643
|
SelectPrimitive__namespace.ScrollDownButton,
|
|
600
644
|
{
|
|
601
645
|
ref,
|
|
@@ -608,39 +652,61 @@ var SelectScrollDownButton = React15__namespace.forwardRef(({ className, ...prop
|
|
|
608
652
|
}
|
|
609
653
|
));
|
|
610
654
|
SelectScrollDownButton.displayName = SelectPrimitive__namespace.ScrollDownButton.displayName;
|
|
611
|
-
var SelectContent =
|
|
612
|
-
(
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
...props
|
|
620
|
-
}, ref) => {
|
|
621
|
-
const popperProps = position === "popper" ? { side, sideOffset, align } : {};
|
|
622
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
623
|
-
SelectPrimitive__namespace.Content,
|
|
624
|
-
{
|
|
625
|
-
ref,
|
|
626
|
-
className: cn(
|
|
627
|
-
"z-[200] max-h-64 w-[var(--radix-select-trigger-width)] overflow-y-auto overflow-x-hidden rounded-md border border-white/20 bg-background-regular text-foreground shadow-lg backdrop-blur-xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
628
|
-
className
|
|
629
|
-
),
|
|
630
|
-
position,
|
|
631
|
-
...popperProps,
|
|
632
|
-
...props,
|
|
633
|
-
children: [
|
|
634
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
|
|
635
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Viewport, { className: "p-1", children }),
|
|
636
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectScrollDownButton, {})
|
|
637
|
-
]
|
|
655
|
+
var SelectContent = React4__namespace.forwardRef(({ className, children, position = "popper", ...props }, ref) => {
|
|
656
|
+
const viewportRef = React4__namespace.useRef(null);
|
|
657
|
+
const contentRef = React4__namespace.useCallback((node) => {
|
|
658
|
+
if (node) {
|
|
659
|
+
node.style.setProperty("max-height", "40vh", "important");
|
|
660
|
+
const anchorWidth = window.getComputedStyle(node).getPropertyValue("--radix-popper-anchor-width");
|
|
661
|
+
if (anchorWidth) {
|
|
662
|
+
node.style.setProperty("width", anchorWidth, "important");
|
|
638
663
|
}
|
|
639
|
-
|
|
640
|
-
}
|
|
641
|
-
)
|
|
664
|
+
}
|
|
665
|
+
}, []);
|
|
666
|
+
const combinedRef = React4__namespace.useCallback((node) => {
|
|
667
|
+
contentRef(node);
|
|
668
|
+
if (typeof ref === "function") {
|
|
669
|
+
ref(node);
|
|
670
|
+
} else if (ref) {
|
|
671
|
+
ref.current = node;
|
|
672
|
+
}
|
|
673
|
+
}, [contentRef, ref]);
|
|
674
|
+
React4__namespace.useEffect(() => {
|
|
675
|
+
if (viewportRef.current) {
|
|
676
|
+
viewportRef.current.style.setProperty("max-height", "40vh", "important");
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
680
|
+
SelectPrimitive__namespace.Content,
|
|
681
|
+
{
|
|
682
|
+
ref: combinedRef,
|
|
683
|
+
className: cn(
|
|
684
|
+
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-white/20 bg-background-regular text-foreground shadow-lg backdrop-blur-xl data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
685
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
686
|
+
className
|
|
687
|
+
),
|
|
688
|
+
position,
|
|
689
|
+
...props,
|
|
690
|
+
children: [
|
|
691
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
|
|
692
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
693
|
+
SelectPrimitive__namespace.Viewport,
|
|
694
|
+
{
|
|
695
|
+
ref: viewportRef,
|
|
696
|
+
className: cn(
|
|
697
|
+
"p-1 overflow-y-auto",
|
|
698
|
+
position === "popper" && "w-full min-w-[var(--radix-select-trigger-width)]"
|
|
699
|
+
),
|
|
700
|
+
children
|
|
701
|
+
}
|
|
702
|
+
),
|
|
703
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectScrollDownButton, {})
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
) });
|
|
707
|
+
});
|
|
642
708
|
SelectContent.displayName = SelectPrimitive__namespace.Content.displayName;
|
|
643
|
-
var SelectLabel =
|
|
709
|
+
var SelectLabel = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
644
710
|
SelectPrimitive__namespace.Label,
|
|
645
711
|
{
|
|
646
712
|
ref,
|
|
@@ -649,7 +715,7 @@ var SelectLabel = React15__namespace.forwardRef(({ className, ...props }, ref) =
|
|
|
649
715
|
}
|
|
650
716
|
));
|
|
651
717
|
SelectLabel.displayName = SelectPrimitive__namespace.Label.displayName;
|
|
652
|
-
var SelectItem =
|
|
718
|
+
var SelectItem = React4__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
653
719
|
SelectPrimitive__namespace.Item,
|
|
654
720
|
{
|
|
655
721
|
ref,
|
|
@@ -665,7 +731,7 @@ var SelectItem = React15__namespace.forwardRef(({ className, children, ...props
|
|
|
665
731
|
}
|
|
666
732
|
));
|
|
667
733
|
SelectItem.displayName = SelectPrimitive__namespace.Item.displayName;
|
|
668
|
-
var SelectSeparator =
|
|
734
|
+
var SelectSeparator = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
669
735
|
SelectPrimitive__namespace.Separator,
|
|
670
736
|
{
|
|
671
737
|
ref,
|
|
@@ -687,6 +753,28 @@ var defaultBillingDetails = {
|
|
|
687
753
|
email: "",
|
|
688
754
|
provider: "mobius"
|
|
689
755
|
};
|
|
756
|
+
var defaultCardDetailsFormTranslations = {
|
|
757
|
+
firstName: "First name",
|
|
758
|
+
lastName: "Last name",
|
|
759
|
+
email: "Email",
|
|
760
|
+
address: "Address",
|
|
761
|
+
city: "City",
|
|
762
|
+
state: "State / Region",
|
|
763
|
+
postalCode: "Postal code",
|
|
764
|
+
country: "Country",
|
|
765
|
+
cardNumber: "Card number",
|
|
766
|
+
expiry: "Expiry",
|
|
767
|
+
cvv: "CVV",
|
|
768
|
+
submit: "Submit",
|
|
769
|
+
processing: "Processing\u2026",
|
|
770
|
+
errorRequiredFields: "Please complete all required billing fields.",
|
|
771
|
+
errorTokenization: "Payment tokenization failed. Please try again.",
|
|
772
|
+
errorFormNotReady: "Payment form is not ready. Please try again later.",
|
|
773
|
+
infoSecure: "Your payment information is encrypted and processed securely.",
|
|
774
|
+
cancel: "Cancel",
|
|
775
|
+
editEmail: "Edit email",
|
|
776
|
+
selectCountry: "Select a country"
|
|
777
|
+
};
|
|
690
778
|
var buildSelector = (prefix, field) => `#${prefix}-${field}`;
|
|
691
779
|
var CardDetailsForm = ({
|
|
692
780
|
visible,
|
|
@@ -698,11 +786,13 @@ var CardDetailsForm = ({
|
|
|
698
786
|
collectPrefix = "card-form",
|
|
699
787
|
className,
|
|
700
788
|
onBillingChange,
|
|
701
|
-
submitDisabled = false
|
|
789
|
+
submitDisabled = false,
|
|
790
|
+
translations
|
|
702
791
|
}) => {
|
|
792
|
+
const t = { ...defaultCardDetailsFormTranslations, ...translations };
|
|
703
793
|
const { config } = usePaymentContext();
|
|
704
|
-
const defaultValuesKey =
|
|
705
|
-
const mergedDefaults =
|
|
794
|
+
const defaultValuesKey = React4.useMemo(() => JSON.stringify(defaultValues ?? {}), [defaultValues]);
|
|
795
|
+
const mergedDefaults = React4.useMemo(
|
|
706
796
|
() => ({
|
|
707
797
|
...defaultBillingDetails,
|
|
708
798
|
...defaultValues,
|
|
@@ -710,20 +800,21 @@ var CardDetailsForm = ({
|
|
|
710
800
|
}),
|
|
711
801
|
[defaultValuesKey, config.defaultUser?.email]
|
|
712
802
|
);
|
|
713
|
-
const [firstName, setFirstName] =
|
|
714
|
-
const [lastName, setLastName] =
|
|
715
|
-
const [address1, setAddress1] =
|
|
716
|
-
const [city, setCity] =
|
|
717
|
-
const [stateRegion, setStateRegion] =
|
|
718
|
-
const [postalCode, setPostalCode] =
|
|
719
|
-
const [country, setCountry] =
|
|
720
|
-
const [email, setEmail] =
|
|
721
|
-
const [
|
|
722
|
-
const [
|
|
723
|
-
const [
|
|
803
|
+
const [firstName, setFirstName] = React4.useState(mergedDefaults.firstName);
|
|
804
|
+
const [lastName, setLastName] = React4.useState(mergedDefaults.lastName);
|
|
805
|
+
const [address1, setAddress1] = React4.useState(mergedDefaults.address1);
|
|
806
|
+
const [city, setCity] = React4.useState(mergedDefaults.city);
|
|
807
|
+
const [stateRegion, setStateRegion] = React4.useState(mergedDefaults.stateRegion ?? "");
|
|
808
|
+
const [postalCode, setPostalCode] = React4.useState(mergedDefaults.postalCode);
|
|
809
|
+
const [country, setCountry] = React4.useState(mergedDefaults.country);
|
|
810
|
+
const [email, setEmail] = React4.useState(mergedDefaults.email ?? "");
|
|
811
|
+
const [isEditingEmail, setIsEditingEmail] = React4.useState(false);
|
|
812
|
+
const [localError, setLocalError] = React4.useState(null);
|
|
813
|
+
const [isTokenizing, setIsTokenizing] = React4.useState(false);
|
|
814
|
+
const [collectReady, setCollectReady] = React4.useState(
|
|
724
815
|
typeof window !== "undefined" && Boolean(window.CollectJS)
|
|
725
816
|
);
|
|
726
|
-
|
|
817
|
+
React4.useEffect(() => {
|
|
727
818
|
if (collectReady) return;
|
|
728
819
|
let active = true;
|
|
729
820
|
waitForCollectJs().then((instance) => {
|
|
@@ -735,13 +826,16 @@ var CardDetailsForm = ({
|
|
|
735
826
|
active = false;
|
|
736
827
|
};
|
|
737
828
|
}, [collectReady]);
|
|
738
|
-
|
|
829
|
+
React4.useEffect(() => {
|
|
739
830
|
if (!visible) {
|
|
740
831
|
setLocalError(null);
|
|
741
832
|
setIsTokenizing(false);
|
|
833
|
+
if (typeof window !== "undefined" && window.__doujinsCollectConfigured && collectPrefix) {
|
|
834
|
+
window.__doujinsCollectConfigured[collectPrefix] = false;
|
|
835
|
+
}
|
|
742
836
|
}
|
|
743
|
-
}, [visible]);
|
|
744
|
-
|
|
837
|
+
}, [visible, collectPrefix]);
|
|
838
|
+
React4.useEffect(() => {
|
|
745
839
|
if (!visible) return;
|
|
746
840
|
setFirstName(mergedDefaults.firstName);
|
|
747
841
|
setLastName(mergedDefaults.lastName);
|
|
@@ -752,7 +846,7 @@ var CardDetailsForm = ({
|
|
|
752
846
|
setCountry(mergedDefaults.country);
|
|
753
847
|
setEmail(mergedDefaults.email ?? "");
|
|
754
848
|
}, [defaultValuesKey, mergedDefaults, visible]);
|
|
755
|
-
|
|
849
|
+
React4.useEffect(() => {
|
|
756
850
|
if (!onBillingChange) return;
|
|
757
851
|
onBillingChange({
|
|
758
852
|
firstName,
|
|
@@ -791,7 +885,7 @@ var CardDetailsForm = ({
|
|
|
791
885
|
}
|
|
792
886
|
return sanitized;
|
|
793
887
|
};
|
|
794
|
-
|
|
888
|
+
React4.useEffect(() => {
|
|
795
889
|
if (!collectReady || typeof window === "undefined" || !window.CollectJS || !visible) {
|
|
796
890
|
return;
|
|
797
891
|
}
|
|
@@ -802,6 +896,8 @@ var CardDetailsForm = ({
|
|
|
802
896
|
setLocalError("Payment tokenization failed. Please try again.");
|
|
803
897
|
return;
|
|
804
898
|
}
|
|
899
|
+
let rawExp = response.card?.exp;
|
|
900
|
+
let formattedExp = rawExp && rawExp.length === 4 ? `${rawExp.slice(0, 2)}/${rawExp.slice(2)}` : rawExp;
|
|
805
901
|
const billing = {
|
|
806
902
|
firstName,
|
|
807
903
|
lastName,
|
|
@@ -811,7 +907,10 @@ var CardDetailsForm = ({
|
|
|
811
907
|
postalCode,
|
|
812
908
|
country,
|
|
813
909
|
email,
|
|
814
|
-
provider: mergedDefaults.provider ?? "mobius"
|
|
910
|
+
provider: mergedDefaults.provider ?? "mobius",
|
|
911
|
+
last_four: response.card?.number,
|
|
912
|
+
card_type: response.card?.type,
|
|
913
|
+
expiry_date: formattedExp
|
|
815
914
|
};
|
|
816
915
|
onTokenize(response.token, billing);
|
|
817
916
|
};
|
|
@@ -851,9 +950,8 @@ var CardDetailsForm = ({
|
|
|
851
950
|
visible
|
|
852
951
|
]);
|
|
853
952
|
const validate = () => {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
setLocalError("Please complete all required billing fields.");
|
|
953
|
+
if (!firstName.trim() || !lastName.trim() || !address1.trim() || !city.trim() || !postalCode.trim() || !country.trim() || !email.trim()) {
|
|
954
|
+
setLocalError(t.errorRequiredFields);
|
|
857
955
|
return false;
|
|
858
956
|
}
|
|
859
957
|
setLocalError(null);
|
|
@@ -863,7 +961,7 @@ var CardDetailsForm = ({
|
|
|
863
961
|
event.preventDefault();
|
|
864
962
|
if (!validate()) return;
|
|
865
963
|
if (!window.CollectJS) {
|
|
866
|
-
setLocalError(
|
|
964
|
+
setLocalError(t.errorFormNotReady);
|
|
867
965
|
return;
|
|
868
966
|
}
|
|
869
967
|
setIsTokenizing(true);
|
|
@@ -871,7 +969,8 @@ var CardDetailsForm = ({
|
|
|
871
969
|
};
|
|
872
970
|
const errorMessage = localError ?? externalError;
|
|
873
971
|
const collectFieldClass = "relative flex h-9 w-full items-center overflow-hidden rounded-md border border-white/30 bg-transparent px-3 text-sm text-foreground";
|
|
874
|
-
const
|
|
972
|
+
const hasDefaultEmail = Boolean(defaultValues?.email || config.defaultUser?.email);
|
|
973
|
+
const showEmailInput = !hasDefaultEmail || isEditingEmail;
|
|
875
974
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
876
975
|
"form",
|
|
877
976
|
{
|
|
@@ -882,7 +981,7 @@ var CardDetailsForm = ({
|
|
|
882
981
|
errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-500/40 bg-red-500/10 px-4 py-2 text-sm text-red-400", children: errorMessage }),
|
|
883
982
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 md:flex-row", children: [
|
|
884
983
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
885
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "firstName", children:
|
|
984
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "firstName", children: t.firstName }),
|
|
886
985
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
887
986
|
Input,
|
|
888
987
|
{
|
|
@@ -894,7 +993,7 @@ var CardDetailsForm = ({
|
|
|
894
993
|
)
|
|
895
994
|
] }),
|
|
896
995
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2", children: [
|
|
897
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "lastName", children:
|
|
996
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "lastName", children: t.lastName }),
|
|
898
997
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
899
998
|
Input,
|
|
900
999
|
{
|
|
@@ -906,21 +1005,50 @@ var CardDetailsForm = ({
|
|
|
906
1005
|
)
|
|
907
1006
|
] })
|
|
908
1007
|
] }),
|
|
909
|
-
|
|
910
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "email", children:
|
|
911
|
-
/* @__PURE__ */ jsxRuntime.
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
1008
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1009
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "email", children: t.email }),
|
|
1010
|
+
showEmailInput ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
1011
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1012
|
+
Input,
|
|
1013
|
+
{
|
|
1014
|
+
id: "email",
|
|
1015
|
+
type: "email",
|
|
1016
|
+
value: email,
|
|
1017
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1018
|
+
required: true,
|
|
1019
|
+
className: "flex-1"
|
|
1020
|
+
}
|
|
1021
|
+
),
|
|
1022
|
+
hasDefaultEmail && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1023
|
+
Button,
|
|
1024
|
+
{
|
|
1025
|
+
type: "button",
|
|
1026
|
+
variant: "ghost",
|
|
1027
|
+
size: "sm",
|
|
1028
|
+
onClick: () => {
|
|
1029
|
+
setIsEditingEmail(false);
|
|
1030
|
+
setEmail(mergedDefaults.email ?? "");
|
|
1031
|
+
},
|
|
1032
|
+
className: "px-3 text-xs text-muted-foreground hover:text-foreground",
|
|
1033
|
+
children: t.cancel
|
|
1034
|
+
}
|
|
1035
|
+
)
|
|
1036
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between h-9 w-full rounded-md border border-white/30 bg-transparent px-3 text-sm text-foreground", children: [
|
|
1037
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: email }),
|
|
1038
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1039
|
+
"button",
|
|
1040
|
+
{
|
|
1041
|
+
type: "button",
|
|
1042
|
+
onClick: () => setIsEditingEmail(true),
|
|
1043
|
+
className: "text-muted-foreground hover:text-foreground transition-colors",
|
|
1044
|
+
"aria-label": t.editEmail,
|
|
1045
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pencil, { className: "h-4 w-4" })
|
|
1046
|
+
}
|
|
1047
|
+
)
|
|
1048
|
+
] })
|
|
921
1049
|
] }),
|
|
922
1050
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
923
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "address1", children:
|
|
1051
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "address1", children: t.address }),
|
|
924
1052
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
925
1053
|
Input,
|
|
926
1054
|
{
|
|
@@ -933,7 +1061,7 @@ var CardDetailsForm = ({
|
|
|
933
1061
|
] }),
|
|
934
1062
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2 md:grid-cols-2", children: [
|
|
935
1063
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
936
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "city", children:
|
|
1064
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "city", children: t.city }),
|
|
937
1065
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
938
1066
|
Input,
|
|
939
1067
|
{
|
|
@@ -945,7 +1073,7 @@ var CardDetailsForm = ({
|
|
|
945
1073
|
)
|
|
946
1074
|
] }),
|
|
947
1075
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
948
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "state", children:
|
|
1076
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "state", children: t.state }),
|
|
949
1077
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
950
1078
|
Input,
|
|
951
1079
|
{
|
|
@@ -958,7 +1086,7 @@ var CardDetailsForm = ({
|
|
|
958
1086
|
] }),
|
|
959
1087
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2 md:grid-cols-2", children: [
|
|
960
1088
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
961
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "postal", children:
|
|
1089
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "postal", children: t.postalCode }),
|
|
962
1090
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
963
1091
|
Input,
|
|
964
1092
|
{
|
|
@@ -970,24 +1098,24 @@ var CardDetailsForm = ({
|
|
|
970
1098
|
)
|
|
971
1099
|
] }),
|
|
972
1100
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
973
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1101
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.country }),
|
|
974
1102
|
/* @__PURE__ */ jsxRuntime.jsxs(Select, { value: country, onValueChange: setCountry, children: [
|
|
975
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder:
|
|
976
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, {
|
|
1103
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: t.selectCountry }) }),
|
|
1104
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: countries.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.code, children: option.name }, option.code)) })
|
|
977
1105
|
] })
|
|
978
1106
|
] })
|
|
979
1107
|
] }),
|
|
980
1108
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
981
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1109
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.cardNumber }),
|
|
982
1110
|
/* @__PURE__ */ jsxRuntime.jsx("div", { id: buildSelector(collectPrefix, "ccnumber").slice(1), className: collectFieldClass })
|
|
983
1111
|
] }),
|
|
984
1112
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-2 md:grid-cols-2", children: [
|
|
985
1113
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
986
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1114
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.expiry }),
|
|
987
1115
|
/* @__PURE__ */ jsxRuntime.jsx("div", { id: buildSelector(collectPrefix, "ccexp").slice(1), className: collectFieldClass })
|
|
988
1116
|
] }),
|
|
989
1117
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
990
|
-
/* @__PURE__ */ jsxRuntime.jsx(Label, { children:
|
|
1118
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: t.cvv }),
|
|
991
1119
|
/* @__PURE__ */ jsxRuntime.jsx("div", { id: buildSelector(collectPrefix, "cvv").slice(1), className: collectFieldClass })
|
|
992
1120
|
] })
|
|
993
1121
|
] }),
|
|
@@ -999,11 +1127,12 @@ var CardDetailsForm = ({
|
|
|
999
1127
|
disabled: submitting || submitDisabled || isTokenizing,
|
|
1000
1128
|
children: submitting || isTokenizing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1001
1129
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
1002
|
-
"
|
|
1003
|
-
|
|
1130
|
+
" ",
|
|
1131
|
+
t.processing
|
|
1132
|
+
] }) : submitLabel || t.submit
|
|
1004
1133
|
}
|
|
1005
1134
|
),
|
|
1006
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-white/60", children:
|
|
1135
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-white/60", children: t.infoSecure })
|
|
1007
1136
|
]
|
|
1008
1137
|
}
|
|
1009
1138
|
);
|
|
@@ -1040,7 +1169,9 @@ var usePaymentMethods = () => {
|
|
|
1040
1169
|
zip: billing.postalCode,
|
|
1041
1170
|
country: billing.country,
|
|
1042
1171
|
email: billing.email,
|
|
1043
|
-
provider: billing.provider
|
|
1172
|
+
provider: billing.provider,
|
|
1173
|
+
last_four: billing.last_four,
|
|
1174
|
+
card_type: billing.card_type
|
|
1044
1175
|
};
|
|
1045
1176
|
return client.createPaymentMethod(payload);
|
|
1046
1177
|
},
|
|
@@ -1079,7 +1210,7 @@ var badgeVariants = classVarianceAuthority.cva(
|
|
|
1079
1210
|
function Badge({ className, variant, ...props }) {
|
|
1080
1211
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(badgeVariants({ variant }), className), ...props });
|
|
1081
1212
|
}
|
|
1082
|
-
var ScrollArea =
|
|
1213
|
+
var ScrollArea = React4__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1083
1214
|
ScrollAreaPrimitive__namespace.Root,
|
|
1084
1215
|
{
|
|
1085
1216
|
ref,
|
|
@@ -1093,7 +1224,7 @@ var ScrollArea = React15__namespace.forwardRef(({ className, children, ...props
|
|
|
1093
1224
|
}
|
|
1094
1225
|
));
|
|
1095
1226
|
ScrollArea.displayName = ScrollAreaPrimitive__namespace.Root.displayName;
|
|
1096
|
-
var ScrollBar =
|
|
1227
|
+
var ScrollBar = React4__namespace.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1097
1228
|
ScrollAreaPrimitive__namespace.ScrollAreaScrollbar,
|
|
1098
1229
|
{
|
|
1099
1230
|
ref,
|
|
@@ -1109,21 +1240,34 @@ var ScrollBar = React15__namespace.forwardRef(({ className, orientation = "verti
|
|
|
1109
1240
|
}
|
|
1110
1241
|
));
|
|
1111
1242
|
ScrollBar.displayName = ScrollAreaPrimitive__namespace.ScrollAreaScrollbar.displayName;
|
|
1243
|
+
var defaultTranslations = {
|
|
1244
|
+
loadingCards: "Loading cards...",
|
|
1245
|
+
noSavedMethods: "No saved payment methods yet.",
|
|
1246
|
+
selectedLabel: "Selected",
|
|
1247
|
+
useCardLabel: "Use card"
|
|
1248
|
+
};
|
|
1112
1249
|
var formatCardLabel = (method) => {
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1250
|
+
if (method.card) {
|
|
1251
|
+
const brand = method.card.brand ? method.card.brand.toUpperCase() : "CARD";
|
|
1252
|
+
const lastFour = method.card.last4 ? `\u2022\u2022\u2022\u2022 ${method.card.last4}` : "";
|
|
1253
|
+
const exp = method.card.exp_month && method.card.exp_year ? ` \u2022 ${String(method.card.exp_month).padStart(2, "0")}/${String(method.card.exp_year).slice(-2)}` : "";
|
|
1254
|
+
return `${brand} ${lastFour}${exp}`.trim();
|
|
1255
|
+
}
|
|
1256
|
+
return "CARD";
|
|
1116
1257
|
};
|
|
1117
1258
|
var StoredPaymentMethods = ({
|
|
1118
1259
|
selectedMethodId,
|
|
1119
|
-
onMethodSelect
|
|
1260
|
+
onMethodSelect,
|
|
1261
|
+
translations
|
|
1120
1262
|
}) => {
|
|
1121
1263
|
const { listQuery } = usePaymentMethods();
|
|
1122
|
-
const payments =
|
|
1264
|
+
const payments = React4.useMemo(() => listQuery.data?.data ?? [], [listQuery.data]);
|
|
1265
|
+
const t = { ...defaultTranslations, ...translations };
|
|
1123
1266
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: listQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-4 text-sm text-muted-foreground", children: [
|
|
1124
1267
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
1125
|
-
"
|
|
1126
|
-
|
|
1268
|
+
" ",
|
|
1269
|
+
t.loadingCards
|
|
1270
|
+
] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: t.noSavedMethods }) : /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "max-h-[320px] pr-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) => {
|
|
1127
1271
|
const isSelected = selectedMethodId === method.id;
|
|
1128
1272
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1129
1273
|
"div",
|
|
@@ -1146,7 +1290,7 @@ var StoredPaymentMethods = ({
|
|
|
1146
1290
|
disabled: isSelected,
|
|
1147
1291
|
onClick: () => onMethodSelect(method),
|
|
1148
1292
|
className: clsx2__default.default("px-3", { "bg-muted/90": !isSelected, "bg-inherit": isSelected }),
|
|
1149
|
-
children: isSelected ?
|
|
1293
|
+
children: isSelected ? t.selectedLabel : t.useCardLabel
|
|
1150
1294
|
}
|
|
1151
1295
|
)
|
|
1152
1296
|
] })
|
|
@@ -1156,6 +1300,26 @@ var StoredPaymentMethods = ({
|
|
|
1156
1300
|
);
|
|
1157
1301
|
}) }) }) });
|
|
1158
1302
|
};
|
|
1303
|
+
|
|
1304
|
+
// src/utils/errorMessages.ts
|
|
1305
|
+
var resolveErrorMessageByCode = (error, translationErrors, fallbackMessage) => {
|
|
1306
|
+
const errors = translationErrors ?? {};
|
|
1307
|
+
const defaultMessage = fallbackMessage ?? (error instanceof Error ? error.message : typeof error === "string" ? error : "An unexpected error occurred");
|
|
1308
|
+
if (error instanceof ClientApiError) {
|
|
1309
|
+
const payload = error.body;
|
|
1310
|
+
const code = payload?.code ?? payload?.error?.code;
|
|
1311
|
+
if (code && errors[code]) return errors[code];
|
|
1312
|
+
if (typeof payload?.error?.message === "string") return payload.error.message;
|
|
1313
|
+
return error.message;
|
|
1314
|
+
}
|
|
1315
|
+
if (typeof error === "object" && error !== null && "code" in error) {
|
|
1316
|
+
const code = error.code;
|
|
1317
|
+
if (typeof code === "string" && errors[code]) return errors[code];
|
|
1318
|
+
}
|
|
1319
|
+
if (error instanceof Error) return error.message;
|
|
1320
|
+
if (typeof error === "string") return error;
|
|
1321
|
+
return defaultMessage;
|
|
1322
|
+
};
|
|
1159
1323
|
function Tabs({
|
|
1160
1324
|
className,
|
|
1161
1325
|
...props
|
|
@@ -1178,7 +1342,7 @@ function TabsList({
|
|
|
1178
1342
|
{
|
|
1179
1343
|
"data-slot": "tabs-list",
|
|
1180
1344
|
className: cn(
|
|
1181
|
-
"bg-
|
|
1345
|
+
"bg-transparent border border-white/30 text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-1",
|
|
1182
1346
|
className
|
|
1183
1347
|
),
|
|
1184
1348
|
...props
|
|
@@ -1189,12 +1353,32 @@ function TabsTrigger({
|
|
|
1189
1353
|
className,
|
|
1190
1354
|
...props
|
|
1191
1355
|
}) {
|
|
1356
|
+
const triggerRef = React4__namespace.useRef(null);
|
|
1357
|
+
React4__namespace.useEffect(() => {
|
|
1358
|
+
const element = triggerRef.current;
|
|
1359
|
+
if (!element) return;
|
|
1360
|
+
const updateStyles = () => {
|
|
1361
|
+
const isActive = element.getAttribute("data-state") === "active";
|
|
1362
|
+
if (isActive) {
|
|
1363
|
+
element.style.setProperty("background-color", "rgba(255, 255, 255, 0.3)", "important");
|
|
1364
|
+
element.style.setProperty("border-color", "transparent", "important");
|
|
1365
|
+
} else {
|
|
1366
|
+
element.style.removeProperty("background-color");
|
|
1367
|
+
element.style.removeProperty("border-color");
|
|
1368
|
+
}
|
|
1369
|
+
};
|
|
1370
|
+
updateStyles();
|
|
1371
|
+
const observer = new MutationObserver(updateStyles);
|
|
1372
|
+
observer.observe(element, { attributes: true, attributeFilter: ["data-state"] });
|
|
1373
|
+
return () => observer.disconnect();
|
|
1374
|
+
}, []);
|
|
1192
1375
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1193
1376
|
TabsPrimitive__namespace.Trigger,
|
|
1194
1377
|
{
|
|
1378
|
+
ref: triggerRef,
|
|
1195
1379
|
"data-slot": "tabs-trigger",
|
|
1196
1380
|
className: cn(
|
|
1197
|
-
"data-[state=active]:
|
|
1381
|
+
"data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/70 inline-flex h-[calc(100%-0.5rem)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow,background-color,border-color] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm hover:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1198
1382
|
className
|
|
1199
1383
|
),
|
|
1200
1384
|
...props
|
|
@@ -1216,19 +1400,19 @@ function TabsContent({
|
|
|
1216
1400
|
}
|
|
1217
1401
|
var usePaymentNotifications = () => {
|
|
1218
1402
|
const { config } = usePaymentContext();
|
|
1219
|
-
const notifyStatus =
|
|
1403
|
+
const notifyStatus = React4.useCallback(
|
|
1220
1404
|
(status, context) => {
|
|
1221
1405
|
config.callbacks?.onStatusChange?.({ status, context });
|
|
1222
1406
|
},
|
|
1223
1407
|
[config.callbacks]
|
|
1224
1408
|
);
|
|
1225
|
-
const notifySuccess =
|
|
1409
|
+
const notifySuccess = React4.useCallback(
|
|
1226
1410
|
(payload) => {
|
|
1227
1411
|
config.callbacks?.onSuccess?.(payload ?? {});
|
|
1228
1412
|
},
|
|
1229
1413
|
[config.callbacks]
|
|
1230
1414
|
);
|
|
1231
|
-
const notifyError =
|
|
1415
|
+
const notifyError = React4.useCallback(
|
|
1232
1416
|
(error) => {
|
|
1233
1417
|
config.callbacks?.onError?.(
|
|
1234
1418
|
typeof error === "string" ? new Error(error) : error
|
|
@@ -1246,17 +1430,17 @@ var useSolanaQrPayment = (options) => {
|
|
|
1246
1430
|
const { priceId, selectedToken, onSuccess, onError } = options;
|
|
1247
1431
|
const { client } = usePaymentContext();
|
|
1248
1432
|
const tokenSymbol = selectedToken?.symbol ?? null;
|
|
1249
|
-
const onSuccessRef =
|
|
1250
|
-
const onErrorRef =
|
|
1251
|
-
const [intent, setIntent] =
|
|
1252
|
-
const [qrDataUri, setQrDataUri] =
|
|
1253
|
-
const [isLoading, setIsLoading] =
|
|
1254
|
-
const [error, setError] =
|
|
1255
|
-
const [timeRemaining, setTimeRemaining] =
|
|
1256
|
-
const [refreshNonce, setRefreshNonce] =
|
|
1257
|
-
const pollRef =
|
|
1258
|
-
const countdownRef =
|
|
1259
|
-
const clearTimers =
|
|
1433
|
+
const onSuccessRef = React4.useRef(onSuccess);
|
|
1434
|
+
const onErrorRef = React4.useRef(onError);
|
|
1435
|
+
const [intent, setIntent] = React4.useState(null);
|
|
1436
|
+
const [qrDataUri, setQrDataUri] = React4.useState(null);
|
|
1437
|
+
const [isLoading, setIsLoading] = React4.useState(false);
|
|
1438
|
+
const [error, setError] = React4.useState(null);
|
|
1439
|
+
const [timeRemaining, setTimeRemaining] = React4.useState(0);
|
|
1440
|
+
const [refreshNonce, setRefreshNonce] = React4.useState(0);
|
|
1441
|
+
const pollRef = React4.useRef(null);
|
|
1442
|
+
const countdownRef = React4.useRef(null);
|
|
1443
|
+
const clearTimers = React4.useCallback(() => {
|
|
1260
1444
|
if (pollRef.current) {
|
|
1261
1445
|
clearInterval(pollRef.current);
|
|
1262
1446
|
pollRef.current = null;
|
|
@@ -1266,12 +1450,12 @@ var useSolanaQrPayment = (options) => {
|
|
|
1266
1450
|
countdownRef.current = null;
|
|
1267
1451
|
}
|
|
1268
1452
|
}, []);
|
|
1269
|
-
|
|
1453
|
+
React4.useEffect(() => {
|
|
1270
1454
|
return () => {
|
|
1271
1455
|
clearTimers();
|
|
1272
1456
|
};
|
|
1273
1457
|
}, [clearTimers]);
|
|
1274
|
-
const resetState =
|
|
1458
|
+
const resetState = React4.useCallback(
|
|
1275
1459
|
(message) => {
|
|
1276
1460
|
clearTimers();
|
|
1277
1461
|
setIntent(null);
|
|
@@ -1281,13 +1465,13 @@ var useSolanaQrPayment = (options) => {
|
|
|
1281
1465
|
},
|
|
1282
1466
|
[clearTimers]
|
|
1283
1467
|
);
|
|
1284
|
-
|
|
1468
|
+
React4.useEffect(() => {
|
|
1285
1469
|
onSuccessRef.current = onSuccess;
|
|
1286
1470
|
}, [onSuccess]);
|
|
1287
|
-
|
|
1471
|
+
React4.useEffect(() => {
|
|
1288
1472
|
onErrorRef.current = onError;
|
|
1289
1473
|
}, [onError]);
|
|
1290
|
-
const handleError =
|
|
1474
|
+
const handleError = React4.useCallback(
|
|
1291
1475
|
(message, notifyParent = false) => {
|
|
1292
1476
|
console.error("[payments-ui] Solana Pay QR error:", message);
|
|
1293
1477
|
clearTimers();
|
|
@@ -1298,7 +1482,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1298
1482
|
},
|
|
1299
1483
|
[clearTimers, resetState]
|
|
1300
1484
|
);
|
|
1301
|
-
const handleSuccess =
|
|
1485
|
+
const handleSuccess = React4.useCallback(
|
|
1302
1486
|
(status) => {
|
|
1303
1487
|
clearTimers();
|
|
1304
1488
|
resetState(null);
|
|
@@ -1312,7 +1496,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1312
1496
|
},
|
|
1313
1497
|
[clearTimers, resetState]
|
|
1314
1498
|
);
|
|
1315
|
-
const pollStatus =
|
|
1499
|
+
const pollStatus = React4.useCallback(
|
|
1316
1500
|
async (reference) => {
|
|
1317
1501
|
try {
|
|
1318
1502
|
const status = await client.getSolanaPayStatus(reference);
|
|
@@ -1331,7 +1515,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1331
1515
|
},
|
|
1332
1516
|
[handleError, handleSuccess, client]
|
|
1333
1517
|
);
|
|
1334
|
-
const startCountdown =
|
|
1518
|
+
const startCountdown = React4.useCallback(
|
|
1335
1519
|
(expiresAt, reference) => {
|
|
1336
1520
|
const updateTime = () => {
|
|
1337
1521
|
const remaining = Math.max(0, Math.floor(expiresAt - Date.now() / 1e3));
|
|
@@ -1346,7 +1530,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1346
1530
|
},
|
|
1347
1531
|
[handleError, pollStatus]
|
|
1348
1532
|
);
|
|
1349
|
-
const renderQr =
|
|
1533
|
+
const renderQr = React4.useCallback(async (qrIntent) => {
|
|
1350
1534
|
try {
|
|
1351
1535
|
const dataUri = await QRCode__default.default.toDataURL(qrIntent.url, {
|
|
1352
1536
|
width: 320,
|
|
@@ -1362,7 +1546,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1362
1546
|
handleError("Unable to render QR code");
|
|
1363
1547
|
}
|
|
1364
1548
|
}, [handleError]);
|
|
1365
|
-
|
|
1549
|
+
React4.useEffect(() => {
|
|
1366
1550
|
let cancelled = false;
|
|
1367
1551
|
const generateIntent = async () => {
|
|
1368
1552
|
clearTimers();
|
|
@@ -1426,7 +1610,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1426
1610
|
tokenSymbol,
|
|
1427
1611
|
refreshNonce
|
|
1428
1612
|
]);
|
|
1429
|
-
const refresh =
|
|
1613
|
+
const refresh = React4.useCallback(() => {
|
|
1430
1614
|
setRefreshNonce((value) => value + 1);
|
|
1431
1615
|
}, []);
|
|
1432
1616
|
return {
|
|
@@ -1438,7 +1622,7 @@ var useSolanaQrPayment = (options) => {
|
|
|
1438
1622
|
refresh
|
|
1439
1623
|
};
|
|
1440
1624
|
};
|
|
1441
|
-
var Card =
|
|
1625
|
+
var Card = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1442
1626
|
"div",
|
|
1443
1627
|
{
|
|
1444
1628
|
ref,
|
|
@@ -1450,7 +1634,7 @@ var Card = React15__namespace.forwardRef(({ className, ...props }, ref) => /* @_
|
|
|
1450
1634
|
}
|
|
1451
1635
|
));
|
|
1452
1636
|
Card.displayName = "Card";
|
|
1453
|
-
var CardHeader =
|
|
1637
|
+
var CardHeader = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1454
1638
|
"div",
|
|
1455
1639
|
{
|
|
1456
1640
|
ref,
|
|
@@ -1459,7 +1643,7 @@ var CardHeader = React15__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
1459
1643
|
}
|
|
1460
1644
|
));
|
|
1461
1645
|
CardHeader.displayName = "CardHeader";
|
|
1462
|
-
var CardTitle =
|
|
1646
|
+
var CardTitle = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1463
1647
|
"div",
|
|
1464
1648
|
{
|
|
1465
1649
|
ref,
|
|
@@ -1471,7 +1655,7 @@ var CardTitle = React15__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
1471
1655
|
}
|
|
1472
1656
|
));
|
|
1473
1657
|
CardTitle.displayName = "CardTitle";
|
|
1474
|
-
var CardDescription =
|
|
1658
|
+
var CardDescription = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1475
1659
|
"div",
|
|
1476
1660
|
{
|
|
1477
1661
|
ref,
|
|
@@ -1480,9 +1664,9 @@ var CardDescription = React15__namespace.forwardRef(({ className, ...props }, re
|
|
|
1480
1664
|
}
|
|
1481
1665
|
));
|
|
1482
1666
|
CardDescription.displayName = "CardDescription";
|
|
1483
|
-
var CardContent =
|
|
1667
|
+
var CardContent = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
1484
1668
|
CardContent.displayName = "CardContent";
|
|
1485
|
-
var CardFooter =
|
|
1669
|
+
var CardFooter = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1486
1670
|
"div",
|
|
1487
1671
|
{
|
|
1488
1672
|
ref,
|
|
@@ -1497,7 +1681,7 @@ var QRCodePayment = ({
|
|
|
1497
1681
|
onPaymentError,
|
|
1498
1682
|
onPaymentSuccess
|
|
1499
1683
|
}) => {
|
|
1500
|
-
const handleQrSuccess =
|
|
1684
|
+
const handleQrSuccess = React4__namespace.default.useCallback(
|
|
1501
1685
|
(paymentId, txId) => {
|
|
1502
1686
|
if (!paymentId && !txId) {
|
|
1503
1687
|
onPaymentError("Missing payment confirmation details");
|
|
@@ -1606,16 +1790,16 @@ var PaymentStatus = ({
|
|
|
1606
1790
|
};
|
|
1607
1791
|
var useSupportedTokens = () => {
|
|
1608
1792
|
const { client } = usePaymentContext();
|
|
1609
|
-
const [tokens, setTokens] =
|
|
1610
|
-
const [isLoading, setIsLoading] =
|
|
1611
|
-
const [error, setError] =
|
|
1612
|
-
const [lastFetched, setLastFetched] =
|
|
1793
|
+
const [tokens, setTokens] = React4.useState([]);
|
|
1794
|
+
const [isLoading, setIsLoading] = React4.useState(false);
|
|
1795
|
+
const [error, setError] = React4.useState(null);
|
|
1796
|
+
const [lastFetched, setLastFetched] = React4.useState(null);
|
|
1613
1797
|
const CACHE_DURATION = 5 * 60 * 1e3;
|
|
1614
|
-
const tokensRef =
|
|
1615
|
-
const lastFetchedRef =
|
|
1798
|
+
const tokensRef = React4.useRef(tokens);
|
|
1799
|
+
const lastFetchedRef = React4.useRef(lastFetched);
|
|
1616
1800
|
tokensRef.current = tokens;
|
|
1617
1801
|
lastFetchedRef.current = lastFetched;
|
|
1618
|
-
const fetchSupportedTokens =
|
|
1802
|
+
const fetchSupportedTokens = React4.useCallback(async () => {
|
|
1619
1803
|
if (tokensRef.current.length > 0 && lastFetchedRef.current && Date.now() - lastFetchedRef.current < CACHE_DURATION) {
|
|
1620
1804
|
return tokensRef.current;
|
|
1621
1805
|
}
|
|
@@ -1642,50 +1826,50 @@ var useSupportedTokens = () => {
|
|
|
1642
1826
|
setIsLoading(false);
|
|
1643
1827
|
}
|
|
1644
1828
|
}, [client]);
|
|
1645
|
-
|
|
1829
|
+
React4.useEffect(() => {
|
|
1646
1830
|
if (tokens.length === 0) {
|
|
1647
1831
|
fetchSupportedTokens();
|
|
1648
1832
|
}
|
|
1649
1833
|
}, [tokens.length, fetchSupportedTokens]);
|
|
1650
|
-
const getTokenBySymbol =
|
|
1834
|
+
const getTokenBySymbol = React4.useCallback(
|
|
1651
1835
|
(symbol) => {
|
|
1652
1836
|
return tokens.find((token) => token.symbol === symbol);
|
|
1653
1837
|
},
|
|
1654
1838
|
[tokens]
|
|
1655
1839
|
);
|
|
1656
|
-
const getTokenByMint =
|
|
1840
|
+
const getTokenByMint = React4.useCallback(
|
|
1657
1841
|
(mintAddress) => {
|
|
1658
1842
|
return tokens.find((token) => token.mint === mintAddress);
|
|
1659
1843
|
},
|
|
1660
1844
|
[tokens]
|
|
1661
1845
|
);
|
|
1662
|
-
const isTokenSupported =
|
|
1846
|
+
const isTokenSupported = React4.useCallback(
|
|
1663
1847
|
(symbol) => {
|
|
1664
1848
|
return tokens.some((token) => token.symbol === symbol);
|
|
1665
1849
|
},
|
|
1666
1850
|
[tokens]
|
|
1667
1851
|
);
|
|
1668
|
-
const getUSDCToken =
|
|
1852
|
+
const getUSDCToken = React4.useCallback(() => {
|
|
1669
1853
|
return getTokenBySymbol("USDC");
|
|
1670
1854
|
}, [getTokenBySymbol]);
|
|
1671
|
-
const getPYUSDToken =
|
|
1855
|
+
const getPYUSDToken = React4.useCallback(() => {
|
|
1672
1856
|
return getTokenBySymbol("PYUSD");
|
|
1673
1857
|
}, [getTokenBySymbol]);
|
|
1674
|
-
const getSOLToken =
|
|
1858
|
+
const getSOLToken = React4.useCallback(() => {
|
|
1675
1859
|
return getTokenBySymbol("SOL");
|
|
1676
1860
|
}, [getTokenBySymbol]);
|
|
1677
|
-
const getStablecoins =
|
|
1861
|
+
const getStablecoins = React4.useCallback(() => {
|
|
1678
1862
|
return tokens.filter((token) => ["USDC", "PYUSD"].includes(token.symbol));
|
|
1679
1863
|
}, [tokens]);
|
|
1680
|
-
const refreshTokens =
|
|
1864
|
+
const refreshTokens = React4.useCallback(async () => {
|
|
1681
1865
|
setLastFetched(null);
|
|
1682
1866
|
return await fetchSupportedTokens();
|
|
1683
1867
|
}, [fetchSupportedTokens]);
|
|
1684
|
-
const isCacheStale =
|
|
1868
|
+
const isCacheStale = React4.useCallback(() => {
|
|
1685
1869
|
if (!lastFetched) return true;
|
|
1686
1870
|
return Date.now() - lastFetched > CACHE_DURATION;
|
|
1687
1871
|
}, [lastFetched]);
|
|
1688
|
-
const getTokenDisplayInfo =
|
|
1872
|
+
const getTokenDisplayInfo = React4.useCallback((token) => {
|
|
1689
1873
|
return {
|
|
1690
1874
|
...token,
|
|
1691
1875
|
displayName: `${token.name} (${token.symbol})`,
|
|
@@ -1693,7 +1877,7 @@ var useSupportedTokens = () => {
|
|
|
1693
1877
|
decimalPlaces: token.decimals
|
|
1694
1878
|
};
|
|
1695
1879
|
}, []);
|
|
1696
|
-
const getTokenPrice =
|
|
1880
|
+
const getTokenPrice = React4.useCallback(
|
|
1697
1881
|
(symbol) => {
|
|
1698
1882
|
const token = getTokenBySymbol(symbol);
|
|
1699
1883
|
if (!token) return 0;
|
|
@@ -1702,7 +1886,7 @@ var useSupportedTokens = () => {
|
|
|
1702
1886
|
},
|
|
1703
1887
|
[getTokenBySymbol]
|
|
1704
1888
|
);
|
|
1705
|
-
const calculateTokenAmount =
|
|
1889
|
+
const calculateTokenAmount = React4.useCallback(
|
|
1706
1890
|
(usdAmount, tokenSymbol) => {
|
|
1707
1891
|
const token = getTokenBySymbol(tokenSymbol);
|
|
1708
1892
|
const price = getTokenPrice(tokenSymbol);
|
|
@@ -1713,7 +1897,7 @@ var useSupportedTokens = () => {
|
|
|
1713
1897
|
},
|
|
1714
1898
|
[getTokenBySymbol, getTokenPrice]
|
|
1715
1899
|
);
|
|
1716
|
-
const formatTokenAmount =
|
|
1900
|
+
const formatTokenAmount = React4.useCallback(
|
|
1717
1901
|
(amount, tokenSymbol) => {
|
|
1718
1902
|
const token = getTokenBySymbol(tokenSymbol);
|
|
1719
1903
|
if (!token) return "0";
|
|
@@ -1754,28 +1938,28 @@ var SolanaPaymentView = ({
|
|
|
1754
1938
|
onClose
|
|
1755
1939
|
}) => {
|
|
1756
1940
|
const { notifyStatus, notifyError, notifySuccess } = usePaymentNotifications();
|
|
1757
|
-
const [paymentState, setPaymentState] =
|
|
1758
|
-
const [errorMessage, setErrorMessage] =
|
|
1759
|
-
const [transactionId, setTransactionId] =
|
|
1760
|
-
const [tokenAmount, setTokenAmount] =
|
|
1761
|
-
const [selectedTokenSymbol, setSelectedTokenSymbol] =
|
|
1941
|
+
const [paymentState, setPaymentState] = React4.useState("selecting");
|
|
1942
|
+
const [errorMessage, setErrorMessage] = React4.useState(null);
|
|
1943
|
+
const [transactionId, setTransactionId] = React4.useState(null);
|
|
1944
|
+
const [tokenAmount, setTokenAmount] = React4.useState(0);
|
|
1945
|
+
const [selectedTokenSymbol, setSelectedTokenSymbol] = React4.useState(null);
|
|
1762
1946
|
const {
|
|
1763
1947
|
tokens,
|
|
1764
1948
|
isLoading: tokensLoading,
|
|
1765
1949
|
error: tokensError
|
|
1766
1950
|
} = useSupportedTokens();
|
|
1767
|
-
const selectedToken =
|
|
1951
|
+
const selectedToken = React4.useMemo(() => {
|
|
1768
1952
|
if (!tokens.length) return null;
|
|
1769
1953
|
const explicit = tokens.find((token) => token.symbol === selectedTokenSymbol);
|
|
1770
1954
|
return explicit || tokens[0];
|
|
1771
1955
|
}, [tokens, selectedTokenSymbol]);
|
|
1772
|
-
|
|
1956
|
+
React4.useEffect(() => {
|
|
1773
1957
|
if (!selectedTokenSymbol && tokens.length) {
|
|
1774
1958
|
const defaultToken = tokens.find((token) => token.symbol === "SOL") || tokens[0];
|
|
1775
1959
|
setSelectedTokenSymbol(defaultToken.symbol);
|
|
1776
1960
|
}
|
|
1777
1961
|
}, [tokens, selectedTokenSymbol]);
|
|
1778
|
-
const handlePaymentSuccess =
|
|
1962
|
+
const handlePaymentSuccess = React4.useCallback(
|
|
1779
1963
|
(result, txId) => {
|
|
1780
1964
|
const resolvedTx = txId || (typeof result === "string" ? result : result.transaction_id);
|
|
1781
1965
|
setTransactionId(resolvedTx);
|
|
@@ -1803,7 +1987,7 @@ var SolanaPaymentView = ({
|
|
|
1803
1987
|
},
|
|
1804
1988
|
[notifyStatus, notifySuccess, onSuccess]
|
|
1805
1989
|
);
|
|
1806
|
-
const handlePaymentError =
|
|
1990
|
+
const handlePaymentError = React4.useCallback(
|
|
1807
1991
|
(error) => {
|
|
1808
1992
|
setPaymentState("error");
|
|
1809
1993
|
setErrorMessage(error);
|
|
@@ -1813,22 +1997,22 @@ var SolanaPaymentView = ({
|
|
|
1813
1997
|
},
|
|
1814
1998
|
[notifyError, notifyStatus, onError]
|
|
1815
1999
|
);
|
|
1816
|
-
const resetState =
|
|
2000
|
+
const resetState = React4.useCallback(() => {
|
|
1817
2001
|
setPaymentState("selecting");
|
|
1818
2002
|
setErrorMessage(null);
|
|
1819
2003
|
setTransactionId(null);
|
|
1820
2004
|
}, []);
|
|
1821
|
-
const handleRetry =
|
|
2005
|
+
const handleRetry = React4.useCallback(() => {
|
|
1822
2006
|
resetState();
|
|
1823
2007
|
}, [resetState]);
|
|
1824
|
-
const handleClose =
|
|
2008
|
+
const handleClose = React4.useCallback(() => {
|
|
1825
2009
|
if (paymentState === "processing" || paymentState === "confirming") {
|
|
1826
2010
|
return;
|
|
1827
2011
|
}
|
|
1828
2012
|
resetState();
|
|
1829
2013
|
onClose?.();
|
|
1830
2014
|
}, [paymentState, onClose, resetState]);
|
|
1831
|
-
|
|
2015
|
+
React4.useEffect(() => {
|
|
1832
2016
|
if (!selectedToken || usdAmount === 0) {
|
|
1833
2017
|
setTokenAmount(0);
|
|
1834
2018
|
return;
|
|
@@ -1840,7 +2024,7 @@ var SolanaPaymentView = ({
|
|
|
1840
2024
|
}
|
|
1841
2025
|
setTokenAmount(usdAmount / price);
|
|
1842
2026
|
}, [usdAmount, selectedToken]);
|
|
1843
|
-
const handleTokenChange =
|
|
2027
|
+
const handleTokenChange = React4.useCallback((value) => {
|
|
1844
2028
|
setSelectedTokenSymbol(value);
|
|
1845
2029
|
}, []);
|
|
1846
2030
|
const renderBody = () => {
|
|
@@ -1931,35 +2115,63 @@ var SolanaPaymentView = ({
|
|
|
1931
2115
|
renderBody()
|
|
1932
2116
|
] });
|
|
1933
2117
|
};
|
|
2118
|
+
var defaultPaymentExperienceTranslations = {
|
|
2119
|
+
...defaultCardDetailsFormTranslations,
|
|
2120
|
+
useSavedCardTab: "Use saved card",
|
|
2121
|
+
addNewCardTab: "Add new card",
|
|
2122
|
+
savedUnavailable: "Saved payment methods are unavailable right now. Add a new card to get started.",
|
|
2123
|
+
payWithSavedCard: "Pay with selected card",
|
|
2124
|
+
processingSavedCard: "Processing...",
|
|
2125
|
+
savedErrorFallback: "Unable to complete payment with saved card",
|
|
2126
|
+
newCardUnavailable: "Select a subscription plan to add a new card.",
|
|
2127
|
+
payNow: "Pay now",
|
|
2128
|
+
storedLoadingCards: "Loading cards...",
|
|
2129
|
+
storedNoSavedMethods: "No saved payment methods yet.",
|
|
2130
|
+
storedSelectedLabel: "Selected",
|
|
2131
|
+
storedUseCardLabel: "Use card",
|
|
2132
|
+
payWithCcbill: "Pay with CCBill",
|
|
2133
|
+
processingCcbill: "Redirecting...",
|
|
2134
|
+
errors: {}
|
|
2135
|
+
};
|
|
1934
2136
|
var PaymentExperience = ({
|
|
1935
2137
|
priceId,
|
|
1936
2138
|
usdAmount,
|
|
1937
2139
|
onNewCardPayment,
|
|
1938
2140
|
onSavedMethodPayment,
|
|
2141
|
+
onCcbillPayment,
|
|
1939
2142
|
enableNewCard = true,
|
|
1940
2143
|
enableStoredMethods = true,
|
|
1941
2144
|
enableSolanaPay = true,
|
|
1942
2145
|
onSolanaSuccess,
|
|
1943
2146
|
onSolanaError,
|
|
1944
|
-
initialMode = "cards"
|
|
2147
|
+
initialMode = "cards",
|
|
2148
|
+
translations
|
|
1945
2149
|
}) => {
|
|
2150
|
+
const t = {
|
|
2151
|
+
...defaultPaymentExperienceTranslations,
|
|
2152
|
+
...translations
|
|
2153
|
+
};
|
|
1946
2154
|
const showNewCard = enableNewCard && Boolean(onNewCardPayment);
|
|
1947
2155
|
const showStored = enableStoredMethods && Boolean(onSavedMethodPayment);
|
|
2156
|
+
const showCcbill = showNewCard && Boolean(onCcbillPayment);
|
|
1948
2157
|
const defaultTab = showStored ? "saved" : "new";
|
|
1949
|
-
const [activeTab, setActiveTab] =
|
|
1950
|
-
const [mode, setMode] =
|
|
2158
|
+
const [activeTab, setActiveTab] = React4.useState(defaultTab);
|
|
2159
|
+
const [mode, setMode] = React4.useState(
|
|
1951
2160
|
() => initialMode === "solana" && enableSolanaPay ? "solana" : "cards"
|
|
1952
2161
|
);
|
|
1953
|
-
const [selectedMethodId, setSelectedMethodId] =
|
|
1954
|
-
const [savedStatus, setSavedStatus] =
|
|
1955
|
-
const [savedError, setSavedError] =
|
|
1956
|
-
const [newCardStatus, setNewCardStatus] =
|
|
1957
|
-
const [newCardError, setNewCardError] =
|
|
2162
|
+
const [selectedMethodId, setSelectedMethodId] = React4.useState(null);
|
|
2163
|
+
const [savedStatus, setSavedStatus] = React4.useState("idle");
|
|
2164
|
+
const [savedError, setSavedError] = React4.useState(null);
|
|
2165
|
+
const [newCardStatus, setNewCardStatus] = React4.useState("idle");
|
|
2166
|
+
const [newCardError, setNewCardError] = React4.useState(null);
|
|
2167
|
+
const [billingDetails, setBillingDetails] = React4.useState(null);
|
|
2168
|
+
const [ccbillStatus, setCcbillStatus] = React4.useState("idle");
|
|
2169
|
+
const [ccbillError, setCcbillError] = React4.useState(null);
|
|
1958
2170
|
const { notifyStatus, notifyError } = usePaymentNotifications();
|
|
1959
|
-
|
|
2171
|
+
React4.useEffect(() => {
|
|
1960
2172
|
setActiveTab(showStored ? "saved" : "new");
|
|
1961
2173
|
}, [showStored]);
|
|
1962
|
-
|
|
2174
|
+
React4.useEffect(() => {
|
|
1963
2175
|
if (!enableSolanaPay) {
|
|
1964
2176
|
setMode("cards");
|
|
1965
2177
|
return;
|
|
@@ -1970,12 +2182,30 @@ var PaymentExperience = ({
|
|
|
1970
2182
|
setMode("cards");
|
|
1971
2183
|
}
|
|
1972
2184
|
}, [enableSolanaPay, initialMode]);
|
|
1973
|
-
|
|
2185
|
+
React4.useEffect(() => {
|
|
2186
|
+
if (!showNewCard) {
|
|
2187
|
+
setBillingDetails(null);
|
|
2188
|
+
setCcbillStatus("idle");
|
|
2189
|
+
setCcbillError(null);
|
|
2190
|
+
}
|
|
2191
|
+
}, [showNewCard]);
|
|
2192
|
+
const handleBillingChange = React4.useCallback((billing) => {
|
|
2193
|
+
setBillingDetails(billing);
|
|
2194
|
+
setCcbillError(null);
|
|
2195
|
+
setCcbillStatus("idle");
|
|
2196
|
+
}, []);
|
|
2197
|
+
const isBillingComplete = React4.useCallback((billing) => {
|
|
2198
|
+
if (!billing) return false;
|
|
2199
|
+
return Boolean(
|
|
2200
|
+
billing.firstName.trim() && billing.lastName.trim() && billing.address1.trim() && billing.city.trim() && billing.postalCode.trim() && billing.country.trim() && billing.email.trim()
|
|
2201
|
+
);
|
|
2202
|
+
}, []);
|
|
2203
|
+
const handleMethodSelect = React4.useCallback((method) => {
|
|
1974
2204
|
setSelectedMethodId(method.id);
|
|
1975
2205
|
setSavedStatus("idle");
|
|
1976
2206
|
setSavedError(null);
|
|
1977
2207
|
}, []);
|
|
1978
|
-
const handleSavedPayment =
|
|
2208
|
+
const handleSavedPayment = React4.useCallback(async () => {
|
|
1979
2209
|
if (!onSavedMethodPayment || !selectedMethodId) return;
|
|
1980
2210
|
try {
|
|
1981
2211
|
setSavedStatus("processing");
|
|
@@ -1988,14 +2218,18 @@ var PaymentExperience = ({
|
|
|
1988
2218
|
setSavedStatus("success");
|
|
1989
2219
|
notifyStatus("success", { source: "saved-payment" });
|
|
1990
2220
|
} catch (error) {
|
|
1991
|
-
const message =
|
|
2221
|
+
const message = resolveErrorMessageByCode(
|
|
2222
|
+
error,
|
|
2223
|
+
t.errors,
|
|
2224
|
+
t.savedErrorFallback
|
|
2225
|
+
);
|
|
1992
2226
|
setSavedStatus("error");
|
|
1993
2227
|
setSavedError(message);
|
|
1994
2228
|
notifyStatus("error", { source: "saved-payment" });
|
|
1995
2229
|
notifyError(message);
|
|
1996
2230
|
}
|
|
1997
|
-
}, [notifyError, notifyStatus, onSavedMethodPayment, selectedMethodId, usdAmount]);
|
|
1998
|
-
const handleNewCardTokenize =
|
|
2231
|
+
}, [notifyError, notifyStatus, onSavedMethodPayment, selectedMethodId, t, usdAmount]);
|
|
2232
|
+
const handleNewCardTokenize = React4.useCallback(
|
|
1999
2233
|
async (token, billing) => {
|
|
2000
2234
|
if (!onNewCardPayment) return;
|
|
2001
2235
|
try {
|
|
@@ -2006,30 +2240,71 @@ var PaymentExperience = ({
|
|
|
2006
2240
|
setNewCardStatus("success");
|
|
2007
2241
|
notifyStatus("success", { source: "new-card" });
|
|
2008
2242
|
} catch (error) {
|
|
2009
|
-
const message =
|
|
2243
|
+
const message = resolveErrorMessageByCode(
|
|
2244
|
+
error,
|
|
2245
|
+
t.errors,
|
|
2246
|
+
"Unable to complete payment"
|
|
2247
|
+
);
|
|
2010
2248
|
setNewCardStatus("error");
|
|
2011
2249
|
setNewCardError(message);
|
|
2012
2250
|
notifyStatus("error", { source: "new-card" });
|
|
2013
2251
|
notifyError(message);
|
|
2014
2252
|
}
|
|
2015
2253
|
},
|
|
2016
|
-
[notifyError, notifyStatus, onNewCardPayment]
|
|
2254
|
+
[notifyError, notifyStatus, onNewCardPayment, t]
|
|
2017
2255
|
);
|
|
2018
|
-
|
|
2256
|
+
const handleCcbillPayment = React4.useCallback(async () => {
|
|
2257
|
+
if (!onCcbillPayment) return;
|
|
2258
|
+
if (!billingDetails || !isBillingComplete(billingDetails)) {
|
|
2259
|
+
const message = t.errorRequiredFields;
|
|
2260
|
+
setActiveTab("new");
|
|
2261
|
+
setCcbillStatus("error");
|
|
2262
|
+
setCcbillError(message);
|
|
2263
|
+
notifyStatus("error", { source: "ccbill" });
|
|
2264
|
+
notifyError(message);
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
try {
|
|
2268
|
+
setCcbillStatus("processing");
|
|
2269
|
+
setCcbillError(null);
|
|
2270
|
+
notifyStatus("processing", { source: "ccbill" });
|
|
2271
|
+
await onCcbillPayment({ billing: billingDetails });
|
|
2272
|
+
setCcbillStatus("success");
|
|
2273
|
+
notifyStatus("success", { source: "ccbill" });
|
|
2274
|
+
} catch (error) {
|
|
2275
|
+
const message = resolveErrorMessageByCode(
|
|
2276
|
+
error,
|
|
2277
|
+
t.errors,
|
|
2278
|
+
"Unable to start CCBill checkout"
|
|
2279
|
+
);
|
|
2280
|
+
setCcbillStatus("error");
|
|
2281
|
+
setCcbillError(message);
|
|
2282
|
+
notifyStatus("error", { source: "ccbill" });
|
|
2283
|
+
notifyError(message);
|
|
2284
|
+
}
|
|
2285
|
+
}, [
|
|
2286
|
+
billingDetails,
|
|
2287
|
+
isBillingComplete,
|
|
2288
|
+
notifyError,
|
|
2289
|
+
notifyStatus,
|
|
2290
|
+
onCcbillPayment,
|
|
2291
|
+
t
|
|
2292
|
+
]);
|
|
2293
|
+
React4.useCallback(() => {
|
|
2019
2294
|
if (!enableSolanaPay) return;
|
|
2020
2295
|
setMode("solana");
|
|
2021
2296
|
}, [enableSolanaPay]);
|
|
2022
|
-
const exitSolanaView =
|
|
2297
|
+
const exitSolanaView = React4.useCallback(() => {
|
|
2023
2298
|
setMode("cards");
|
|
2024
2299
|
}, []);
|
|
2025
|
-
const handleSolanaSuccess =
|
|
2300
|
+
const handleSolanaSuccess = React4.useCallback(
|
|
2026
2301
|
(result) => {
|
|
2027
2302
|
onSolanaSuccess?.(result);
|
|
2028
2303
|
exitSolanaView();
|
|
2029
2304
|
},
|
|
2030
2305
|
[exitSolanaView, onSolanaSuccess]
|
|
2031
2306
|
);
|
|
2032
|
-
const handleSolanaError =
|
|
2307
|
+
const handleSolanaError = React4.useCallback(
|
|
2033
2308
|
(error) => {
|
|
2034
2309
|
onSolanaError?.(error);
|
|
2035
2310
|
},
|
|
@@ -2037,14 +2312,20 @@ var PaymentExperience = ({
|
|
|
2037
2312
|
);
|
|
2038
2313
|
const renderSavedTab = () => {
|
|
2039
2314
|
if (!showStored) {
|
|
2040
|
-
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children:
|
|
2315
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: t.savedUnavailable });
|
|
2041
2316
|
}
|
|
2042
2317
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
2043
2318
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2044
2319
|
StoredPaymentMethods,
|
|
2045
2320
|
{
|
|
2046
2321
|
selectedMethodId,
|
|
2047
|
-
onMethodSelect: handleMethodSelect
|
|
2322
|
+
onMethodSelect: handleMethodSelect,
|
|
2323
|
+
translations: {
|
|
2324
|
+
loadingCards: t.storedLoadingCards,
|
|
2325
|
+
noSavedMethods: t.storedNoSavedMethods,
|
|
2326
|
+
selectedLabel: t.storedSelectedLabel,
|
|
2327
|
+
useCardLabel: t.storedUseCardLabel
|
|
2328
|
+
}
|
|
2048
2329
|
}
|
|
2049
2330
|
),
|
|
2050
2331
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2053,7 +2334,7 @@ var PaymentExperience = ({
|
|
|
2053
2334
|
className: "w-full",
|
|
2054
2335
|
disabled: !selectedMethodId || savedStatus === "processing",
|
|
2055
2336
|
onClick: handleSavedPayment,
|
|
2056
|
-
children: savedStatus === "processing" ?
|
|
2337
|
+
children: savedStatus === "processing" ? t.processingSavedCard : t.payWithSavedCard
|
|
2057
2338
|
}
|
|
2058
2339
|
),
|
|
2059
2340
|
savedError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: savedError })
|
|
@@ -2061,29 +2342,50 @@ var PaymentExperience = ({
|
|
|
2061
2342
|
};
|
|
2062
2343
|
const renderNewTab = () => {
|
|
2063
2344
|
if (!showNewCard) {
|
|
2064
|
-
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children:
|
|
2345
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: t.newCardUnavailable });
|
|
2065
2346
|
}
|
|
2066
2347
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2067
2348
|
CardDetailsForm,
|
|
2068
2349
|
{
|
|
2069
2350
|
visible: true,
|
|
2070
|
-
submitLabel:
|
|
2351
|
+
submitLabel: t.payNow,
|
|
2071
2352
|
externalError: newCardError,
|
|
2072
2353
|
onTokenize: handleNewCardTokenize,
|
|
2073
|
-
submitting: newCardStatus === "processing"
|
|
2354
|
+
submitting: newCardStatus === "processing",
|
|
2355
|
+
onBillingChange: handleBillingChange,
|
|
2356
|
+
translations: t
|
|
2074
2357
|
}
|
|
2075
2358
|
);
|
|
2076
2359
|
};
|
|
2077
2360
|
const renderCardExperience = () => /* @__PURE__ */ jsxRuntime.jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, children: [
|
|
2078
2361
|
/* @__PURE__ */ jsxRuntime.jsxs(TabsList, { className: "w-full rounded-md mb-4", children: [
|
|
2079
|
-
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className:
|
|
2080
|
-
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className:
|
|
2362
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className: "cursor-pointer", value: "saved", children: t.useSavedCardTab }),
|
|
2363
|
+
/* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { className: "cursor-pointer", value: "new", children: t.addNewCardTab })
|
|
2081
2364
|
] }),
|
|
2082
2365
|
/* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "saved", children: renderSavedTab() }),
|
|
2083
2366
|
/* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "new", children: renderNewTab() })
|
|
2084
2367
|
] });
|
|
2368
|
+
const renderCcbillAction = () => {
|
|
2369
|
+
if (!showCcbill) return null;
|
|
2370
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 border-t border-white/10 pt-4", children: [
|
|
2371
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2372
|
+
Button,
|
|
2373
|
+
{
|
|
2374
|
+
className: "w-full",
|
|
2375
|
+
variant: "outline",
|
|
2376
|
+
disabled: ccbillStatus === "processing",
|
|
2377
|
+
onClick: handleCcbillPayment,
|
|
2378
|
+
children: ccbillStatus === "processing" ? t.processingCcbill : t.payWithCcbill
|
|
2379
|
+
}
|
|
2380
|
+
),
|
|
2381
|
+
ccbillError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: ccbillError })
|
|
2382
|
+
] });
|
|
2383
|
+
};
|
|
2085
2384
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pt-4", children: [
|
|
2086
|
-
mode === "cards" &&
|
|
2385
|
+
mode === "cards" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2386
|
+
renderCardExperience(),
|
|
2387
|
+
renderCcbillAction()
|
|
2388
|
+
] }),
|
|
2087
2389
|
mode === "solana" && enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2088
2390
|
SolanaPaymentView,
|
|
2089
2391
|
{
|
|
@@ -2132,20 +2434,20 @@ var useSubscriptionActions = () => {
|
|
|
2132
2434
|
}
|
|
2133
2435
|
return priceId;
|
|
2134
2436
|
};
|
|
2135
|
-
const subscribeWithCard =
|
|
2437
|
+
const subscribeWithCard = React4.useCallback(
|
|
2136
2438
|
async ({
|
|
2137
2439
|
priceId,
|
|
2138
|
-
processor = "
|
|
2440
|
+
processor = "mobius",
|
|
2139
2441
|
provider,
|
|
2140
2442
|
paymentToken,
|
|
2141
2443
|
billing,
|
|
2142
2444
|
idempotencyKey
|
|
2143
2445
|
}) => {
|
|
2144
|
-
|
|
2145
|
-
|
|
2446
|
+
if (processor !== "ccbill" && !paymentToken) {
|
|
2447
|
+
throw new Error("payments-ui: payment token is required for card checkout");
|
|
2448
|
+
}
|
|
2449
|
+
const payment = {
|
|
2146
2450
|
processor,
|
|
2147
|
-
provider,
|
|
2148
|
-
payment_token: paymentToken,
|
|
2149
2451
|
email: billing.email,
|
|
2150
2452
|
first_name: billing.firstName,
|
|
2151
2453
|
last_name: billing.lastName,
|
|
@@ -2155,14 +2457,25 @@ var useSubscriptionActions = () => {
|
|
|
2155
2457
|
zip: billing.postalCode,
|
|
2156
2458
|
country: billing.country
|
|
2157
2459
|
};
|
|
2460
|
+
if (paymentToken) {
|
|
2461
|
+
payment.payment_token = paymentToken;
|
|
2462
|
+
payment.last_four = billing.last_four;
|
|
2463
|
+
payment.card_type = billing.card_type;
|
|
2464
|
+
payment.expiry_date = billing.expiry_date;
|
|
2465
|
+
}
|
|
2466
|
+
const payload = {
|
|
2467
|
+
price_id: ensurePrice(priceId),
|
|
2468
|
+
provider,
|
|
2469
|
+
payment
|
|
2470
|
+
};
|
|
2158
2471
|
return client.checkout(payload, idempotencyKey);
|
|
2159
2472
|
},
|
|
2160
2473
|
[client]
|
|
2161
2474
|
);
|
|
2162
|
-
const subscribeWithSavedMethod =
|
|
2475
|
+
const subscribeWithSavedMethod = React4.useCallback(
|
|
2163
2476
|
async ({
|
|
2164
2477
|
priceId,
|
|
2165
|
-
processor = "
|
|
2478
|
+
processor = "mobius",
|
|
2166
2479
|
provider,
|
|
2167
2480
|
paymentMethodId,
|
|
2168
2481
|
email,
|
|
@@ -2170,16 +2483,18 @@ var useSubscriptionActions = () => {
|
|
|
2170
2483
|
}) => {
|
|
2171
2484
|
const payload = {
|
|
2172
2485
|
price_id: ensurePrice(priceId),
|
|
2173
|
-
processor,
|
|
2174
2486
|
provider,
|
|
2175
|
-
|
|
2176
|
-
|
|
2487
|
+
payment: {
|
|
2488
|
+
processor,
|
|
2489
|
+
payment_method_id: paymentMethodId,
|
|
2490
|
+
email
|
|
2491
|
+
}
|
|
2177
2492
|
};
|
|
2178
2493
|
return client.checkout(payload, idempotencyKey);
|
|
2179
2494
|
},
|
|
2180
2495
|
[client]
|
|
2181
2496
|
);
|
|
2182
|
-
const subscribeWithCCBill =
|
|
2497
|
+
const subscribeWithCCBill = React4.useCallback(
|
|
2183
2498
|
async ({
|
|
2184
2499
|
priceId,
|
|
2185
2500
|
email,
|
|
@@ -2192,12 +2507,14 @@ var useSubscriptionActions = () => {
|
|
|
2192
2507
|
}) => {
|
|
2193
2508
|
const payload = {
|
|
2194
2509
|
price_id: ensurePrice(priceId),
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2510
|
+
payment: {
|
|
2511
|
+
processor,
|
|
2512
|
+
email,
|
|
2513
|
+
first_name: firstName,
|
|
2514
|
+
last_name: lastName,
|
|
2515
|
+
zip: zipCode,
|
|
2516
|
+
country
|
|
2517
|
+
}
|
|
2201
2518
|
};
|
|
2202
2519
|
return client.checkout(payload, idempotencyKey);
|
|
2203
2520
|
},
|
|
@@ -2209,6 +2526,11 @@ var useSubscriptionActions = () => {
|
|
|
2209
2526
|
subscribeWithCCBill
|
|
2210
2527
|
};
|
|
2211
2528
|
};
|
|
2529
|
+
var defaultTranslations2 = {
|
|
2530
|
+
...defaultPaymentExperienceTranslations,
|
|
2531
|
+
title: "Checkout",
|
|
2532
|
+
selectPlanMessage: "Select a subscription plan to continue."
|
|
2533
|
+
};
|
|
2212
2534
|
var SubscriptionCheckoutModal = ({
|
|
2213
2535
|
open,
|
|
2214
2536
|
onOpenChange,
|
|
@@ -2223,17 +2545,22 @@ var SubscriptionCheckoutModal = ({
|
|
|
2223
2545
|
enableSolanaPay = true,
|
|
2224
2546
|
onSolanaSuccess,
|
|
2225
2547
|
onSolanaError,
|
|
2226
|
-
initialMode = "cards"
|
|
2548
|
+
initialMode = "cards",
|
|
2549
|
+
translations
|
|
2227
2550
|
}) => {
|
|
2228
|
-
const [showSuccess, setShowSuccess] =
|
|
2229
|
-
const [idempotencyKey, setIdempotencyKey] =
|
|
2551
|
+
const [showSuccess, setShowSuccess] = React4.useState(false);
|
|
2552
|
+
const [idempotencyKey, setIdempotencyKey] = React4.useState(() => crypto.randomUUID());
|
|
2230
2553
|
const { subscribeWithCard, subscribeWithSavedMethod } = useSubscriptionActions();
|
|
2231
|
-
|
|
2554
|
+
const t = {
|
|
2555
|
+
...defaultTranslations2,
|
|
2556
|
+
...translations
|
|
2557
|
+
};
|
|
2558
|
+
React4.useEffect(() => {
|
|
2232
2559
|
if (open) {
|
|
2233
2560
|
setIdempotencyKey(crypto.randomUUID());
|
|
2234
2561
|
}
|
|
2235
2562
|
}, [open, priceId]);
|
|
2236
|
-
const handleClose =
|
|
2563
|
+
const handleClose = React4.useCallback(
|
|
2237
2564
|
(nextOpen) => {
|
|
2238
2565
|
onOpenChange(nextOpen);
|
|
2239
2566
|
if (!nextOpen) setShowSuccess(false);
|
|
@@ -2251,13 +2578,31 @@ var SubscriptionCheckoutModal = ({
|
|
|
2251
2578
|
console.debug("[payments-ui] subscription success", result);
|
|
2252
2579
|
}
|
|
2253
2580
|
};
|
|
2254
|
-
const
|
|
2255
|
-
if (status === "blocked") {
|
|
2256
|
-
throw new Error(message || "This subscription cannot be completed right now.");
|
|
2581
|
+
const handleCheckoutResponse = (response) => {
|
|
2582
|
+
if (response.status === "blocked") {
|
|
2583
|
+
throw new Error(response.message || "This subscription cannot be completed right now.");
|
|
2257
2584
|
}
|
|
2258
|
-
|
|
2259
|
-
|
|
2585
|
+
const nextAction = response.next_action;
|
|
2586
|
+
if (nextAction?.type === "redirect_to_url") {
|
|
2587
|
+
const redirectUrl = nextAction.redirect_to_url?.url || response.payment?.redirect_url;
|
|
2588
|
+
if (!redirectUrl) {
|
|
2589
|
+
throw new Error(response.message || "Checkout requires a redirect URL.");
|
|
2590
|
+
}
|
|
2591
|
+
if (typeof window !== "undefined") {
|
|
2592
|
+
window.location.assign(redirectUrl);
|
|
2593
|
+
}
|
|
2594
|
+
return;
|
|
2260
2595
|
}
|
|
2596
|
+
if (response.payment?.redirect_url) {
|
|
2597
|
+
if (typeof window !== "undefined") {
|
|
2598
|
+
window.location.assign(response.payment.redirect_url);
|
|
2599
|
+
}
|
|
2600
|
+
return;
|
|
2601
|
+
}
|
|
2602
|
+
if (nextAction && nextAction.type !== "none") {
|
|
2603
|
+
throw new Error(response.message || "Unsupported checkout action.");
|
|
2604
|
+
}
|
|
2605
|
+
notifySuccess();
|
|
2261
2606
|
};
|
|
2262
2607
|
const handleNewCardPayment = async ({ token, billing }) => {
|
|
2263
2608
|
const response = await subscribeWithCard({
|
|
@@ -2267,8 +2612,7 @@ var SubscriptionCheckoutModal = ({
|
|
|
2267
2612
|
paymentToken: token,
|
|
2268
2613
|
priceId: ensurePrice()
|
|
2269
2614
|
});
|
|
2270
|
-
|
|
2271
|
-
notifySuccess();
|
|
2615
|
+
handleCheckoutResponse(response);
|
|
2272
2616
|
};
|
|
2273
2617
|
const handleSavedMethodPayment = async ({ paymentMethodId }) => {
|
|
2274
2618
|
const response = await subscribeWithSavedMethod({
|
|
@@ -2278,8 +2622,16 @@ var SubscriptionCheckoutModal = ({
|
|
|
2278
2622
|
email: userEmail ?? "",
|
|
2279
2623
|
idempotencyKey
|
|
2280
2624
|
});
|
|
2281
|
-
|
|
2282
|
-
|
|
2625
|
+
handleCheckoutResponse(response);
|
|
2626
|
+
};
|
|
2627
|
+
const handleCcbillPayment = async ({ billing }) => {
|
|
2628
|
+
const response = await subscribeWithCard({
|
|
2629
|
+
billing,
|
|
2630
|
+
idempotencyKey,
|
|
2631
|
+
processor: "ccbill",
|
|
2632
|
+
priceId: ensurePrice()
|
|
2633
|
+
});
|
|
2634
|
+
handleCheckoutResponse(response);
|
|
2283
2635
|
};
|
|
2284
2636
|
const solanaSuccess = (result) => {
|
|
2285
2637
|
notifySuccess(result);
|
|
@@ -2295,11 +2647,11 @@ var SubscriptionCheckoutModal = ({
|
|
|
2295
2647
|
{
|
|
2296
2648
|
className: "z-[100] max-w-xl max-h-[90vh] overflow-y-auto border border-white/20 p-6 backdrop-blur-xl bg-background-regular rounded-md [&::-webkit-scrollbar]:hidden",
|
|
2297
2649
|
children: [
|
|
2298
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "flex items-center gap-2 text-foreground", children:
|
|
2650
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "flex items-center gap-2 text-foreground", children: t.title }) }),
|
|
2299
2651
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: !priceId ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-center px-3 py-2 text-sm text-destructive", children: [
|
|
2300
2652
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
|
|
2301
2653
|
" ",
|
|
2302
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
2654
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t.selectPlanMessage })
|
|
2303
2655
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2304
2656
|
PaymentExperience,
|
|
2305
2657
|
{
|
|
@@ -2312,7 +2664,9 @@ var SubscriptionCheckoutModal = ({
|
|
|
2312
2664
|
enableStoredMethods: Boolean(priceId),
|
|
2313
2665
|
enableSolanaPay: enableSolanaPay && Boolean(priceId),
|
|
2314
2666
|
onNewCardPayment: priceId ? handleNewCardPayment : void 0,
|
|
2315
|
-
onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0
|
|
2667
|
+
onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
|
|
2668
|
+
onCcbillPayment: priceId ? handleCcbillPayment : void 0,
|
|
2669
|
+
translations: t
|
|
2316
2670
|
}
|
|
2317
2671
|
) })
|
|
2318
2672
|
]
|
|
@@ -2322,7 +2676,9 @@ var SubscriptionCheckoutModal = ({
|
|
|
2322
2676
|
SubscriptionSuccessDialog,
|
|
2323
2677
|
{
|
|
2324
2678
|
open: showSuccess,
|
|
2325
|
-
onClose: () =>
|
|
2679
|
+
onClose: () => {
|
|
2680
|
+
setShowSuccess(false);
|
|
2681
|
+
},
|
|
2326
2682
|
planName,
|
|
2327
2683
|
amountLabel: amountLabel ?? `$${usdAmount.toFixed(2)}`,
|
|
2328
2684
|
billingPeriodLabel
|
|
@@ -2343,7 +2699,7 @@ var wallets = [
|
|
|
2343
2699
|
}
|
|
2344
2700
|
];
|
|
2345
2701
|
var WalletModal = ({ open, onOpenChange }) => {
|
|
2346
|
-
const [expandedWallet, setExpandedWallet] =
|
|
2702
|
+
const [expandedWallet, setExpandedWallet] = React4.useState(null);
|
|
2347
2703
|
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "z-[100] w-full max-w-lg max-h-[90vh] overflow-y-auto rounded-md border border-white/20 p-0 backdrop-blur-xl bg-background-regular shadow-2xl [&::-webkit-scrollbar]:hidden", children: [
|
|
2348
2704
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "border-b border-white/10 bg-gradient-to-r from-primary/10 via-transparent to-transparent px-6 py-5 text-left", children: [
|
|
2349
2705
|
/* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex items-center gap-2 text-foreground", children: [
|
|
@@ -2399,17 +2755,17 @@ var createDialogState = () => ({
|
|
|
2399
2755
|
isOpen: false,
|
|
2400
2756
|
props: null
|
|
2401
2757
|
});
|
|
2402
|
-
var PaymentsDialogContext =
|
|
2758
|
+
var PaymentsDialogContext = React4.createContext(void 0);
|
|
2403
2759
|
var PaymentsDialogProvider = ({
|
|
2404
2760
|
children
|
|
2405
2761
|
}) => {
|
|
2406
|
-
const [checkoutState, setCheckoutState] =
|
|
2762
|
+
const [checkoutState, setCheckoutState] = React4.useState(
|
|
2407
2763
|
() => createDialogState()
|
|
2408
2764
|
);
|
|
2409
|
-
const [walletState, setWalletState] =
|
|
2765
|
+
const [walletState, setWalletState] = React4.useState(
|
|
2410
2766
|
() => createDialogState()
|
|
2411
2767
|
);
|
|
2412
|
-
const contextValue =
|
|
2768
|
+
const contextValue = React4.useMemo(() => {
|
|
2413
2769
|
const openCheckout = (options) => setCheckoutState({
|
|
2414
2770
|
isOpen: true,
|
|
2415
2771
|
props: options
|
|
@@ -2463,18 +2819,18 @@ var PaymentsDialogProvider = ({
|
|
|
2463
2819
|
] });
|
|
2464
2820
|
};
|
|
2465
2821
|
var usePaymentDialogs = () => {
|
|
2466
|
-
const context =
|
|
2822
|
+
const context = React4.useContext(PaymentsDialogContext);
|
|
2467
2823
|
if (!context) {
|
|
2468
2824
|
throw new Error("usePaymentDialogs must be used within PaymentProvider");
|
|
2469
2825
|
}
|
|
2470
2826
|
return context;
|
|
2471
2827
|
};
|
|
2472
|
-
var PaymentContext =
|
|
2828
|
+
var PaymentContext = React4.createContext(void 0);
|
|
2473
2829
|
var PaymentProvider = ({
|
|
2474
2830
|
config,
|
|
2475
2831
|
children
|
|
2476
2832
|
}) => {
|
|
2477
|
-
const queryClient =
|
|
2833
|
+
const queryClient = React4.useMemo(() => {
|
|
2478
2834
|
return new reactQuery.QueryClient({
|
|
2479
2835
|
defaultOptions: {
|
|
2480
2836
|
queries: {
|
|
@@ -2489,7 +2845,7 @@ var PaymentProvider = ({
|
|
|
2489
2845
|
}
|
|
2490
2846
|
});
|
|
2491
2847
|
}, []);
|
|
2492
|
-
const client =
|
|
2848
|
+
const client = React4.useMemo(() => {
|
|
2493
2849
|
const authProvider = config.getAuthToken ? async () => {
|
|
2494
2850
|
try {
|
|
2495
2851
|
const result = config.getAuthToken?.();
|
|
@@ -2513,12 +2869,12 @@ var PaymentProvider = ({
|
|
|
2513
2869
|
defaultHeaders: config.defaultHeaders
|
|
2514
2870
|
});
|
|
2515
2871
|
}, [config]);
|
|
2516
|
-
const solanaEndpoint =
|
|
2872
|
+
const solanaEndpoint = React4.useMemo(() => {
|
|
2517
2873
|
if (config.solana?.endpoint) return config.solana.endpoint;
|
|
2518
2874
|
const network = config.solana?.network ?? walletAdapterBase.WalletAdapterNetwork.Mainnet;
|
|
2519
2875
|
return web3_js.clusterApiUrl(network);
|
|
2520
2876
|
}, [config.solana?.endpoint, config.solana?.network]);
|
|
2521
|
-
const walletAdapters =
|
|
2877
|
+
const walletAdapters = React4.useMemo(() => {
|
|
2522
2878
|
if (config.solana?.wallets?.length) {
|
|
2523
2879
|
return config.solana.wallets;
|
|
2524
2880
|
}
|
|
@@ -2530,21 +2886,21 @@ var PaymentProvider = ({
|
|
|
2530
2886
|
];
|
|
2531
2887
|
}, [config.solana?.wallets]);
|
|
2532
2888
|
const autoConnect = config.solana?.autoConnect ?? true;
|
|
2533
|
-
const value =
|
|
2889
|
+
const value = React4.useMemo(() => {
|
|
2534
2890
|
return {
|
|
2535
2891
|
config,
|
|
2536
2892
|
client,
|
|
2537
2893
|
queryClient
|
|
2538
2894
|
};
|
|
2539
2895
|
}, [client, config, queryClient]);
|
|
2540
|
-
|
|
2896
|
+
React4.useEffect(() => {
|
|
2541
2897
|
if (!config.collectJsKey) return;
|
|
2542
2898
|
loadCollectJs(config.collectJsKey);
|
|
2543
2899
|
}, [config.collectJsKey]);
|
|
2544
2900
|
return /* @__PURE__ */ jsxRuntime.jsx(PaymentContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReact.ConnectionProvider, { endpoint: solanaEndpoint, config: { commitment: "confirmed" }, children: /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReact.WalletProvider, { wallets: walletAdapters, autoConnect, children: /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletModalProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(PaymentsDialogProvider, { children }) }) }) }) }) });
|
|
2545
2901
|
};
|
|
2546
2902
|
var usePaymentContext = () => {
|
|
2547
|
-
const context =
|
|
2903
|
+
const context = React4.useContext(PaymentContext);
|
|
2548
2904
|
if (!context) {
|
|
2549
2905
|
throw new Error("usePaymentContext must be used within a PaymentProvider");
|
|
2550
2906
|
}
|
|
@@ -2557,7 +2913,7 @@ var SolanaPaymentSelector = ({
|
|
|
2557
2913
|
}) => {
|
|
2558
2914
|
return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isOpen, onOpenChange: (value) => value ? void 0 : onClose(), children: /* @__PURE__ */ jsxRuntime.jsx(DialogContent, { className: "w-full max-w-2xl max-h-[90vh] overflow-y-auto rounded-md border bg-background/95 p-0 shadow-2xl [&::-webkit-scrollbar]:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(SolanaPaymentView, { ...props, onClose }) }) });
|
|
2559
2915
|
};
|
|
2560
|
-
var Table =
|
|
2916
|
+
var Table = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2561
2917
|
"table",
|
|
2562
2918
|
{
|
|
2563
2919
|
ref,
|
|
@@ -2566,9 +2922,9 @@ var Table = React15__namespace.forwardRef(({ className, ...props }, ref) => /* @
|
|
|
2566
2922
|
}
|
|
2567
2923
|
) }));
|
|
2568
2924
|
Table.displayName = "Table";
|
|
2569
|
-
var TableHeader =
|
|
2925
|
+
var TableHeader = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
|
|
2570
2926
|
TableHeader.displayName = "TableHeader";
|
|
2571
|
-
var TableBody =
|
|
2927
|
+
var TableBody = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2572
2928
|
"tbody",
|
|
2573
2929
|
{
|
|
2574
2930
|
ref,
|
|
@@ -2577,7 +2933,7 @@ var TableBody = React15__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
2577
2933
|
}
|
|
2578
2934
|
));
|
|
2579
2935
|
TableBody.displayName = "TableBody";
|
|
2580
|
-
var TableFooter =
|
|
2936
|
+
var TableFooter = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2581
2937
|
"tfoot",
|
|
2582
2938
|
{
|
|
2583
2939
|
ref,
|
|
@@ -2589,7 +2945,7 @@ var TableFooter = React15__namespace.forwardRef(({ className, ...props }, ref) =
|
|
|
2589
2945
|
}
|
|
2590
2946
|
));
|
|
2591
2947
|
TableFooter.displayName = "TableFooter";
|
|
2592
|
-
var TableRow =
|
|
2948
|
+
var TableRow = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2593
2949
|
"tr",
|
|
2594
2950
|
{
|
|
2595
2951
|
ref,
|
|
@@ -2601,7 +2957,7 @@ var TableRow = React15__namespace.forwardRef(({ className, ...props }, ref) => /
|
|
|
2601
2957
|
}
|
|
2602
2958
|
));
|
|
2603
2959
|
TableRow.displayName = "TableRow";
|
|
2604
|
-
var TableHead =
|
|
2960
|
+
var TableHead = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2605
2961
|
"th",
|
|
2606
2962
|
{
|
|
2607
2963
|
ref,
|
|
@@ -2613,7 +2969,7 @@ var TableHead = React15__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
2613
2969
|
}
|
|
2614
2970
|
));
|
|
2615
2971
|
TableHead.displayName = "TableHead";
|
|
2616
|
-
var TableCell =
|
|
2972
|
+
var TableCell = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2617
2973
|
"td",
|
|
2618
2974
|
{
|
|
2619
2975
|
ref,
|
|
@@ -2622,7 +2978,7 @@ var TableCell = React15__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
2622
2978
|
}
|
|
2623
2979
|
));
|
|
2624
2980
|
TableCell.displayName = "TableCell";
|
|
2625
|
-
var TableCaption =
|
|
2981
|
+
var TableCaption = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2626
2982
|
"caption",
|
|
2627
2983
|
{
|
|
2628
2984
|
ref,
|
|
@@ -2634,7 +2990,7 @@ TableCaption.displayName = "TableCaption";
|
|
|
2634
2990
|
var AlertDialog = AlertDialogPrimitive__namespace.Root;
|
|
2635
2991
|
var AlertDialogTrigger = AlertDialogPrimitive__namespace.Trigger;
|
|
2636
2992
|
var AlertDialogPortal = AlertDialogPrimitive__namespace.Portal;
|
|
2637
|
-
var AlertDialogOverlay =
|
|
2993
|
+
var AlertDialogOverlay = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2638
2994
|
AlertDialogPrimitive__namespace.Overlay,
|
|
2639
2995
|
{
|
|
2640
2996
|
className: cn(
|
|
@@ -2646,7 +3002,7 @@ var AlertDialogOverlay = React15__namespace.forwardRef(({ className, ...props },
|
|
|
2646
3002
|
}
|
|
2647
3003
|
));
|
|
2648
3004
|
AlertDialogOverlay.displayName = AlertDialogPrimitive__namespace.Overlay.displayName;
|
|
2649
|
-
var AlertDialogContent =
|
|
3005
|
+
var AlertDialogContent = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { children: [
|
|
2650
3006
|
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogOverlay, {}),
|
|
2651
3007
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2652
3008
|
AlertDialogPrimitive__namespace.Content,
|
|
@@ -2689,7 +3045,7 @@ var AlertDialogFooter = ({
|
|
|
2689
3045
|
}
|
|
2690
3046
|
);
|
|
2691
3047
|
AlertDialogFooter.displayName = "AlertDialogFooter";
|
|
2692
|
-
var AlertDialogTitle =
|
|
3048
|
+
var AlertDialogTitle = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2693
3049
|
AlertDialogPrimitive__namespace.Title,
|
|
2694
3050
|
{
|
|
2695
3051
|
ref,
|
|
@@ -2698,7 +3054,7 @@ var AlertDialogTitle = React15__namespace.forwardRef(({ className, ...props }, r
|
|
|
2698
3054
|
}
|
|
2699
3055
|
));
|
|
2700
3056
|
AlertDialogTitle.displayName = AlertDialogPrimitive__namespace.Title.displayName;
|
|
2701
|
-
var AlertDialogDescription =
|
|
3057
|
+
var AlertDialogDescription = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2702
3058
|
AlertDialogPrimitive__namespace.Description,
|
|
2703
3059
|
{
|
|
2704
3060
|
ref,
|
|
@@ -2707,7 +3063,7 @@ var AlertDialogDescription = React15__namespace.forwardRef(({ className, ...prop
|
|
|
2707
3063
|
}
|
|
2708
3064
|
));
|
|
2709
3065
|
AlertDialogDescription.displayName = AlertDialogPrimitive__namespace.Description.displayName;
|
|
2710
|
-
var AlertDialogAction =
|
|
3066
|
+
var AlertDialogAction = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2711
3067
|
AlertDialogPrimitive__namespace.Action,
|
|
2712
3068
|
{
|
|
2713
3069
|
ref,
|
|
@@ -2716,7 +3072,7 @@ var AlertDialogAction = React15__namespace.forwardRef(({ className, ...props },
|
|
|
2716
3072
|
}
|
|
2717
3073
|
));
|
|
2718
3074
|
AlertDialogAction.displayName = AlertDialogPrimitive__namespace.Action.displayName;
|
|
2719
|
-
var AlertDialogCancel =
|
|
3075
|
+
var AlertDialogCancel = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2720
3076
|
AlertDialogPrimitive__namespace.Cancel,
|
|
2721
3077
|
{
|
|
2722
3078
|
ref,
|
|
@@ -2729,7 +3085,7 @@ var AlertDialogCancel = React15__namespace.forwardRef(({ className, ...props },
|
|
|
2729
3085
|
}
|
|
2730
3086
|
));
|
|
2731
3087
|
AlertDialogCancel.displayName = AlertDialogPrimitive__namespace.Cancel.displayName;
|
|
2732
|
-
var Textarea =
|
|
3088
|
+
var Textarea = React4__namespace.forwardRef(({ className, ...props }, ref) => {
|
|
2733
3089
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2734
3090
|
"textarea",
|
|
2735
3091
|
{
|
|
@@ -2747,7 +3103,7 @@ var notifyDefault = (payload) => {
|
|
|
2747
3103
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
2748
3104
|
console[level === "error" ? "error" : "log"]("[payments-ui] cancellation", payload);
|
|
2749
3105
|
};
|
|
2750
|
-
var
|
|
3106
|
+
var defaultTranslations3 = {
|
|
2751
3107
|
buttonLabel: "Cancel Membership",
|
|
2752
3108
|
title: "Confirm Membership Cancellation",
|
|
2753
3109
|
description: "You are about to cancel your membership. Please review the consequences:",
|
|
@@ -2769,23 +3125,33 @@ var CancelMembershipDialog = ({
|
|
|
2769
3125
|
minReasonLength = 15,
|
|
2770
3126
|
onCancelled,
|
|
2771
3127
|
onNotify,
|
|
2772
|
-
translations: customTranslations
|
|
3128
|
+
translations: customTranslations,
|
|
3129
|
+
open,
|
|
3130
|
+
onOpenChange
|
|
2773
3131
|
}) => {
|
|
2774
3132
|
const { client } = usePaymentContext();
|
|
2775
3133
|
const notify = onNotify ?? notifyDefault;
|
|
2776
|
-
const t = { ...
|
|
2777
|
-
const [cancelReason, setCancelReason] =
|
|
2778
|
-
const [
|
|
2779
|
-
const [isReasonValid, setIsReasonValid] =
|
|
2780
|
-
const [hasInteracted, setHasInteracted] =
|
|
2781
|
-
const [isSubmitting, setIsSubmitting] =
|
|
2782
|
-
|
|
3134
|
+
const t = { ...defaultTranslations3, ...customTranslations };
|
|
3135
|
+
const [cancelReason, setCancelReason] = React4.useState("");
|
|
3136
|
+
const [internalOpen, setInternalOpen] = React4.useState(false);
|
|
3137
|
+
const [isReasonValid, setIsReasonValid] = React4.useState(false);
|
|
3138
|
+
const [hasInteracted, setHasInteracted] = React4.useState(false);
|
|
3139
|
+
const [isSubmitting, setIsSubmitting] = React4.useState(false);
|
|
3140
|
+
const isControlled = typeof open === "boolean";
|
|
3141
|
+
const isOpen = isControlled ? open : internalOpen;
|
|
3142
|
+
const setOpen = (next) => {
|
|
3143
|
+
if (!isControlled) {
|
|
3144
|
+
setInternalOpen(next);
|
|
3145
|
+
}
|
|
3146
|
+
onOpenChange?.(next);
|
|
3147
|
+
};
|
|
3148
|
+
React4.useEffect(() => {
|
|
2783
3149
|
const trimmed = cancelReason.trim();
|
|
2784
3150
|
setIsReasonValid(trimmed.length >= minReasonLength);
|
|
2785
3151
|
}, [cancelReason, minReasonLength]);
|
|
2786
|
-
const handleOpenChange = (
|
|
2787
|
-
|
|
2788
|
-
if (!
|
|
3152
|
+
const handleOpenChange = (open2) => {
|
|
3153
|
+
setOpen(open2);
|
|
3154
|
+
if (!open2) {
|
|
2789
3155
|
setCancelReason("");
|
|
2790
3156
|
setIsReasonValid(false);
|
|
2791
3157
|
setHasInteracted(false);
|
|
@@ -2822,7 +3188,7 @@ var CancelMembershipDialog = ({
|
|
|
2822
3188
|
};
|
|
2823
3189
|
const showError = hasInteracted && !isReasonValid;
|
|
2824
3190
|
return /* @__PURE__ */ jsxRuntime.jsxs(AlertDialog, { open: isOpen, onOpenChange: handleOpenChange, children: [
|
|
2825
|
-
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, {
|
|
3191
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { className: "bg-destructive text-destructive-foreground border-destructive/50 hover:bg-destructive/90", children: [
|
|
2826
3192
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "mr-2 h-4 w-4" }),
|
|
2827
3193
|
" ",
|
|
2828
3194
|
t.buttonLabel
|
|
@@ -2889,7 +3255,7 @@ var notifyDefault2 = (payload) => {
|
|
|
2889
3255
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
2890
3256
|
console[level === "error" ? "error" : "log"]("[payments-ui] billing", payload);
|
|
2891
3257
|
};
|
|
2892
|
-
var
|
|
3258
|
+
var defaultTranslations4 = {
|
|
2893
3259
|
title: "Transaction History",
|
|
2894
3260
|
description: "Record of billing history",
|
|
2895
3261
|
reviewActivity: "Review your account activity below",
|
|
@@ -2911,10 +3277,10 @@ var BillingHistory = ({
|
|
|
2911
3277
|
}) => {
|
|
2912
3278
|
const { client } = usePaymentContext();
|
|
2913
3279
|
const notify = onNotify ?? notifyDefault2;
|
|
2914
|
-
const t = { ...
|
|
2915
|
-
const [isExpanded, setIsExpanded] =
|
|
2916
|
-
const observerRef =
|
|
2917
|
-
const loadMoreRef =
|
|
3280
|
+
const t = { ...defaultTranslations4, ...customTranslations };
|
|
3281
|
+
const [isExpanded, setIsExpanded] = React4.useState(false);
|
|
3282
|
+
const observerRef = React4.useRef(null);
|
|
3283
|
+
const loadMoreRef = React4.useRef(null);
|
|
2918
3284
|
const historyQuery = reactQuery.useInfiniteQuery({
|
|
2919
3285
|
queryKey: ["payments-ui", "billing-history", pageSize],
|
|
2920
3286
|
queryFn: async ({ pageParam = initialPage }) => {
|
|
@@ -2941,7 +3307,7 @@ var BillingHistory = ({
|
|
|
2941
3307
|
},
|
|
2942
3308
|
staleTime: 5 * 60 * 1e3
|
|
2943
3309
|
});
|
|
2944
|
-
|
|
3310
|
+
React4.useEffect(() => {
|
|
2945
3311
|
if (!loadMoreRef.current || !isExpanded) return;
|
|
2946
3312
|
observerRef.current = new IntersectionObserver((entries) => {
|
|
2947
3313
|
const [entry] = entries;
|
|
@@ -2956,7 +3322,7 @@ var BillingHistory = ({
|
|
|
2956
3322
|
observerRef.current?.disconnect();
|
|
2957
3323
|
};
|
|
2958
3324
|
}, [historyQuery, isExpanded, notify]);
|
|
2959
|
-
const payments =
|
|
3325
|
+
const payments = React4.useMemo(() => {
|
|
2960
3326
|
const data = historyQuery.data;
|
|
2961
3327
|
return data?.pages ?? [];
|
|
2962
3328
|
}, [historyQuery.data]);
|
|
@@ -3020,15 +3386,21 @@ var BillingHistory = ({
|
|
|
3020
3386
|
] }) });
|
|
3021
3387
|
};
|
|
3022
3388
|
var formatCardLabel2 = (method) => {
|
|
3023
|
-
|
|
3024
|
-
|
|
3389
|
+
if (method.card) {
|
|
3390
|
+
const brand2 = method.card.brand ? method.card.brand.toUpperCase() : "CARD";
|
|
3391
|
+
const lastFour2 = method.card.last4 ? `\u2022\u2022\u2022\u2022 ${method.card.last4}` : "";
|
|
3392
|
+
const exp = method.card.exp_month && method.card.exp_year ? ` \u2022 ${String(method.card.exp_month).padStart(2, "0")}/${String(method.card.exp_year).slice(-2)}` : "";
|
|
3393
|
+
return `${brand2} ${lastFour2}${exp}`.trim();
|
|
3394
|
+
}
|
|
3395
|
+
const brand = "CARD";
|
|
3396
|
+
const lastFour = "";
|
|
3025
3397
|
return `${brand} ${lastFour}`.trim();
|
|
3026
3398
|
};
|
|
3027
3399
|
var notifyDefault3 = (payload) => {
|
|
3028
3400
|
const level = payload.status === "destructive" ? "error" : "info";
|
|
3029
3401
|
console[level === "error" ? "error" : "log"]("[payments-ui] notification", payload);
|
|
3030
3402
|
};
|
|
3031
|
-
var
|
|
3403
|
+
var defaultTranslations5 = {
|
|
3032
3404
|
title: "Payment Methods",
|
|
3033
3405
|
description: "Manage your saved billing cards",
|
|
3034
3406
|
addCard: "Add card",
|
|
@@ -3049,7 +3421,11 @@ var defaultTranslations3 = {
|
|
|
3049
3421
|
cardUpdated: "Card updated",
|
|
3050
3422
|
unableToRemoveCard: "Unable to remove card",
|
|
3051
3423
|
defaultPaymentMethodUpdated: "Default payment method updated",
|
|
3052
|
-
unableToSetDefault: "Unable to set default payment method"
|
|
3424
|
+
unableToSetDefault: "Unable to set default payment method",
|
|
3425
|
+
errors: {},
|
|
3426
|
+
activeSubscriptions: "Active subscriptions",
|
|
3427
|
+
showSubscriptions: "Show",
|
|
3428
|
+
hideSubscriptions: "Hide"
|
|
3053
3429
|
};
|
|
3054
3430
|
var PaymentMethodsSection = ({
|
|
3055
3431
|
isAuthenticated = true,
|
|
@@ -3060,8 +3436,7 @@ var PaymentMethodsSection = ({
|
|
|
3060
3436
|
onNotify,
|
|
3061
3437
|
translations: customTranslations
|
|
3062
3438
|
}) => {
|
|
3063
|
-
const { client } = usePaymentContext();
|
|
3064
|
-
const queryClient = reactQuery.useQueryClient();
|
|
3439
|
+
const { client, queryClient } = usePaymentContext();
|
|
3065
3440
|
const paymentMethods = {
|
|
3066
3441
|
list: (params) => client.listPaymentMethods({ limit: params.pageSize }),
|
|
3067
3442
|
create: (payload) => client.createPaymentMethod(payload),
|
|
@@ -3069,15 +3444,17 @@ var PaymentMethodsSection = ({
|
|
|
3069
3444
|
remove: (id) => client.deletePaymentMethod(id),
|
|
3070
3445
|
activate: (id) => client.activatePaymentMethod(id)
|
|
3071
3446
|
};
|
|
3072
|
-
const [isModalOpen, setIsModalOpen] =
|
|
3073
|
-
const [deletingId, setDeletingId] =
|
|
3447
|
+
const [isModalOpen, setIsModalOpen] = React4.useState(false);
|
|
3448
|
+
const [deletingId, setDeletingId] = React4.useState(null);
|
|
3449
|
+
const [createErrorMessage, setCreateErrorMessage] = React4.useState(null);
|
|
3450
|
+
const [expandedSubscriptions, setExpandedSubscriptions] = React4.useState({});
|
|
3074
3451
|
const notify = onNotify ?? notifyDefault3;
|
|
3075
|
-
const t = { ...
|
|
3452
|
+
const t = { ...defaultTranslations5, ...customTranslations };
|
|
3076
3453
|
const queryKey = ["payments-ui", "payment-methods"];
|
|
3077
3454
|
const paymentQuery = reactQuery.useQuery({
|
|
3078
3455
|
queryKey,
|
|
3079
3456
|
queryFn: () => paymentMethods.list({ pageSize: 50 }),
|
|
3080
|
-
enabled: isAuthenticated,
|
|
3457
|
+
enabled: isAuthenticated && !!client,
|
|
3081
3458
|
staleTime: 3e4
|
|
3082
3459
|
});
|
|
3083
3460
|
const createMutation = reactQuery.useMutation({
|
|
@@ -3086,11 +3463,14 @@ var PaymentMethodsSection = ({
|
|
|
3086
3463
|
notify({ title: t.cardAddedSuccess, status: "success" });
|
|
3087
3464
|
setIsModalOpen(false);
|
|
3088
3465
|
void queryClient.invalidateQueries({ queryKey });
|
|
3466
|
+
setCreateErrorMessage(null);
|
|
3089
3467
|
},
|
|
3090
3468
|
onError: (error) => {
|
|
3469
|
+
const message = resolveErrorMessageByCode(error, t.errors, error.message);
|
|
3470
|
+
setCreateErrorMessage(message);
|
|
3091
3471
|
notify({
|
|
3092
3472
|
title: t.unableToAddCard,
|
|
3093
|
-
description:
|
|
3473
|
+
description: message,
|
|
3094
3474
|
status: "destructive"
|
|
3095
3475
|
});
|
|
3096
3476
|
}
|
|
@@ -3101,6 +3481,9 @@ var PaymentMethodsSection = ({
|
|
|
3101
3481
|
onSuccess: () => {
|
|
3102
3482
|
notify({ title: t.cardRemoved, status: "success" });
|
|
3103
3483
|
void queryClient.invalidateQueries({ queryKey });
|
|
3484
|
+
if (paymentQuery.refetch) {
|
|
3485
|
+
paymentQuery.refetch();
|
|
3486
|
+
}
|
|
3104
3487
|
},
|
|
3105
3488
|
onError: (error) => {
|
|
3106
3489
|
notify({
|
|
@@ -3111,7 +3494,7 @@ var PaymentMethodsSection = ({
|
|
|
3111
3494
|
},
|
|
3112
3495
|
onSettled: () => setDeletingId(null)
|
|
3113
3496
|
});
|
|
3114
|
-
|
|
3497
|
+
reactQuery.useMutation({
|
|
3115
3498
|
mutationFn: (id) => paymentMethods.activate(id),
|
|
3116
3499
|
onSuccess: () => {
|
|
3117
3500
|
notify({ title: t.defaultPaymentMethodUpdated, status: "success" });
|
|
@@ -3125,12 +3508,18 @@ var PaymentMethodsSection = ({
|
|
|
3125
3508
|
});
|
|
3126
3509
|
}
|
|
3127
3510
|
});
|
|
3128
|
-
|
|
3511
|
+
React4.useEffect(() => {
|
|
3129
3512
|
if (!isModalOpen) {
|
|
3130
3513
|
createMutation.reset();
|
|
3514
|
+
setCreateErrorMessage(null);
|
|
3515
|
+
}
|
|
3516
|
+
}, [isModalOpen]);
|
|
3517
|
+
React4.useEffect(() => {
|
|
3518
|
+
if (!isModalOpen && paymentQuery.refetch) {
|
|
3519
|
+
paymentQuery.refetch();
|
|
3131
3520
|
}
|
|
3132
|
-
}, [
|
|
3133
|
-
const payments =
|
|
3521
|
+
}, [isModalOpen]);
|
|
3522
|
+
const payments = React4.useMemo(() => paymentQuery.data?.data ?? [], [paymentQuery.data]);
|
|
3134
3523
|
const loading = paymentQuery.isLoading || paymentQuery.isFetching;
|
|
3135
3524
|
const buildPayload = (token, billing) => ({
|
|
3136
3525
|
payment_token: token,
|
|
@@ -3143,9 +3532,13 @@ var PaymentMethodsSection = ({
|
|
|
3143
3532
|
zip: billing.postalCode,
|
|
3144
3533
|
country: billing.country,
|
|
3145
3534
|
email: billing.email,
|
|
3146
|
-
provider: billing.provider
|
|
3535
|
+
provider: billing.provider,
|
|
3536
|
+
last_four: billing.last_four,
|
|
3537
|
+
card_type: billing.card_type,
|
|
3538
|
+
expiry_date: billing.expiry_date
|
|
3147
3539
|
});
|
|
3148
3540
|
const handleCardTokenize = (token, billing) => {
|
|
3541
|
+
setCreateErrorMessage(null);
|
|
3149
3542
|
createMutation.mutate(buildPayload(token, billing));
|
|
3150
3543
|
};
|
|
3151
3544
|
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-black/30 shadow-2xl backdrop-blur-xl", children: [
|
|
@@ -3164,32 +3557,19 @@ var PaymentMethodsSection = ({
|
|
|
3164
3557
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-5 w-5 animate-spin" }),
|
|
3165
3558
|
" ",
|
|
3166
3559
|
t.loadingCards
|
|
3167
|
-
] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-sm text-center", children: t.noPaymentMethods }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) =>
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3560
|
+
] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-sm text-center", children: t.noPaymentMethods }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) => {
|
|
3561
|
+
(method.subscriptions?.length ?? 0) > 0;
|
|
3562
|
+
expandedSubscriptions[method.id] ?? false;
|
|
3563
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3564
|
+
"div",
|
|
3565
|
+
{
|
|
3566
|
+
className: "rounded-lg border bg-white/5 p-4 shadow-sm",
|
|
3567
|
+
children: [
|
|
3568
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
3569
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-between", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-medium text-white", children: formatCardLabel2(method) }) }),
|
|
3570
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: method.failure_reason && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "destructive", children: method.failure_reason }) })
|
|
3176
3571
|
] }),
|
|
3177
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", {
|
|
3178
|
-
] }),
|
|
3179
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
3180
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3181
|
-
Button,
|
|
3182
|
-
{
|
|
3183
|
-
variant: "outline",
|
|
3184
|
-
disabled: method.is_active || activateMutation.isPending,
|
|
3185
|
-
onClick: () => activateMutation.mutate(method.id),
|
|
3186
|
-
children: [
|
|
3187
|
-
activateMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
|
|
3188
|
-
method.is_active ? t.defaultMethod : t.makeDefault
|
|
3189
|
-
]
|
|
3190
|
-
}
|
|
3191
|
-
),
|
|
3192
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3572
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3193
3573
|
Button,
|
|
3194
3574
|
{
|
|
3195
3575
|
variant: "ghost",
|
|
@@ -3201,12 +3581,12 @@ var PaymentMethodsSection = ({
|
|
|
3201
3581
|
t.remove
|
|
3202
3582
|
]
|
|
3203
3583
|
}
|
|
3204
|
-
)
|
|
3205
|
-
]
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
)
|
|
3584
|
+
) })
|
|
3585
|
+
]
|
|
3586
|
+
},
|
|
3587
|
+
method.id
|
|
3588
|
+
);
|
|
3589
|
+
}) }) }),
|
|
3210
3590
|
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3211
3591
|
DialogContent,
|
|
3212
3592
|
{
|
|
@@ -3224,12 +3604,13 @@ var PaymentMethodsSection = ({
|
|
|
3224
3604
|
collectPrefix,
|
|
3225
3605
|
onTokenize: handleCardTokenize,
|
|
3226
3606
|
submitting: createMutation.isPending,
|
|
3607
|
+
translations: t,
|
|
3227
3608
|
defaultValues: {
|
|
3228
3609
|
provider,
|
|
3229
3610
|
email: userEmail ?? "",
|
|
3230
3611
|
country: defaultCountry
|
|
3231
3612
|
},
|
|
3232
|
-
externalError:
|
|
3613
|
+
externalError: createErrorMessage
|
|
3233
3614
|
}
|
|
3234
3615
|
)
|
|
3235
3616
|
]
|
|
@@ -3237,7 +3618,388 @@ var PaymentMethodsSection = ({
|
|
|
3237
3618
|
) })
|
|
3238
3619
|
] });
|
|
3239
3620
|
};
|
|
3240
|
-
var
|
|
3621
|
+
var notifyDefault4 = (payload) => {
|
|
3622
|
+
const level = payload.status === "destructive" ? "error" : "info";
|
|
3623
|
+
console[level === "error" ? "error" : "log"]("[payments-ui] notification", payload);
|
|
3624
|
+
};
|
|
3625
|
+
var defaultTranslations6 = {
|
|
3626
|
+
title: "Subscriptions",
|
|
3627
|
+
description: "Manage your active and recent subscriptions.",
|
|
3628
|
+
loading: "Loading subscriptions...",
|
|
3629
|
+
noSubscriptions: "No subscriptions found.",
|
|
3630
|
+
status: "Status",
|
|
3631
|
+
active: "Active",
|
|
3632
|
+
cancelled: "Cancelled",
|
|
3633
|
+
pastDue: "Past due",
|
|
3634
|
+
pending: "Pending",
|
|
3635
|
+
paymentMethodLabel: "Payment method",
|
|
3636
|
+
changePaymentMethod: "Change payment method",
|
|
3637
|
+
paymentMethodUpdated: "Payment method updated",
|
|
3638
|
+
paymentMethodUpdateFailed: "Unable to update payment method",
|
|
3639
|
+
resume: "Resume subscription",
|
|
3640
|
+
changePlan: "Change plan",
|
|
3641
|
+
changePlanPlaceholder: "Enter a new price ID",
|
|
3642
|
+
planChanged: "Subscription updated",
|
|
3643
|
+
planChangeFailed: "Unable to update subscription",
|
|
3644
|
+
planChangeUnavailable: "Plan changes are unavailable for this subscription.",
|
|
3645
|
+
resumeSuccess: "Resume requested",
|
|
3646
|
+
resumeFailed: "Unable to resume subscription",
|
|
3647
|
+
update: "Update",
|
|
3648
|
+
product: "Product",
|
|
3649
|
+
price: "Price",
|
|
3650
|
+
currentPeriod: "Current period",
|
|
3651
|
+
refresh: "Refresh",
|
|
3652
|
+
manage: "Manage",
|
|
3653
|
+
close: "Close",
|
|
3654
|
+
paymentMethodTab: "Payment method",
|
|
3655
|
+
changePlanTab: "Change plan",
|
|
3656
|
+
statusTab: "Details",
|
|
3657
|
+
cancelTab: "Cancel/Resume"
|
|
3658
|
+
};
|
|
3659
|
+
var formatCardLabel3 = (method) => {
|
|
3660
|
+
if (method.card) {
|
|
3661
|
+
const brand2 = method.card.brand ? method.card.brand.toUpperCase() : "CARD";
|
|
3662
|
+
const lastFour2 = method.card.last4 ? `\u2022\u2022\u2022\u2022 ${method.card.last4}` : "";
|
|
3663
|
+
const exp = method.card.exp_month && method.card.exp_year ? ` \u2022 ${String(method.card.exp_month).padStart(2, "0")}/${String(method.card.exp_year).slice(-2)}` : "";
|
|
3664
|
+
return `${brand2} ${lastFour2}${exp}`.trim();
|
|
3665
|
+
}
|
|
3666
|
+
const brand = "CARD";
|
|
3667
|
+
const lastFour = "";
|
|
3668
|
+
return `${brand} ${lastFour}`.trim();
|
|
3669
|
+
};
|
|
3670
|
+
var SubscriptionsSection = ({
|
|
3671
|
+
isAuthenticated = true,
|
|
3672
|
+
translations: customTranslations,
|
|
3673
|
+
onNotify,
|
|
3674
|
+
statusFilter,
|
|
3675
|
+
cancelDialogTranslations,
|
|
3676
|
+
onCancelled
|
|
3677
|
+
}) => {
|
|
3678
|
+
const { client, queryClient } = usePaymentContext();
|
|
3679
|
+
const notify = onNotify ?? notifyDefault4;
|
|
3680
|
+
const t = { ...defaultTranslations6, ...customTranslations };
|
|
3681
|
+
const cancelTranslations = cancelDialogTranslations ?? defaultTranslations3;
|
|
3682
|
+
const [paymentSelections, setPaymentSelections] = React4.useState({});
|
|
3683
|
+
const [priceInputs, setPriceInputs] = React4.useState({});
|
|
3684
|
+
const [activeSubId, setActiveSubId] = React4.useState(null);
|
|
3685
|
+
const [cancelDialogOpen, setCancelDialogOpen] = React4.useState(false);
|
|
3686
|
+
const [sectionsOpen, setSectionsOpen] = React4.useState({
|
|
3687
|
+
status: true,
|
|
3688
|
+
payment: false,
|
|
3689
|
+
plan: false,
|
|
3690
|
+
cancel: false
|
|
3691
|
+
});
|
|
3692
|
+
const normalizedStatusFilter = statusFilter ?? "all";
|
|
3693
|
+
const subscriptionsQueryKey = ["payments-ui", "subscriptions", normalizedStatusFilter];
|
|
3694
|
+
const paymentMethodsQueryKey = ["payments-ui", "payment-methods"];
|
|
3695
|
+
const subscriptionsQuery = reactQuery.useQuery({
|
|
3696
|
+
queryKey: subscriptionsQueryKey,
|
|
3697
|
+
queryFn: () => client.listSubscriptions({
|
|
3698
|
+
status: normalizedStatusFilter,
|
|
3699
|
+
limit: 50
|
|
3700
|
+
}),
|
|
3701
|
+
enabled: isAuthenticated && !!client,
|
|
3702
|
+
staleTime: 3e4
|
|
3703
|
+
});
|
|
3704
|
+
const paymentMethodsQuery = reactQuery.useQuery({
|
|
3705
|
+
queryKey: paymentMethodsQueryKey,
|
|
3706
|
+
queryFn: () => client.listPaymentMethods({ limit: 50 }),
|
|
3707
|
+
enabled: isAuthenticated && !!client,
|
|
3708
|
+
staleTime: 3e4
|
|
3709
|
+
});
|
|
3710
|
+
const subscriptions = React4.useMemo(() => subscriptionsQuery.data?.data ?? [], [subscriptionsQuery.data]);
|
|
3711
|
+
const paymentMethods = React4.useMemo(() => paymentMethodsQuery.data?.data ?? [], [paymentMethodsQuery.data]);
|
|
3712
|
+
const activeSubscription = React4.useMemo(
|
|
3713
|
+
() => subscriptions.find((sub) => sub.id === activeSubId),
|
|
3714
|
+
[subscriptions, activeSubId]
|
|
3715
|
+
);
|
|
3716
|
+
React4.useEffect(() => {
|
|
3717
|
+
setPaymentSelections((prev) => {
|
|
3718
|
+
const next = {};
|
|
3719
|
+
subscriptions.forEach((sub) => {
|
|
3720
|
+
next[sub.id] = prev[sub.id] ?? "";
|
|
3721
|
+
});
|
|
3722
|
+
return next;
|
|
3723
|
+
});
|
|
3724
|
+
}, [subscriptions]);
|
|
3725
|
+
React4.useEffect(() => {
|
|
3726
|
+
setCancelDialogOpen(false);
|
|
3727
|
+
}, [activeSubId]);
|
|
3728
|
+
const updatePaymentMethodMutation = reactQuery.useMutation({
|
|
3729
|
+
mutationFn: (payload) => client.updateSubscriptionPaymentMethod({
|
|
3730
|
+
subscription_id: payload.subscriptionId,
|
|
3731
|
+
payment_method_id: payload.paymentMethodId
|
|
3732
|
+
}),
|
|
3733
|
+
onSuccess: () => {
|
|
3734
|
+
notify({ title: t.paymentMethodUpdated, status: "success" });
|
|
3735
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3736
|
+
},
|
|
3737
|
+
onError: (error) => {
|
|
3738
|
+
notify({
|
|
3739
|
+
title: t.paymentMethodUpdateFailed,
|
|
3740
|
+
description: resolveErrorMessageByCode(error, {}, error.message),
|
|
3741
|
+
status: "destructive"
|
|
3742
|
+
});
|
|
3743
|
+
}
|
|
3744
|
+
});
|
|
3745
|
+
const resumeSubscriptionMutation = reactQuery.useMutation({
|
|
3746
|
+
mutationFn: () => client.resumeSubscription(),
|
|
3747
|
+
onSuccess: () => {
|
|
3748
|
+
notify({ title: t.resumeSuccess, status: "success" });
|
|
3749
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3750
|
+
},
|
|
3751
|
+
onError: (error) => {
|
|
3752
|
+
notify({
|
|
3753
|
+
title: t.resumeFailed,
|
|
3754
|
+
description: resolveErrorMessageByCode(error, {}, error.message),
|
|
3755
|
+
status: "destructive"
|
|
3756
|
+
});
|
|
3757
|
+
}
|
|
3758
|
+
});
|
|
3759
|
+
reactQuery.useMutation({
|
|
3760
|
+
mutationFn: (payload) => client.changeSubscription({ price_id: payload.priceId }),
|
|
3761
|
+
onSuccess: () => {
|
|
3762
|
+
notify({ title: t.planChanged, status: "success" });
|
|
3763
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3764
|
+
},
|
|
3765
|
+
onError: (error) => {
|
|
3766
|
+
notify({
|
|
3767
|
+
title: t.planChangeFailed,
|
|
3768
|
+
description: resolveErrorMessageByCode(error, {}, error.message),
|
|
3769
|
+
status: "destructive"
|
|
3770
|
+
});
|
|
3771
|
+
}
|
|
3772
|
+
});
|
|
3773
|
+
const isLoading = subscriptionsQuery.isLoading || subscriptionsQuery.isFetching;
|
|
3774
|
+
const isError = subscriptionsQuery.isError;
|
|
3775
|
+
const errorMessage = subscriptionsQuery.error instanceof Error ? subscriptionsQuery.error.message : void 0;
|
|
3776
|
+
React4.useEffect(() => {
|
|
3777
|
+
if (subscriptionsQuery.refetch) {
|
|
3778
|
+
void subscriptionsQuery.refetch();
|
|
3779
|
+
}
|
|
3780
|
+
}, []);
|
|
3781
|
+
const formatPrice = (sub) => {
|
|
3782
|
+
const price = sub.price;
|
|
3783
|
+
if (!price) return t.price;
|
|
3784
|
+
const amount = (price.amount / 100).toFixed(2);
|
|
3785
|
+
const currency = price.currency ? price.currency?.toUpperCase() : "";
|
|
3786
|
+
return `${price.display_name ?? t.price} \u2014 ${currency} ${amount}`;
|
|
3787
|
+
};
|
|
3788
|
+
const renderStatusBadge = (status) => {
|
|
3789
|
+
const normalized = status.toLowerCase();
|
|
3790
|
+
const label = normalized === "active" ? t.active : normalized === "past_due" ? t.pastDue : normalized === "pending" ? t.pending : t.cancelled;
|
|
3791
|
+
const variant = normalized === "active" ? "default" : normalized === "past_due" ? "destructive" : normalized === "pending" ? "outline" : "secondary";
|
|
3792
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant, children: label });
|
|
3793
|
+
};
|
|
3794
|
+
const handleUpdatePaymentMethod = (subscriptionId) => {
|
|
3795
|
+
const paymentMethodId = paymentSelections[subscriptionId];
|
|
3796
|
+
const currentPaymentMethodId = "pm_" + subscriptions.find((s) => s.id === subscriptionId)?.payment_method_id;
|
|
3797
|
+
if (!paymentMethodId) return;
|
|
3798
|
+
if (currentPaymentMethodId && paymentMethodId === currentPaymentMethodId) {
|
|
3799
|
+
notify({
|
|
3800
|
+
title: t.paymentMethodUpdateFailed,
|
|
3801
|
+
description: t.paymentMethodUpdateFailed,
|
|
3802
|
+
status: "destructive"
|
|
3803
|
+
});
|
|
3804
|
+
return;
|
|
3805
|
+
}
|
|
3806
|
+
updatePaymentMethodMutation.mutate({ subscriptionId, paymentMethodId });
|
|
3807
|
+
};
|
|
3808
|
+
const toggleSection = (key) => {
|
|
3809
|
+
setSectionsOpen((prev) => ({
|
|
3810
|
+
...prev,
|
|
3811
|
+
[key]: !prev[key]
|
|
3812
|
+
}));
|
|
3813
|
+
};
|
|
3814
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3815
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-black/30 shadow-2xl backdrop-blur-xl", children: [
|
|
3816
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-col gap-4 md:flex-row md:items-center md:justify-between", children: [
|
|
3817
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3818
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2", children: [
|
|
3819
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.WalletCards, { className: "h-5 w-5" }),
|
|
3820
|
+
t.title
|
|
3821
|
+
] }),
|
|
3822
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: t.description })
|
|
3823
|
+
] }),
|
|
3824
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3825
|
+
Button,
|
|
3826
|
+
{
|
|
3827
|
+
variant: "ghost",
|
|
3828
|
+
size: "sm",
|
|
3829
|
+
onClick: () => subscriptionsQuery.refetch?.(),
|
|
3830
|
+
disabled: subscriptionsQuery.isFetching,
|
|
3831
|
+
children: [
|
|
3832
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: "mr-2 h-4 w-4" }),
|
|
3833
|
+
" ",
|
|
3834
|
+
subscriptionsQuery.isFetching ? t.loading : t.refresh
|
|
3835
|
+
]
|
|
3836
|
+
}
|
|
3837
|
+
)
|
|
3838
|
+
] }),
|
|
3839
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "space-y-4", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-10 text-white/60", children: [
|
|
3840
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-5 w-5 animate-spin" }),
|
|
3841
|
+
" ",
|
|
3842
|
+
t.loading
|
|
3843
|
+
] }) : isError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-100", children: errorMessage ?? "Unable to load subscriptions." }) : subscriptions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 text-sm text-center", children: t.noSubscriptions }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: subscriptions.map((subscription) => {
|
|
3844
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3845
|
+
"div",
|
|
3846
|
+
{
|
|
3847
|
+
className: "rounded-lg border bg-white/5 p-4 shadow-sm",
|
|
3848
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4", children: [
|
|
3849
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3850
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-base font-semibold text-white", children: subscription.product?.display_name ?? t.product }),
|
|
3851
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-white/80", children: formatPrice(subscription) })
|
|
3852
|
+
] }),
|
|
3853
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3854
|
+
renderStatusBadge(subscription.status),
|
|
3855
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3856
|
+
Button,
|
|
3857
|
+
{
|
|
3858
|
+
variant: "default",
|
|
3859
|
+
size: "sm",
|
|
3860
|
+
className: "rounded-full bg-foreground/10 text-muted-foreground hover:bg-foreground/20 hover:text-foreground",
|
|
3861
|
+
onClick: () => setActiveSubId(subscription.id),
|
|
3862
|
+
children: t.update
|
|
3863
|
+
}
|
|
3864
|
+
)
|
|
3865
|
+
] })
|
|
3866
|
+
] })
|
|
3867
|
+
},
|
|
3868
|
+
subscription.id
|
|
3869
|
+
);
|
|
3870
|
+
}) }) })
|
|
3871
|
+
] }),
|
|
3872
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: !!activeSubscription, onOpenChange: (open) => setActiveSubId(open ? activeSubId : null), children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-w-2xl min-h-[300px] border border-white/20 bg-background-regular p-6 text-foreground", children: [
|
|
3873
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
3874
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "flex items-center gap-2", children: activeSubscription?.product?.display_name ?? t.product }),
|
|
3875
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "text-white/70", children: activeSubscription ? formatPrice(activeSubscription) : null })
|
|
3876
|
+
] }),
|
|
3877
|
+
activeSubscription && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-3", children: [
|
|
3878
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-lg border border-white/15 bg-white/5", children: [
|
|
3879
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3880
|
+
"button",
|
|
3881
|
+
{
|
|
3882
|
+
type: "button",
|
|
3883
|
+
className: "flex w-full items-center justify-between px-4 py-3 text-left text-white hover:bg-white/10",
|
|
3884
|
+
onClick: () => toggleSection("status"),
|
|
3885
|
+
children: [
|
|
3886
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: t.statusTab }),
|
|
3887
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3888
|
+
lucideReact.ChevronDown,
|
|
3889
|
+
{
|
|
3890
|
+
className: `h-4 w-4 transition-transform ${sectionsOpen.status ? "rotate-180" : ""}`
|
|
3891
|
+
}
|
|
3892
|
+
)
|
|
3893
|
+
]
|
|
3894
|
+
}
|
|
3895
|
+
),
|
|
3896
|
+
sectionsOpen.status ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 border-t border-white/10 px-4 py-3", children: [
|
|
3897
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between rounded-lg border border-white/10 bg-white/5 p-3", children: [
|
|
3898
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium text-white/80", children: t.status }),
|
|
3899
|
+
renderStatusBadge(activeSubscription.status)
|
|
3900
|
+
] }),
|
|
3901
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-white/60", children: [
|
|
3902
|
+
t.currentPeriod,
|
|
3903
|
+
": ",
|
|
3904
|
+
activeSubscription.started_at ? new Date(activeSubscription.started_at).toLocaleDateString() : "\u2014",
|
|
3905
|
+
" \u2192",
|
|
3906
|
+
" ",
|
|
3907
|
+
activeSubscription.current_period_ends_at ?? "\u2014"
|
|
3908
|
+
] }),
|
|
3909
|
+
activeSubscription.status.toLowerCase() === "cancelled" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3910
|
+
Button,
|
|
3911
|
+
{
|
|
3912
|
+
variant: "secondary",
|
|
3913
|
+
onClick: () => resumeSubscriptionMutation.mutate(),
|
|
3914
|
+
disabled: resumeSubscriptionMutation.isPending,
|
|
3915
|
+
className: "rounded-full px-4",
|
|
3916
|
+
children: [
|
|
3917
|
+
resumeSubscriptionMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
|
|
3918
|
+
t.resume
|
|
3919
|
+
]
|
|
3920
|
+
}
|
|
3921
|
+
) : null
|
|
3922
|
+
] }) : null
|
|
3923
|
+
] }),
|
|
3924
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-lg border border-white/15 bg-white/5", children: [
|
|
3925
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3926
|
+
"button",
|
|
3927
|
+
{
|
|
3928
|
+
type: "button",
|
|
3929
|
+
className: "flex w-full items-center justify-between px-4 py-3 text-left text-white hover:bg-white/10",
|
|
3930
|
+
onClick: () => toggleSection("payment"),
|
|
3931
|
+
children: [
|
|
3932
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: t.paymentMethodTab }),
|
|
3933
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3934
|
+
lucideReact.ChevronDown,
|
|
3935
|
+
{
|
|
3936
|
+
className: `h-4 w-4 transition-transform ${sectionsOpen.payment ? "rotate-180" : ""}`
|
|
3937
|
+
}
|
|
3938
|
+
)
|
|
3939
|
+
]
|
|
3940
|
+
}
|
|
3941
|
+
),
|
|
3942
|
+
sectionsOpen.payment ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 border-t border-white/10 px-4 py-3", children: [
|
|
3943
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs uppercase tracking-wide text-white/60", children: t.paymentMethodLabel }),
|
|
3944
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:gap-2", children: [
|
|
3945
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3946
|
+
Select,
|
|
3947
|
+
{
|
|
3948
|
+
value: paymentSelections[activeSubscription.id] || "pm_" + activeSubscription.payment_method_id || "",
|
|
3949
|
+
onValueChange: (value) => setPaymentSelections((prev) => ({ ...prev, [activeSubscription.id]: value })),
|
|
3950
|
+
disabled: paymentMethodsQuery.isLoading || paymentMethods.length === 0,
|
|
3951
|
+
children: [
|
|
3952
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "w-full md:w-64 text-white", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: paymentMethodsQuery.isLoading ? t.loading : "" }) }),
|
|
3953
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: paymentMethods.filter((method) => method.id !== activeSubscription.payment_method_id).map((method) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: method.id, children: formatCardLabel3(method) }, method.id)) })
|
|
3954
|
+
]
|
|
3955
|
+
}
|
|
3956
|
+
),
|
|
3957
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3958
|
+
Button,
|
|
3959
|
+
{
|
|
3960
|
+
size: "sm",
|
|
3961
|
+
onClick: () => handleUpdatePaymentMethod(activeSubscription.id),
|
|
3962
|
+
disabled: updatePaymentMethodMutation.isPending || !paymentSelections[activeSubscription.id] || paymentSelections[activeSubscription.id] === activeSubscription.payment_method_id,
|
|
3963
|
+
className: "border-0 bg-green-bg text-white hover:bg-green-bg/80 disabled:opacity-50",
|
|
3964
|
+
children: [
|
|
3965
|
+
updatePaymentMethodMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null,
|
|
3966
|
+
t.update
|
|
3967
|
+
]
|
|
3968
|
+
}
|
|
3969
|
+
)
|
|
3970
|
+
] })
|
|
3971
|
+
] }) : null
|
|
3972
|
+
] })
|
|
3973
|
+
] }),
|
|
3974
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { className: "flex flex-wrap gap-2", children: [
|
|
3975
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3976
|
+
CancelMembershipDialog,
|
|
3977
|
+
{
|
|
3978
|
+
translations: cancelTranslations,
|
|
3979
|
+
onNotify,
|
|
3980
|
+
open: cancelDialogOpen,
|
|
3981
|
+
onOpenChange: (openState) => setCancelDialogOpen(openState),
|
|
3982
|
+
onCancelled: () => {
|
|
3983
|
+
void queryClient.invalidateQueries({ queryKey: subscriptionsQueryKey });
|
|
3984
|
+
onCancelled?.();
|
|
3985
|
+
setActiveSubId(null);
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
),
|
|
3989
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3990
|
+
Button,
|
|
3991
|
+
{
|
|
3992
|
+
variant: "secondary",
|
|
3993
|
+
onClick: () => setActiveSubId(null),
|
|
3994
|
+
className: "border-white/20 bg-transparent text-foreground hover:bg-foreground/10 hover:text-foreground",
|
|
3995
|
+
children: t.close
|
|
3996
|
+
}
|
|
3997
|
+
)
|
|
3998
|
+
] })
|
|
3999
|
+
] }) })
|
|
4000
|
+
] });
|
|
4001
|
+
};
|
|
4002
|
+
var Checkbox = React4__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3241
4003
|
CheckboxPrimitive__namespace.Root,
|
|
3242
4004
|
{
|
|
3243
4005
|
ref,
|
|
@@ -3264,9 +4026,9 @@ var initialState = {
|
|
|
3264
4026
|
termsAccepted: false
|
|
3265
4027
|
};
|
|
3266
4028
|
var WalletDialog = ({ open, onOpenChange }) => {
|
|
3267
|
-
const [form, setForm] =
|
|
3268
|
-
const [errors, setErrors] =
|
|
3269
|
-
const validators =
|
|
4029
|
+
const [form, setForm] = React4.useState(initialState);
|
|
4030
|
+
const [errors, setErrors] = React4.useState({});
|
|
4031
|
+
const validators = React4.useMemo(
|
|
3270
4032
|
() => ({
|
|
3271
4033
|
nameOnCard: (value) => !value ? "Name is required" : void 0,
|
|
3272
4034
|
cardNumber: (value) => /^\d{16}$/.test(value) ? void 0 : "Card number must be 16 digits",
|
|
@@ -3359,10 +4121,10 @@ var WalletDialog = ({ open, onOpenChange }) => {
|
|
|
3359
4121
|
var useTokenBalance = (tokens) => {
|
|
3360
4122
|
const { publicKey } = walletAdapterReact.useWallet();
|
|
3361
4123
|
const { connection } = walletAdapterReact.useConnection();
|
|
3362
|
-
const [balances, setBalances] =
|
|
3363
|
-
const [isLoading, setIsLoading] =
|
|
3364
|
-
const [error, setError] =
|
|
3365
|
-
const fetchTokenBalance =
|
|
4124
|
+
const [balances, setBalances] = React4.useState([]);
|
|
4125
|
+
const [isLoading, setIsLoading] = React4.useState(false);
|
|
4126
|
+
const [error, setError] = React4.useState(null);
|
|
4127
|
+
const fetchTokenBalance = React4.useCallback(
|
|
3366
4128
|
async (token, walletAddress) => {
|
|
3367
4129
|
try {
|
|
3368
4130
|
const mintPublicKey = new web3_js.PublicKey(token.mint);
|
|
@@ -3403,8 +4165,8 @@ var useTokenBalance = (tokens) => {
|
|
|
3403
4165
|
},
|
|
3404
4166
|
[connection]
|
|
3405
4167
|
);
|
|
3406
|
-
const tokensKey =
|
|
3407
|
-
|
|
4168
|
+
const tokensKey = React4.useMemo(() => tokens.map((t) => t.mint).join(","), [tokens]);
|
|
4169
|
+
React4.useEffect(() => {
|
|
3408
4170
|
if (!publicKey || tokens.length === 0) {
|
|
3409
4171
|
setBalances([]);
|
|
3410
4172
|
return;
|
|
@@ -3428,20 +4190,20 @@ var useTokenBalance = (tokens) => {
|
|
|
3428
4190
|
};
|
|
3429
4191
|
fetchAllBalances();
|
|
3430
4192
|
}, [publicKey, tokensKey, fetchTokenBalance]);
|
|
3431
|
-
const getTokenBalance =
|
|
4193
|
+
const getTokenBalance = React4.useCallback(
|
|
3432
4194
|
(tokenSymbol) => {
|
|
3433
4195
|
return balances.find((balance) => balance.token.symbol === tokenSymbol);
|
|
3434
4196
|
},
|
|
3435
4197
|
[balances]
|
|
3436
4198
|
);
|
|
3437
|
-
const hasSufficientBalance =
|
|
4199
|
+
const hasSufficientBalance = React4.useCallback(
|
|
3438
4200
|
(tokenSymbol, requiredAmount) => {
|
|
3439
4201
|
const balance = getTokenBalance(tokenSymbol);
|
|
3440
4202
|
return balance ? balance.uiAmount >= requiredAmount : false;
|
|
3441
4203
|
},
|
|
3442
4204
|
[getTokenBalance]
|
|
3443
4205
|
);
|
|
3444
|
-
const getFormattedBalance =
|
|
4206
|
+
const getFormattedBalance = React4.useCallback(
|
|
3445
4207
|
(tokenSymbol) => {
|
|
3446
4208
|
const balance = getTokenBalance(tokenSymbol);
|
|
3447
4209
|
if (!balance) return "0.00";
|
|
@@ -3455,7 +4217,7 @@ var useTokenBalance = (tokens) => {
|
|
|
3455
4217
|
},
|
|
3456
4218
|
[getTokenBalance]
|
|
3457
4219
|
);
|
|
3458
|
-
const refreshBalances =
|
|
4220
|
+
const refreshBalances = React4.useCallback(async () => {
|
|
3459
4221
|
if (!publicKey || tokens.length === 0) {
|
|
3460
4222
|
setBalances([]);
|
|
3461
4223
|
return;
|
|
@@ -3476,7 +4238,7 @@ var useTokenBalance = (tokens) => {
|
|
|
3476
4238
|
setIsLoading(false);
|
|
3477
4239
|
}
|
|
3478
4240
|
}, [publicKey, tokens, fetchTokenBalance]);
|
|
3479
|
-
const getTotalValue =
|
|
4241
|
+
const getTotalValue = React4.useCallback(
|
|
3480
4242
|
(priceData) => {
|
|
3481
4243
|
if (!priceData) return 0;
|
|
3482
4244
|
return balances.reduce((total, balance) => {
|
|
@@ -3515,21 +4277,21 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3515
4277
|
retryInterval = 1e4
|
|
3516
4278
|
// 10 seconds
|
|
3517
4279
|
} = options;
|
|
3518
|
-
const [status, setStatus] =
|
|
3519
|
-
const [paymentStatus, setPaymentStatus] =
|
|
3520
|
-
const [isLoading, setIsLoading] =
|
|
3521
|
-
const [error, setError] =
|
|
3522
|
-
const [retryCount, setRetryCount] =
|
|
3523
|
-
const intervalRef =
|
|
3524
|
-
const isMonitoringRef =
|
|
3525
|
-
|
|
4280
|
+
const [status, setStatus] = React4.useState(null);
|
|
4281
|
+
const [paymentStatus, setPaymentStatus] = React4.useState(null);
|
|
4282
|
+
const [isLoading, setIsLoading] = React4.useState(false);
|
|
4283
|
+
const [error, setError] = React4.useState(null);
|
|
4284
|
+
const [retryCount, setRetryCount] = React4.useState(0);
|
|
4285
|
+
const intervalRef = React4.useRef(null);
|
|
4286
|
+
const isMonitoringRef = React4.useRef(false);
|
|
4287
|
+
React4.useEffect(() => {
|
|
3526
4288
|
return () => {
|
|
3527
4289
|
if (intervalRef.current) {
|
|
3528
4290
|
clearInterval(intervalRef.current);
|
|
3529
4291
|
}
|
|
3530
4292
|
};
|
|
3531
4293
|
}, []);
|
|
3532
|
-
const checkTransactionStatus =
|
|
4294
|
+
const checkTransactionStatus = React4.useCallback(
|
|
3533
4295
|
async (signature) => {
|
|
3534
4296
|
try {
|
|
3535
4297
|
const statusResponse = await connection.getSignatureStatus(signature, {
|
|
@@ -3574,7 +4336,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3574
4336
|
},
|
|
3575
4337
|
[connection]
|
|
3576
4338
|
);
|
|
3577
|
-
const checkPaymentStatus =
|
|
4339
|
+
const checkPaymentStatus = React4.useCallback(
|
|
3578
4340
|
async (id) => {
|
|
3579
4341
|
try {
|
|
3580
4342
|
return await client.getPaymentStatus(id);
|
|
@@ -3588,7 +4350,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3588
4350
|
},
|
|
3589
4351
|
[client]
|
|
3590
4352
|
);
|
|
3591
|
-
const startMonitoring =
|
|
4353
|
+
const startMonitoring = React4.useCallback(async () => {
|
|
3592
4354
|
if (isMonitoringRef.current || !transactionId && !purchaseId) {
|
|
3593
4355
|
return;
|
|
3594
4356
|
}
|
|
@@ -3676,14 +4438,14 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3676
4438
|
retryInterval,
|
|
3677
4439
|
retryCount
|
|
3678
4440
|
]);
|
|
3679
|
-
const stopMonitoring =
|
|
4441
|
+
const stopMonitoring = React4.useCallback(() => {
|
|
3680
4442
|
if (intervalRef.current) {
|
|
3681
4443
|
clearInterval(intervalRef.current);
|
|
3682
4444
|
}
|
|
3683
4445
|
isMonitoringRef.current = false;
|
|
3684
4446
|
setIsLoading(false);
|
|
3685
4447
|
}, []);
|
|
3686
|
-
const checkStatus =
|
|
4448
|
+
const checkStatus = React4.useCallback(async () => {
|
|
3687
4449
|
if (!transactionId && !purchaseId) return;
|
|
3688
4450
|
setIsLoading(true);
|
|
3689
4451
|
setError(null);
|
|
@@ -3708,7 +4470,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3708
4470
|
setIsLoading(false);
|
|
3709
4471
|
}
|
|
3710
4472
|
}, [transactionId, purchaseId, checkTransactionStatus, checkPaymentStatus]);
|
|
3711
|
-
|
|
4473
|
+
React4.useEffect(() => {
|
|
3712
4474
|
if ((transactionId || purchaseId) && !isMonitoringRef.current) {
|
|
3713
4475
|
startMonitoring();
|
|
3714
4476
|
}
|
|
@@ -3716,7 +4478,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3716
4478
|
stopMonitoring();
|
|
3717
4479
|
};
|
|
3718
4480
|
}, [transactionId, purchaseId, startMonitoring, stopMonitoring]);
|
|
3719
|
-
const getConfirmationStatus =
|
|
4481
|
+
const getConfirmationStatus = React4.useCallback(() => {
|
|
3720
4482
|
if (paymentStatus?.status === "confirmed") return "confirmed";
|
|
3721
4483
|
if (paymentStatus?.status === "failed") return "failed";
|
|
3722
4484
|
if (status?.confirmationStatus === "finalized") return "confirmed";
|
|
@@ -3725,7 +4487,7 @@ var usePaymentStatus = (options = {}) => {
|
|
|
3725
4487
|
return "failed";
|
|
3726
4488
|
return "pending";
|
|
3727
4489
|
}, [status, paymentStatus]);
|
|
3728
|
-
const getSolscanUrl =
|
|
4490
|
+
const getSolscanUrl = React4.useCallback(
|
|
3729
4491
|
(signature) => {
|
|
3730
4492
|
const txId = signature || transactionId;
|
|
3731
4493
|
if (!txId) return null;
|
|
@@ -3766,9 +4528,13 @@ exports.SolanaPaymentView = SolanaPaymentView;
|
|
|
3766
4528
|
exports.StoredPaymentMethods = StoredPaymentMethods;
|
|
3767
4529
|
exports.SubscriptionCheckoutModal = SubscriptionCheckoutModal;
|
|
3768
4530
|
exports.SubscriptionSuccessDialog = SubscriptionSuccessDialog;
|
|
4531
|
+
exports.SubscriptionsSection = SubscriptionsSection;
|
|
3769
4532
|
exports.WalletDialog = WalletDialog;
|
|
3770
4533
|
exports.WalletModal = WalletModal;
|
|
3771
4534
|
exports.createClient = createClient;
|
|
4535
|
+
exports.defaultCardDetailsFormTranslations = defaultCardDetailsFormTranslations;
|
|
4536
|
+
exports.defaultPaymentExperienceTranslations = defaultPaymentExperienceTranslations;
|
|
4537
|
+
exports.defaultTranslations = defaultTranslations3;
|
|
3772
4538
|
exports.usePaymentContext = usePaymentContext;
|
|
3773
4539
|
exports.usePaymentDialogs = usePaymentDialogs;
|
|
3774
4540
|
exports.usePaymentMethods = usePaymentMethods;
|