@doujins/payments-ui 0.0.12 → 0.0.13

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 CHANGED
@@ -1,27 +1,30 @@
1
1
  'use strict';
2
2
 
3
3
  var React3 = require('react');
4
- var vanilla = require('zustand/vanilla');
5
- var jsxRuntime = require('react/jsx-runtime');
4
+ var reactQuery = require('@tanstack/react-query');
5
+ var walletAdapterReact = require('@solana/wallet-adapter-react');
6
+ var walletAdapterReactUi = require('@solana/wallet-adapter-react-ui');
7
+ require('@solana/wallet-adapter-react-ui/styles.css');
8
+ var web3_js = require('@solana/web3.js');
9
+ var walletAdapterPhantom = require('@solana/wallet-adapter-phantom');
10
+ var walletAdapterSolflare = require('@solana/wallet-adapter-solflare');
11
+ var walletAdapterTrust = require('@solana/wallet-adapter-trust');
12
+ var walletAdapterCoinbase = require('@solana/wallet-adapter-coinbase');
13
+ var DialogPrimitive = require('@radix-ui/react-dialog');
6
14
  var lucideReact = require('lucide-react');
7
- var countryList = require('country-list');
8
- var classVarianceAuthority = require('class-variance-authority');
9
15
  var clsx = require('clsx');
10
16
  var tailwindMerge = require('tailwind-merge');
17
+ var jsxRuntime = require('react/jsx-runtime');
18
+ var countryList = require('country-list');
19
+ var classVarianceAuthority = require('class-variance-authority');
11
20
  var LabelPrimitive = require('@radix-ui/react-label');
12
21
  var SelectPrimitive = require('@radix-ui/react-select');
13
- var reactQuery = require('@tanstack/react-query');
14
- var DialogPrimitive = require('@radix-ui/react-dialog');
15
22
  var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
16
- var walletAdapterReact = require('@solana/wallet-adapter-react');
23
+ var TabsPrimitive = require('@radix-ui/react-tabs');
17
24
  var buffer = require('buffer');
18
- var web3_js = require('@solana/web3.js');
19
25
  var splToken = require('@solana/spl-token');
20
26
  var QRCode = require('qrcode');
21
- var zustand = require('zustand');
22
- var TabsPrimitive = require('@radix-ui/react-tabs');
23
27
  var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
24
- var walletAdapterReactUi = require('@solana/wallet-adapter-react-ui');
25
28
  var bs58 = require('bs58');
26
29
  var CheckboxPrimitive = require('@radix-ui/react-checkbox');
27
30
 
@@ -46,13 +49,13 @@ function _interopNamespace(e) {
46
49
  }
47
50
 
48
51
  var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
52
+ var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
49
53
  var countryList__default = /*#__PURE__*/_interopDefault(countryList);
50
54
  var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
51
55
  var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
52
- var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
53
56
  var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPrimitive);
54
- var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
55
57
  var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
58
+ var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
56
59
  var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
57
60
  var bs58__default = /*#__PURE__*/_interopDefault(bs58);
58
61
  var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
@@ -524,141 +527,98 @@ var PaymentApp = class {
524
527
  };
525
528
  }
526
529
  };
527
- var initialState = {
528
- selectedMethodId: null,
529
- solanaModalOpen: false,
530
- savedPaymentStatus: "idle",
531
- savedPaymentError: null,
532
- newCardStatus: "idle",
533
- newCardError: null,
534
- solanaTab: "wallet",
535
- solanaStatus: "selecting",
536
- solanaError: null,
537
- solanaTransactionId: null,
538
- solanaSelectedToken: null,
539
- solanaTokenAmount: 0
540
- };
541
- var createPaymentStore = (options) => vanilla.createStore((set, get) => {
542
- const notifyStatus = (status, context) => {
543
- options?.callbacks?.onStatusChange?.({ status, context });
544
- };
545
- const notifySuccess = (payload) => {
546
- if (!options?.callbacks?.onSuccess) return;
547
- options.callbacks.onSuccess(payload ?? {});
548
- };
549
- const notifyError = (error) => {
550
- options?.callbacks?.onError?.(new Error(error));
551
- };
552
- return {
553
- ...initialState,
554
- setSelectedMethod: (methodId) => {
555
- if (get().selectedMethodId === methodId) return;
556
- set({ selectedMethodId: methodId });
557
- },
558
- setSolanaModalOpen: (open) => {
559
- if (get().solanaModalOpen === open) return;
560
- set({ solanaModalOpen: open });
561
- },
562
- setSolanaTab: (tab) => {
563
- if (get().solanaTab === tab) return;
564
- set({ solanaTab: tab });
565
- },
566
- setSolanaSelectedToken: (symbol) => {
567
- if (get().solanaSelectedToken === symbol) return;
568
- set({ solanaSelectedToken: symbol });
569
- },
570
- setSolanaTokenAmount: (amount) => {
571
- if (get().solanaTokenAmount === amount) return;
572
- set({ solanaTokenAmount: amount });
573
- },
574
- setSolanaTransactionId: (txId) => {
575
- if (get().solanaTransactionId === txId) return;
576
- set({ solanaTransactionId: txId });
577
- },
578
- startSavedPayment: () => {
579
- notifyStatus("processing", { source: "saved-payment" });
580
- set({ savedPaymentStatus: "processing", savedPaymentError: null });
581
- },
582
- completeSavedPayment: () => {
583
- notifyStatus("success", { source: "saved-payment" });
584
- set({ savedPaymentStatus: "success", savedPaymentError: null });
585
- },
586
- failSavedPayment: (error) => {
587
- notifyStatus("error", { source: "saved-payment" });
588
- notifyError(error);
589
- set({ savedPaymentStatus: "error", savedPaymentError: error });
590
- },
591
- resetSavedPayment: () => set({ savedPaymentStatus: "idle", savedPaymentError: null }),
592
- startNewCardPayment: () => {
593
- notifyStatus("processing", { source: "new-card" });
594
- set({ newCardStatus: "processing", newCardError: null });
595
- },
596
- completeNewCardPayment: () => {
597
- notifyStatus("success", { source: "new-card" });
598
- set({ newCardStatus: "success", newCardError: null });
599
- },
600
- failNewCardPayment: (error) => {
601
- notifyStatus("error", { source: "new-card" });
602
- notifyError(error);
603
- set({ newCardStatus: "error", newCardError: error });
604
- },
605
- resetNewCardPayment: () => set({ newCardStatus: "idle", newCardError: null }),
606
- startSolanaPayment: () => {
607
- notifyStatus("processing", { source: "solana" });
608
- set({ solanaStatus: "processing", solanaError: null });
609
- },
610
- confirmSolanaPayment: () => set({ solanaStatus: "confirming" }),
611
- completeSolanaPayment: (payload) => {
612
- notifyStatus("success", { source: "solana" });
613
- notifySuccess(payload);
614
- set({ solanaStatus: "success", solanaError: null });
615
- },
616
- failSolanaPayment: (error) => {
617
- notifyStatus("error", { source: "solana" });
618
- notifyError(error);
619
- set({ solanaStatus: "error", solanaError: error });
530
+
531
+ // src/runtime/PaymentsRuntime.ts
532
+ var createQueryClient = () => new reactQuery.QueryClient({
533
+ defaultOptions: {
534
+ queries: {
535
+ staleTime: 3e4,
536
+ gcTime: 5 * 6e4,
537
+ refetchOnWindowFocus: false,
538
+ retry: 1
620
539
  },
621
- resetSolanaPayment: () => set({
622
- solanaStatus: "selecting",
623
- solanaError: null,
624
- solanaTransactionId: null
625
- }),
626
- resetAll: () => set(initialState)
627
- };
540
+ mutations: {
541
+ retry: 1
542
+ }
543
+ }
628
544
  });
629
- var PaymentContext = React3.createContext(void 0);
630
- var PaymentProvider = ({
631
- config,
632
- children
633
- }) => {
634
- const app = React3.useMemo(() => new PaymentApp({ config }), [config]);
635
- const store = React3.useMemo(
636
- () => createPaymentStore({ callbacks: config.callbacks }),
637
- [config.callbacks]
638
- );
639
- const value = React3.useMemo(() => {
640
- return {
641
- config: app.getConfig(),
642
- fetcher: app.getFetcher(),
643
- resolveAuthToken: app.resolveAuthToken,
644
- app,
645
- services: app.getServices(),
646
- store
647
- };
648
- }, [app, store]);
649
- React3.useEffect(() => {
650
- if (!value.config.collectJsKey) return;
651
- loadCollectJs(value.config.collectJsKey);
652
- }, [value.config.collectJsKey]);
653
- return /* @__PURE__ */ jsxRuntime.jsx(PaymentContext.Provider, { value, children });
654
- };
655
- var usePaymentContext = () => {
656
- const context = React3.useContext(PaymentContext);
657
- if (!context) {
658
- throw new Error("usePaymentContext must be used within a PaymentProvider");
545
+ var PaymentsRuntime = class {
546
+ constructor(config) {
547
+ this.config = config;
548
+ this.app = new PaymentApp({ config });
549
+ this.services = this.app.getServices();
550
+ this.queryClient = createQueryClient();
659
551
  }
660
- return context;
661
552
  };
553
+ var createPaymentsRuntime = (config) => new PaymentsRuntime(config);
554
+
555
+ // node_modules/@solana/wallet-adapter-base/lib/esm/types.js
556
+ var WalletAdapterNetwork;
557
+ (function(WalletAdapterNetwork2) {
558
+ WalletAdapterNetwork2["Mainnet"] = "mainnet-beta";
559
+ WalletAdapterNetwork2["Testnet"] = "testnet";
560
+ WalletAdapterNetwork2["Devnet"] = "devnet";
561
+ })(WalletAdapterNetwork || (WalletAdapterNetwork = {}));
562
+ function cn(...inputs) {
563
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
564
+ }
565
+ var Dialog = DialogPrimitive__namespace.Root;
566
+ var DialogPortal = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { className: cn(className), ...props });
567
+ DialogPortal.displayName = DialogPrimitive__namespace.Portal.displayName;
568
+ var DialogOverlay = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
569
+ DialogPrimitive__namespace.Overlay,
570
+ {
571
+ ref,
572
+ className: cn(
573
+ "fixed inset-0 z-50 bg-black/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
574
+ className
575
+ ),
576
+ ...props
577
+ }
578
+ ));
579
+ DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
580
+ var DialogContent = React3__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
581
+ /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
582
+ /* @__PURE__ */ jsxRuntime.jsxs(
583
+ DialogPrimitive__namespace.Content,
584
+ {
585
+ ref,
586
+ className: cn(
587
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
588
+ className
589
+ ),
590
+ ...props,
591
+ children: [
592
+ children,
593
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [
594
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }),
595
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
596
+ ] })
597
+ ]
598
+ }
599
+ )
600
+ ] }));
601
+ DialogContent.displayName = DialogPrimitive__namespace.Content.displayName;
602
+ var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
603
+ DialogHeader.displayName = "DialogHeader";
604
+ var DialogTitle = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
605
+ DialogPrimitive__namespace.Title,
606
+ {
607
+ ref,
608
+ className: cn("text-lg font-semibold leading-none tracking-tight", className),
609
+ ...props
610
+ }
611
+ ));
612
+ DialogTitle.displayName = DialogPrimitive__namespace.Title.displayName;
613
+ var DialogDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
614
+ DialogPrimitive__namespace.Description,
615
+ {
616
+ ref,
617
+ className: cn("text-sm text-muted-foreground", className),
618
+ ...props
619
+ }
620
+ ));
621
+ DialogDescription.displayName = DialogPrimitive__namespace.Description.displayName;
662
622
  var customCountries = [
663
623
  { code: "TW", name: "Taiwan, Province of China" },
664
624
  { code: "KR", name: "Korea" },
@@ -788,9 +748,6 @@ function getElementRef(element) {
788
748
  }
789
749
  return element.props.ref || element.ref;
790
750
  }
791
- function cn(...inputs) {
792
- return tailwindMerge.twMerge(clsx.clsx(inputs));
793
- }
794
751
  var buttonVariants = classVarianceAuthority.cva(
795
752
  "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
796
753
  {
@@ -933,7 +890,6 @@ var defaultBilling = {
933
890
  firstName: "",
934
891
  lastName: "",
935
892
  address1: "",
936
- address2: "",
937
893
  city: "",
938
894
  stateRegion: "",
939
895
  postalCode: "",
@@ -967,7 +923,6 @@ var CardDetailsForm = ({
967
923
  const [firstName, setFirstName] = React3.useState(mergedDefaults.firstName);
968
924
  const [lastName, setLastName] = React3.useState(mergedDefaults.lastName);
969
925
  const [address1, setAddress1] = React3.useState(mergedDefaults.address1);
970
- const [address2, setAddress2] = React3.useState(mergedDefaults.address2 ?? "");
971
926
  const [city, setCity] = React3.useState(mergedDefaults.city);
972
927
  const [stateRegion, setStateRegion] = React3.useState(mergedDefaults.stateRegion ?? "");
973
928
  const [postalCode, setPostalCode] = React3.useState(mergedDefaults.postalCode);
@@ -986,7 +941,6 @@ var CardDetailsForm = ({
986
941
  setFirstName(mergedDefaults.firstName);
987
942
  setLastName(mergedDefaults.lastName);
988
943
  setAddress1(mergedDefaults.address1);
989
- setAddress2(mergedDefaults.address2 ?? "");
990
944
  setCity(mergedDefaults.city);
991
945
  setStateRegion(mergedDefaults.stateRegion ?? "");
992
946
  setPostalCode(mergedDefaults.postalCode);
@@ -999,7 +953,6 @@ var CardDetailsForm = ({
999
953
  firstName,
1000
954
  lastName,
1001
955
  address1,
1002
- address2,
1003
956
  city,
1004
957
  stateRegion,
1005
958
  postalCode,
@@ -1011,7 +964,6 @@ var CardDetailsForm = ({
1011
964
  firstName,
1012
965
  lastName,
1013
966
  address1,
1014
- address2,
1015
967
  city,
1016
968
  stateRegion,
1017
969
  postalCode,
@@ -1035,7 +987,6 @@ var CardDetailsForm = ({
1035
987
  firstName,
1036
988
  lastName,
1037
989
  address1,
1038
- address2,
1039
990
  city,
1040
991
  stateRegion,
1041
992
  postalCode,
@@ -1066,7 +1017,6 @@ var CardDetailsForm = ({
1066
1017
  firstName,
1067
1018
  lastName,
1068
1019
  address1,
1069
- address2,
1070
1020
  city,
1071
1021
  stateRegion,
1072
1022
  postalCode,
@@ -1095,19 +1045,16 @@ var CardDetailsForm = ({
1095
1045
  window.CollectJS.startPaymentRequest();
1096
1046
  };
1097
1047
  const errorMessage = localError ?? externalError;
1098
- const collectFieldClass = "flex h-11 w-full items-center rounded-md border border-dashed border-muted-foreground/40 bg-muted/20 px-3 text-sm text-muted-foreground";
1048
+ const collectFieldClass = "flex h-11 w-full items-center rounded-md border border-border/60 bg-background px-3 text-sm text-muted-foreground";
1099
1049
  return /* @__PURE__ */ jsxRuntime.jsxs(
1100
1050
  "form",
1101
1051
  {
1102
- className: cn(
1103
- "space-y-6 rounded-2xl border border-border/60 bg-card/90 p-6 shadow-lg",
1104
- className
1105
- ),
1052
+ className: cn("space-y-5", className),
1106
1053
  onSubmit: handleSubmit,
1107
1054
  noValidate: true,
1108
1055
  children: [
1109
1056
  errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 px-4 py-2 text-sm text-destructive", children: errorMessage }),
1110
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
1057
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [
1111
1058
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1112
1059
  /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-first", className: "flex items-center gap-2 text-muted-foreground", children: [
1113
1060
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4" }),
@@ -1153,7 +1100,7 @@ var CardDetailsForm = ({
1153
1100
  )
1154
1101
  ] }),
1155
1102
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1156
- /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-address1", children: "Address line 1" }),
1103
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-address1", children: "Address" }),
1157
1104
  /* @__PURE__ */ jsxRuntime.jsx(
1158
1105
  Input,
1159
1106
  {
@@ -1164,18 +1111,7 @@ var CardDetailsForm = ({
1164
1111
  }
1165
1112
  )
1166
1113
  ] }),
1167
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1168
- /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-address2", children: "Address line 2 (optional)" }),
1169
- /* @__PURE__ */ jsxRuntime.jsx(
1170
- Input,
1171
- {
1172
- id: "payments-address2",
1173
- value: address2,
1174
- onChange: (e) => setAddress2(e.target.value)
1175
- }
1176
- )
1177
- ] }),
1178
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
1114
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [
1179
1115
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1180
1116
  /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-city", children: "City" }),
1181
1117
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1200,7 +1136,7 @@ var CardDetailsForm = ({
1200
1136
  )
1201
1137
  ] })
1202
1138
  ] }),
1203
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [
1139
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5 md:grid-cols-2", children: [
1204
1140
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1205
1141
  /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-postal", className: "flex items-center gap-2 text-muted-foreground", children: [
1206
1142
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-4 w-4" }),
@@ -1220,7 +1156,7 @@ var CardDetailsForm = ({
1220
1156
  /* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Country" }),
1221
1157
  /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: country, onValueChange: setCountry, children: [
1222
1158
  /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select a country" }) }),
1223
- /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "max-h-64", children: countries.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.code, children: option.name }, option.code)) })
1159
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "max-h-64 w-full", children: countries.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.code, children: option.name }, option.code)) })
1224
1160
  ] })
1225
1161
  ] })
1226
1162
  ] }),
@@ -1309,63 +1245,6 @@ var usePaymentMethods = () => {
1309
1245
  deleteMutation
1310
1246
  };
1311
1247
  };
1312
- var Dialog = DialogPrimitive__namespace.Root;
1313
- var DialogPortal = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { className: cn(className), ...props });
1314
- DialogPortal.displayName = DialogPrimitive__namespace.Portal.displayName;
1315
- var DialogOverlay = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1316
- DialogPrimitive__namespace.Overlay,
1317
- {
1318
- ref,
1319
- className: cn(
1320
- "fixed inset-0 z-50 bg-black/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in",
1321
- className
1322
- ),
1323
- ...props
1324
- }
1325
- ));
1326
- DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
1327
- var DialogContent = React3__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
1328
- /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1329
- /* @__PURE__ */ jsxRuntime.jsxs(
1330
- DialogPrimitive__namespace.Content,
1331
- {
1332
- ref,
1333
- className: cn(
1334
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
1335
- className
1336
- ),
1337
- ...props,
1338
- children: [
1339
- children,
1340
- /* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none", children: [
1341
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }),
1342
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
1343
- ] })
1344
- ]
1345
- }
1346
- )
1347
- ] }));
1348
- DialogContent.displayName = DialogPrimitive__namespace.Content.displayName;
1349
- var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
1350
- DialogHeader.displayName = "DialogHeader";
1351
- var DialogTitle = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1352
- DialogPrimitive__namespace.Title,
1353
- {
1354
- ref,
1355
- className: cn("text-lg font-semibold leading-none tracking-tight", className),
1356
- ...props
1357
- }
1358
- ));
1359
- DialogTitle.displayName = DialogPrimitive__namespace.Title.displayName;
1360
- var DialogDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1361
- DialogPrimitive__namespace.Description,
1362
- {
1363
- ref,
1364
- className: cn("text-sm text-muted-foreground", className),
1365
- ...props
1366
- }
1367
- ));
1368
- DialogDescription.displayName = DialogPrimitive__namespace.Description.displayName;
1369
1248
  var badgeVariants = classVarianceAuthority.cva(
1370
1249
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none",
1371
1250
  {
@@ -1415,43 +1294,6 @@ var ScrollBar = React3__namespace.forwardRef(({ className, orientation = "vertic
1415
1294
  }
1416
1295
  ));
1417
1296
  ScrollBar.displayName = ScrollAreaPrimitive__namespace.ScrollAreaScrollbar.displayName;
1418
- var Card = React3__namespace.forwardRef(
1419
- ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1420
- "div",
1421
- {
1422
- ref,
1423
- className: cn("rounded-xl border bg-card text-card-foreground shadow", className),
1424
- ...props
1425
- }
1426
- )
1427
- );
1428
- Card.displayName = "Card";
1429
- var CardHeader = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1430
- "div",
1431
- {
1432
- ref,
1433
- className: cn("flex flex-col space-y-1.5 p-6", className),
1434
- ...props
1435
- }
1436
- ));
1437
- CardHeader.displayName = "CardHeader";
1438
- var CardTitle = React3__namespace.forwardRef(
1439
- ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
1440
- );
1441
- CardTitle.displayName = "CardTitle";
1442
- var CardDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1443
- CardDescription.displayName = "CardDescription";
1444
- var CardContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
1445
- CardContent.displayName = "CardContent";
1446
- var CardFooter = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1447
- "div",
1448
- {
1449
- ref,
1450
- className: cn("flex items-center p-6 pt-0", className),
1451
- ...props
1452
- }
1453
- ));
1454
- CardFooter.displayName = "CardFooter";
1455
1297
  var formatCardLabel = (method) => {
1456
1298
  const brand = method.card_type ? method.card_type.toUpperCase() : "CARD";
1457
1299
  const lastFour = method.last_four ? `\u2022\u2022\u2022\u2022 ${method.last_four}` : "";
@@ -1480,22 +1322,22 @@ var StoredPaymentMethods = ({
1480
1322
  }
1481
1323
  );
1482
1324
  };
1483
- return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-border/60 bg-card/95", children: [
1484
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-row items-start justify-between space-y-0", children: [
1485
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1486
- /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-base font-semibold text-foreground", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-muted-foreground", children: [
1325
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
1326
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
1327
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1328
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-medium text-muted-foreground", children: [
1487
1329
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WalletCards, { className: "h-4 w-4" }),
1488
1330
  " ",
1489
1331
  heading
1490
- ] }) }),
1491
- /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: description })
1332
+ ] }),
1333
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: description })
1492
1334
  ] }),
1493
- showAddButton && /* @__PURE__ */ jsxRuntime.jsxs(Button, { size: "sm", onClick: () => setIsModalOpen(true), children: [
1335
+ showAddButton && /* @__PURE__ */ jsxRuntime.jsxs(Button, { size: "sm", variant: "outline", onClick: () => setIsModalOpen(true), children: [
1494
1336
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
1495
1337
  " Add card"
1496
1338
  ] })
1497
1339
  ] }),
1498
- /* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: listQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center rounded-lg border border-dashed border-border/60 bg-muted/10 py-8 text-sm text-muted-foreground", children: [
1340
+ listQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center rounded-lg border border-dashed border-border/60 bg-muted/10 py-8 text-sm text-muted-foreground", children: [
1499
1341
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
1500
1342
  " Loading cards\u2026"
1501
1343
  ] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-border/60 bg-muted/10 px-4 py-6 text-sm text-muted-foreground", children: "No saved payment methods yet." }) : /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "max-h-[320px] pr-2", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) => {
@@ -1553,8 +1395,8 @@ var StoredPaymentMethods = ({
1553
1395
  },
1554
1396
  method.id
1555
1397
  );
1556
- }) }) }) }),
1557
- /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-h-[90vh] overflow-y-auto", children: [
1398
+ }) }) }),
1399
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-h-[85vh] overflow-y-auto", children: [
1558
1400
  /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
1559
1401
  /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Add a new card" }),
1560
1402
  /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "Your card details are tokenized securely via our payment provider." })
@@ -1573,12 +1415,77 @@ var StoredPaymentMethods = ({
1573
1415
  ] }) })
1574
1416
  ] });
1575
1417
  };
1576
- var useSolanaService = () => {
1577
- const { services } = usePaymentContext();
1578
- return React3.useMemo(() => services.solanaPayments, [services]);
1579
- };
1580
- var getSolBalance = async (connection, publicKey) => {
1581
- try {
1418
+ var Tabs = TabsPrimitive__namespace.Root;
1419
+ var TabsList = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1420
+ TabsPrimitive__namespace.List,
1421
+ {
1422
+ ref,
1423
+ className: cn(
1424
+ "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
1425
+ className
1426
+ ),
1427
+ ...props
1428
+ }
1429
+ ));
1430
+ TabsList.displayName = TabsPrimitive__namespace.List.displayName;
1431
+ var TabsTrigger = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1432
+ TabsPrimitive__namespace.Trigger,
1433
+ {
1434
+ ref,
1435
+ className: cn(
1436
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
1437
+ className
1438
+ ),
1439
+ ...props
1440
+ }
1441
+ ));
1442
+ TabsTrigger.displayName = TabsPrimitive__namespace.Trigger.displayName;
1443
+ var TabsContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1444
+ TabsPrimitive__namespace.Content,
1445
+ {
1446
+ ref,
1447
+ className: cn(
1448
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
1449
+ className
1450
+ ),
1451
+ ...props
1452
+ }
1453
+ ));
1454
+ TabsContent.displayName = TabsPrimitive__namespace.Content.displayName;
1455
+ var usePaymentNotifications = () => {
1456
+ const { config } = usePaymentContext();
1457
+ const notifyStatus = React3.useCallback(
1458
+ (status, context) => {
1459
+ config.callbacks?.onStatusChange?.({ status, context });
1460
+ },
1461
+ [config.callbacks]
1462
+ );
1463
+ const notifySuccess = React3.useCallback(
1464
+ (payload) => {
1465
+ config.callbacks?.onSuccess?.(payload ?? {});
1466
+ },
1467
+ [config.callbacks]
1468
+ );
1469
+ const notifyError = React3.useCallback(
1470
+ (error) => {
1471
+ config.callbacks?.onError?.(
1472
+ typeof error === "string" ? new Error(error) : error
1473
+ );
1474
+ },
1475
+ [config.callbacks]
1476
+ );
1477
+ return {
1478
+ notifyStatus,
1479
+ notifySuccess,
1480
+ notifyError
1481
+ };
1482
+ };
1483
+ var useSolanaService = () => {
1484
+ const { services } = usePaymentContext();
1485
+ return React3.useMemo(() => services.solanaPayments, [services]);
1486
+ };
1487
+ var getSolBalance = async (connection, publicKey) => {
1488
+ try {
1582
1489
  const lamports = await connection.getBalance(publicKey);
1583
1490
  return lamports / web3_js.LAMPORTS_PER_SOL;
1584
1491
  } catch (error) {
@@ -1849,6 +1756,43 @@ var useSolanaDirectPayment = (options) => {
1849
1756
  pay
1850
1757
  };
1851
1758
  };
1759
+ var Card = React3__namespace.forwardRef(
1760
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1761
+ "div",
1762
+ {
1763
+ ref,
1764
+ className: cn("rounded-xl border bg-card text-card-foreground shadow", className),
1765
+ ...props
1766
+ }
1767
+ )
1768
+ );
1769
+ Card.displayName = "Card";
1770
+ var CardHeader = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1771
+ "div",
1772
+ {
1773
+ ref,
1774
+ className: cn("flex flex-col space-y-1.5 p-6", className),
1775
+ ...props
1776
+ }
1777
+ ));
1778
+ CardHeader.displayName = "CardHeader";
1779
+ var CardTitle = React3__namespace.forwardRef(
1780
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
1781
+ );
1782
+ CardTitle.displayName = "CardTitle";
1783
+ var CardDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1784
+ CardDescription.displayName = "CardDescription";
1785
+ var CardContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
1786
+ CardContent.displayName = "CardContent";
1787
+ var CardFooter = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1788
+ "div",
1789
+ {
1790
+ ref,
1791
+ className: cn("flex items-center p-6 pt-0", className),
1792
+ ...props
1793
+ }
1794
+ ));
1795
+ CardFooter.displayName = "CardFooter";
1852
1796
  var DirectPayment = ({
1853
1797
  priceId,
1854
1798
  tokenAmount,
@@ -1869,7 +1813,7 @@ var DirectPayment = ({
1869
1813
  onSuccess: onPaymentSuccess,
1870
1814
  onError: onPaymentError
1871
1815
  });
1872
- return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "space-y-4 border border-border/60 bg-background/80 p-6", children: [
1816
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "space-y-4 rounded-md border border-border/60 bg-background/80 shadow-none p-6", children: [
1873
1817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1874
1818
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [
1875
1819
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-4 w-4" }),
@@ -2101,9 +2045,9 @@ var QRCodePayment = ({
2101
2045
  onSuccess: onPaymentSuccess
2102
2046
  });
2103
2047
  if (!selectedToken) {
2104
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-dashed border-border/60 bg-muted/10 px-4 py-6 text-center text-sm text-muted-foreground", children: "Select a token to continue." });
2048
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-dashed border-border/60 bg-muted/10 px-4 py-6 text-center text-sm text-muted-foreground", children: "Select a token to continue." });
2105
2049
  }
2106
- return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "space-y-4 border border-border/60 bg-background/80 p-6", children: [
2050
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "space-y-4 border border-border/60 bg-background/80 p-6 shadow-none rounded-md", children: [
2107
2051
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
2108
2052
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2109
2053
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Scan with Solana Pay" }),
@@ -2332,109 +2276,21 @@ var useSupportedTokens = () => {
2332
2276
  tokenCount: tokens.length
2333
2277
  };
2334
2278
  };
2335
- var usePaymentStore = (selector) => {
2336
- const { store } = usePaymentContext();
2337
- return zustand.useStore(store, selector);
2338
- };
2339
-
2340
- // src/state/selectors.ts
2341
- var selectCheckoutFlow = (state) => ({
2342
- selectedMethodId: state.selectedMethodId,
2343
- savedStatus: state.savedPaymentStatus,
2344
- savedError: state.savedPaymentError,
2345
- newCardStatus: state.newCardStatus,
2346
- newCardError: state.newCardError,
2347
- solanaModalOpen: state.solanaModalOpen,
2348
- setSelectedMethod: state.setSelectedMethod,
2349
- setSolanaModalOpen: state.setSolanaModalOpen,
2350
- startSavedPayment: state.startSavedPayment,
2351
- completeSavedPayment: state.completeSavedPayment,
2352
- failSavedPayment: state.failSavedPayment,
2353
- startNewCardPayment: state.startNewCardPayment,
2354
- completeNewCardPayment: state.completeNewCardPayment,
2355
- failNewCardPayment: state.failNewCardPayment,
2356
- resetSavedPayment: state.resetSavedPayment
2357
- });
2358
- var selectSolanaFlow = (state) => ({
2359
- tab: state.solanaTab,
2360
- status: state.solanaStatus,
2361
- error: state.solanaError,
2362
- transactionId: state.solanaTransactionId,
2363
- tokenAmount: state.solanaTokenAmount,
2364
- selectedTokenSymbol: state.solanaSelectedToken,
2365
- setTab: state.setSolanaTab,
2366
- setTokenAmount: state.setSolanaTokenAmount,
2367
- setTransactionId: state.setSolanaTransactionId,
2368
- setSelectedTokenSymbol: state.setSolanaSelectedToken,
2369
- startSolanaPayment: state.startSolanaPayment,
2370
- confirmSolanaPayment: state.confirmSolanaPayment,
2371
- completeSolanaPayment: state.completeSolanaPayment,
2372
- failSolanaPayment: state.failSolanaPayment,
2373
- resetSolanaPayment: state.resetSolanaPayment
2374
- });
2375
- var Tabs = TabsPrimitive__namespace.Root;
2376
- var TabsList = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2377
- TabsPrimitive__namespace.List,
2378
- {
2379
- ref,
2380
- className: cn(
2381
- "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
2382
- className
2383
- ),
2384
- ...props
2385
- }
2386
- ));
2387
- TabsList.displayName = TabsPrimitive__namespace.List.displayName;
2388
- var TabsTrigger = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2389
- TabsPrimitive__namespace.Trigger,
2390
- {
2391
- ref,
2392
- className: cn(
2393
- "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
2394
- className
2395
- ),
2396
- ...props
2397
- }
2398
- ));
2399
- TabsTrigger.displayName = TabsPrimitive__namespace.Trigger.displayName;
2400
- var TabsContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2401
- TabsPrimitive__namespace.Content,
2402
- {
2403
- ref,
2404
- className: cn(
2405
- "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2406
- className
2407
- ),
2408
- ...props
2409
- }
2410
- ));
2411
- TabsContent.displayName = TabsPrimitive__namespace.Content.displayName;
2412
- var SolanaPaymentSelector = ({
2413
- isOpen,
2414
- onClose,
2279
+ var SolanaPaymentView = ({
2415
2280
  priceId,
2416
2281
  usdAmount,
2417
2282
  onSuccess,
2418
- onError
2283
+ onError,
2284
+ onClose
2419
2285
  }) => {
2420
2286
  const { connected } = walletAdapterReact.useWallet();
2421
- const {
2422
- tab: activeTab,
2423
- status: paymentState,
2424
- error: errorMessage,
2425
- transactionId,
2426
- tokenAmount,
2427
- selectedTokenSymbol,
2428
- setTab,
2429
- setTokenAmount,
2430
- setTransactionId,
2431
- setSelectedTokenSymbol,
2432
- startSolanaPayment,
2433
- confirmSolanaPayment,
2434
- completeSolanaPayment,
2435
- failSolanaPayment,
2436
- resetSolanaPayment
2437
- } = usePaymentStore(selectSolanaFlow);
2287
+ const { notifyStatus, notifyError, notifySuccess } = usePaymentNotifications();
2288
+ const [activeTab, setActiveTab] = React3.useState("wallet");
2289
+ const [paymentState, setPaymentState] = React3.useState("selecting");
2290
+ const [errorMessage, setErrorMessage] = React3.useState(null);
2291
+ const [transactionId, setTransactionId] = React3.useState(null);
2292
+ const [tokenAmount, setTokenAmount] = React3.useState(0);
2293
+ const [selectedTokenSymbol, setSelectedTokenSymbol] = React3.useState(null);
2438
2294
  const {
2439
2295
  tokens,
2440
2296
  isLoading: tokensLoading,
@@ -2450,60 +2306,70 @@ var SolanaPaymentSelector = ({
2450
2306
  const defaultToken = tokens.find((token) => token.symbol === "SOL") || tokens[0];
2451
2307
  setSelectedTokenSymbol(defaultToken.symbol);
2452
2308
  }
2453
- }, [tokens, selectedTokenSymbol, setSelectedTokenSymbol]);
2309
+ }, [tokens, selectedTokenSymbol]);
2454
2310
  const handlePaymentStart = React3.useCallback(() => {
2455
- startSolanaPayment();
2456
- }, [startSolanaPayment]);
2311
+ setPaymentState("processing");
2312
+ setErrorMessage(null);
2313
+ notifyStatus("processing", { source: "solana" });
2314
+ }, [notifyStatus]);
2457
2315
  const handlePaymentConfirming = React3.useCallback(() => {
2458
- confirmSolanaPayment();
2459
- }, [confirmSolanaPayment]);
2316
+ setPaymentState("confirming");
2317
+ }, []);
2460
2318
  const handlePaymentSuccess = React3.useCallback(
2461
2319
  (result, txId) => {
2462
2320
  const resolvedTx = txId || (typeof result === "string" ? result : result.transaction_id);
2463
2321
  setTransactionId(resolvedTx);
2464
- completeSolanaPayment(
2465
- typeof result === "string" ? {
2466
- transactionId: resolvedTx,
2467
- processor: "solana",
2468
- metadata: { source: "solana-pay" }
2469
- } : {
2470
- transactionId: result.transaction_id,
2471
- intentId: result.intent_id,
2472
- processor: "solana",
2473
- metadata: {
2474
- purchaseId: result.purchase_id,
2475
- amount: result.amount,
2476
- currency: result.currency
2477
- }
2322
+ setPaymentState("success");
2323
+ setErrorMessage(null);
2324
+ const payload = typeof result === "string" ? {
2325
+ transactionId: resolvedTx,
2326
+ processor: "solana",
2327
+ metadata: { source: "solana-pay" }
2328
+ } : {
2329
+ transactionId: result.transaction_id,
2330
+ intentId: result.intent_id,
2331
+ processor: "solana",
2332
+ metadata: {
2333
+ purchaseId: result.purchase_id,
2334
+ amount: result.amount,
2335
+ currency: result.currency
2478
2336
  }
2479
- );
2337
+ };
2338
+ notifyStatus("success", { source: "solana" });
2339
+ notifySuccess(payload);
2480
2340
  setTimeout(() => {
2481
2341
  onSuccess(result);
2482
2342
  }, 1500);
2483
2343
  },
2484
- [completeSolanaPayment, onSuccess, setTransactionId]
2344
+ [notifyStatus, notifySuccess, onSuccess]
2485
2345
  );
2486
2346
  const handlePaymentError = React3.useCallback(
2487
2347
  (error) => {
2488
- failSolanaPayment(error);
2348
+ setPaymentState("error");
2349
+ setErrorMessage(error);
2350
+ notifyStatus("error", { source: "solana" });
2351
+ notifyError(error);
2489
2352
  onError?.(error);
2490
2353
  },
2491
- [failSolanaPayment, onError]
2354
+ [notifyError, notifyStatus, onError]
2492
2355
  );
2493
- const handleRetry = React3.useCallback(() => {
2494
- resetSolanaPayment();
2356
+ const resetState = React3.useCallback(() => {
2357
+ setPaymentState("selecting");
2358
+ setErrorMessage(null);
2495
2359
  setTransactionId(null);
2496
- }, [resetSolanaPayment, setTransactionId]);
2360
+ }, []);
2361
+ const handleRetry = React3.useCallback(() => {
2362
+ resetState();
2363
+ }, [resetState]);
2497
2364
  const handleClose = React3.useCallback(() => {
2498
2365
  if (paymentState === "processing" || paymentState === "confirming") {
2499
2366
  return;
2500
2367
  }
2501
- resetSolanaPayment();
2502
- setTransactionId(null);
2503
- onClose();
2504
- }, [paymentState, resetSolanaPayment, setTransactionId, onClose]);
2368
+ resetState();
2369
+ onClose?.();
2370
+ }, [paymentState, onClose, resetState]);
2505
2371
  React3.useEffect(() => {
2506
- if (!isOpen || !selectedToken || usdAmount === 0) {
2372
+ if (!selectedToken || usdAmount === 0) {
2507
2373
  setTokenAmount(0);
2508
2374
  return;
2509
2375
  }
@@ -2513,23 +2379,20 @@ var SolanaPaymentSelector = ({
2513
2379
  return;
2514
2380
  }
2515
2381
  setTokenAmount(usdAmount / price);
2516
- }, [isOpen, usdAmount, selectedToken, setTokenAmount]);
2517
- const handleTokenChange = React3.useCallback(
2518
- (value) => {
2519
- setSelectedTokenSymbol(value);
2520
- },
2521
- [setSelectedTokenSymbol]
2522
- );
2382
+ }, [usdAmount, selectedToken]);
2383
+ const handleTokenChange = React3.useCallback((value) => {
2384
+ setSelectedTokenSymbol(value);
2385
+ }, []);
2523
2386
  const wasConnectedRef = React3.useRef(connected);
2524
2387
  React3.useEffect(() => {
2525
2388
  if (connected && !wasConnectedRef.current) {
2526
- setTab("wallet");
2389
+ setActiveTab("wallet");
2527
2390
  }
2528
2391
  if (!connected && wasConnectedRef.current) {
2529
- setTab("qr");
2392
+ setActiveTab("qr");
2530
2393
  }
2531
2394
  wasConnectedRef.current = connected;
2532
- }, [connected, setTab]);
2395
+ }, [connected]);
2533
2396
  const renderBody = () => {
2534
2397
  if (paymentState !== "selecting") {
2535
2398
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2545,63 +2408,79 @@ var SolanaPaymentSelector = ({
2545
2408
  }
2546
2409
  );
2547
2410
  }
2548
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-6", children: tokensLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center rounded-lg border border-dashed border-border/60 bg-muted/10 py-8 text-sm text-muted-foreground", children: [
2549
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
2550
- " Loading supported tokens\u2026"
2551
- ] }) : tokensError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: tokensError }) : !tokens.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-border/60 bg-muted/10 px-4 py-6 text-sm text-muted-foreground", children: "No payment tokens available." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2552
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border/60 bg-muted/10 p-4 text-center", children: [
2553
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-2xl font-semibold text-foreground", children: [
2411
+ if (tokensLoading) {
2412
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-10 text-sm text-muted-foreground", children: [
2413
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
2414
+ " Loading supported tokens\u2026"
2415
+ ] });
2416
+ }
2417
+ if (tokensError) {
2418
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: tokensError });
2419
+ }
2420
+ if (!tokens.length) {
2421
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "No payment tokens available." });
2422
+ }
2423
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
2424
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 text-center", children: [
2425
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Amount due" }),
2426
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-3xl font-semibold text-foreground", children: [
2554
2427
  "$",
2555
2428
  usdAmount.toFixed(2),
2556
2429
  " USD"
2557
2430
  ] }),
2558
- selectedToken && tokenAmount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm text-muted-foreground", children: [
2431
+ selectedToken && tokenAmount > 0 && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
2559
2432
  "\u2248 ",
2560
2433
  tokenAmount.toFixed(selectedToken.symbol === "SOL" ? 4 : 2),
2561
2434
  " ",
2562
2435
  selectedToken.symbol
2563
2436
  ] })
2564
2437
  ] }),
2565
- /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: selectedToken?.symbol ?? "", onValueChange: handleTokenChange, children: [
2566
- /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select token" }) }),
2567
- /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "max-h-64", children: tokens.map((token) => /* @__PURE__ */ jsxRuntime.jsxs(SelectItem, { value: token.symbol, children: [
2568
- token.name,
2569
- " (",
2570
- token.symbol,
2571
- ")"
2572
- ] }, token.symbol)) })
2438
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
2439
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-foreground", children: "Select token" }),
2440
+ /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: selectedToken?.symbol ?? "", onValueChange: handleTokenChange, children: [
2441
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select token" }) }),
2442
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "max-h-64", children: tokens.map((token) => /* @__PURE__ */ jsxRuntime.jsxs(SelectItem, { value: token.symbol, children: [
2443
+ token.name,
2444
+ " (",
2445
+ token.symbol,
2446
+ ")"
2447
+ ] }, token.symbol)) })
2448
+ ] })
2573
2449
  ] }),
2574
- /* @__PURE__ */ jsxRuntime.jsxs(
2450
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
2575
2451
  Tabs,
2576
2452
  {
2577
2453
  value: activeTab,
2578
- onValueChange: (value) => setTab(value),
2579
- className: "w-full",
2454
+ onValueChange: (value) => setActiveTab(value),
2455
+ className: "w-full space-y-3",
2580
2456
  children: [
2581
- /* @__PURE__ */ jsxRuntime.jsxs(TabsList, { className: "grid w-full grid-cols-2 bg-muted/20", children: [
2457
+ /* @__PURE__ */ jsxRuntime.jsxs(TabsList, { className: "grid w-full grid-cols-2 bg-muted/10", children: [
2582
2458
  /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "wallet", disabled: !connected, children: [
2583
2459
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "mr-2 h-4 w-4" }),
2584
- " Pay with Wallet"
2460
+ " Wallet"
2585
2461
  ] }),
2586
2462
  /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "qr", children: [
2587
2463
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
2588
- " Scan QR Code"
2464
+ " QR Code"
2589
2465
  ] })
2590
2466
  ] }),
2591
- /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "wallet", className: "mt-4", children: activeTab === "wallet" && /* @__PURE__ */ jsxRuntime.jsx(
2592
- DirectPayment,
2593
- {
2594
- priceId,
2595
- tokenAmount,
2596
- selectedToken,
2597
- supportedTokens: tokens,
2598
- onPaymentStart: handlePaymentStart,
2599
- onPaymentConfirming: handlePaymentConfirming,
2600
- onPaymentSuccess: handlePaymentSuccess,
2601
- onPaymentError: handlePaymentError
2602
- }
2603
- ) }),
2604
- /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "qr", className: "mt-4", children: activeTab === "qr" && /* @__PURE__ */ jsxRuntime.jsx(
2467
+ /* @__PURE__ */ jsxRuntime.jsxs(TabsContent, { value: "wallet", className: "space-y-4", children: [
2468
+ activeTab === "wallet" && /* @__PURE__ */ jsxRuntime.jsx(
2469
+ DirectPayment,
2470
+ {
2471
+ priceId,
2472
+ tokenAmount,
2473
+ selectedToken,
2474
+ supportedTokens: tokens,
2475
+ onPaymentStart: handlePaymentStart,
2476
+ onPaymentConfirming: handlePaymentConfirming,
2477
+ onPaymentSuccess: handlePaymentSuccess,
2478
+ onPaymentError: handlePaymentError
2479
+ }
2480
+ ),
2481
+ !connected && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-amber-100", children: "Connect your Solana wallet to continue or switch to QR mode." })
2482
+ ] }),
2483
+ /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "qr", children: activeTab === "qr" && /* @__PURE__ */ jsxRuntime.jsx(
2605
2484
  QRCodePayment,
2606
2485
  {
2607
2486
  priceId,
@@ -2612,17 +2491,34 @@ var SolanaPaymentSelector = ({
2612
2491
  ) })
2613
2492
  ]
2614
2493
  }
2615
- ),
2616
- !connected && activeTab === "wallet" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-amber-500/40 bg-amber-500/10 p-4 text-sm text-amber-100", children: "Please connect your Solana wallet to complete this payment, or switch to QR mode." })
2617
- ] }) });
2494
+ ) })
2495
+ ] });
2618
2496
  };
2619
- return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-lg", children: [
2620
- /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "space-y-1", children: [
2621
- /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Complete your payment" }),
2622
- /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "Select a token and preferred method. We\u2019ll guide you through the rest." })
2497
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
2498
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4", children: [
2499
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
2500
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs uppercase tracking-wide text-muted-foreground", children: "Solana Pay checkout" }),
2501
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-semibold text-foreground", children: "Pay with Solana" }),
2502
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Choose a supported token and send the payment with your wallet or a QR code." })
2503
+ ] }),
2504
+ onClose && /* @__PURE__ */ jsxRuntime.jsxs(
2505
+ Button,
2506
+ {
2507
+ type: "button",
2508
+ size: "sm",
2509
+ variant: "ghost",
2510
+ onClick: handleClose,
2511
+ disabled: paymentState === "processing" || paymentState === "confirming",
2512
+ className: "h-8 px-2 text-sm",
2513
+ children: [
2514
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "mr-2 h-4 w-4" }),
2515
+ " Back"
2516
+ ]
2517
+ }
2518
+ )
2623
2519
  ] }),
2624
2520
  renderBody()
2625
- ] }) });
2521
+ ] });
2626
2522
  };
2627
2523
  var PaymentExperience = ({
2628
2524
  priceId,
@@ -2632,142 +2528,608 @@ var PaymentExperience = ({
2632
2528
  enableNewCard = true,
2633
2529
  enableStoredMethods = true,
2634
2530
  enableSolanaPay = true,
2635
- checkoutSummary,
2636
2531
  onSolanaSuccess,
2637
- onSolanaError
2532
+ onSolanaError,
2533
+ initialMode = "cards"
2638
2534
  }) => {
2639
2535
  const showNewCard = enableNewCard && Boolean(onNewCardPayment);
2640
- const showStored = enableStoredMethods;
2641
- const {
2642
- selectedMethodId,
2643
- savedStatus,
2644
- savedError,
2645
- newCardStatus,
2646
- newCardError,
2647
- solanaModalOpen,
2648
- setSelectedMethod,
2649
- setSolanaModalOpen,
2650
- startSavedPayment,
2651
- completeSavedPayment,
2652
- failSavedPayment,
2653
- startNewCardPayment,
2654
- completeNewCardPayment,
2655
- failNewCardPayment,
2656
- resetSavedPayment
2657
- } = usePaymentStore(selectCheckoutFlow);
2658
- const handleMethodSelect = (method) => {
2659
- setSelectedMethod(method.id);
2660
- resetSavedPayment();
2661
- };
2662
- const handleNewCardTokenize = async (token, billing) => {
2663
- if (!onNewCardPayment) return;
2664
- try {
2665
- startNewCardPayment();
2666
- await onNewCardPayment({ token, billing });
2667
- completeNewCardPayment();
2668
- } catch (error) {
2669
- const message = error instanceof Error ? error.message : "Unable to complete payment";
2670
- failNewCardPayment(message);
2536
+ const showStored = enableStoredMethods && Boolean(onSavedMethodPayment);
2537
+ const defaultTab = showStored ? "saved" : "new";
2538
+ const [activeTab, setActiveTab] = React3.useState(defaultTab);
2539
+ const [mode, setMode] = React3.useState(
2540
+ () => initialMode === "solana" && enableSolanaPay ? "solana" : "cards"
2541
+ );
2542
+ const [selectedMethodId, setSelectedMethodId] = React3.useState(null);
2543
+ const [savedStatus, setSavedStatus] = React3.useState("idle");
2544
+ const [savedError, setSavedError] = React3.useState(null);
2545
+ const [newCardStatus, setNewCardStatus] = React3.useState("idle");
2546
+ const [newCardError, setNewCardError] = React3.useState(null);
2547
+ const { notifyStatus, notifySuccess, notifyError } = usePaymentNotifications();
2548
+ React3.useEffect(() => {
2549
+ setActiveTab(showStored ? "saved" : "new");
2550
+ }, [showStored]);
2551
+ React3.useEffect(() => {
2552
+ if (!enableSolanaPay) {
2553
+ setMode("cards");
2554
+ return;
2671
2555
  }
2672
- };
2673
- const handleSavedPayment = async () => {
2556
+ if (initialMode === "solana") {
2557
+ setMode("solana");
2558
+ } else {
2559
+ setMode("cards");
2560
+ }
2561
+ }, [enableSolanaPay, initialMode]);
2562
+ const handleMethodSelect = React3.useCallback((method) => {
2563
+ setSelectedMethodId(method.id);
2564
+ setSavedStatus("idle");
2565
+ setSavedError(null);
2566
+ }, []);
2567
+ const handleSavedPayment = React3.useCallback(async () => {
2674
2568
  if (!onSavedMethodPayment || !selectedMethodId) return;
2675
2569
  try {
2676
- startSavedPayment();
2570
+ setSavedStatus("processing");
2571
+ setSavedError(null);
2572
+ notifyStatus("processing", { source: "saved-payment" });
2677
2573
  await onSavedMethodPayment({
2678
2574
  paymentMethodId: selectedMethodId,
2679
2575
  amount: usdAmount
2680
2576
  });
2681
- completeSavedPayment();
2577
+ setSavedStatus("success");
2578
+ notifyStatus("success", { source: "saved-payment" });
2682
2579
  } catch (error) {
2683
2580
  const message = error instanceof Error ? error.message : "Unable to complete payment with saved card";
2684
- failSavedPayment(message);
2581
+ setSavedStatus("error");
2582
+ setSavedError(message);
2583
+ notifyStatus("error", { source: "saved-payment" });
2584
+ notifyError(message);
2585
+ }
2586
+ }, [notifyError, notifyStatus, onSavedMethodPayment, selectedMethodId, usdAmount]);
2587
+ const handleNewCardTokenize = React3.useCallback(
2588
+ async (token, billing) => {
2589
+ if (!onNewCardPayment) return;
2590
+ try {
2591
+ setNewCardStatus("processing");
2592
+ setNewCardError(null);
2593
+ notifyStatus("processing", { source: "new-card" });
2594
+ await onNewCardPayment({ token, billing });
2595
+ setNewCardStatus("success");
2596
+ notifyStatus("success", { source: "new-card" });
2597
+ } catch (error) {
2598
+ const message = error instanceof Error ? error.message : "Unable to complete payment";
2599
+ setNewCardStatus("error");
2600
+ setNewCardError(message);
2601
+ notifyStatus("error", { source: "new-card" });
2602
+ notifyError(message);
2603
+ }
2604
+ },
2605
+ [notifyError, notifyStatus, onNewCardPayment]
2606
+ );
2607
+ const showSolanaView = React3.useCallback(() => {
2608
+ if (!enableSolanaPay) return;
2609
+ setMode("solana");
2610
+ }, [enableSolanaPay]);
2611
+ const exitSolanaView = React3.useCallback(() => {
2612
+ setMode("cards");
2613
+ }, []);
2614
+ const handleSolanaSuccess = React3.useCallback(
2615
+ (result) => {
2616
+ onSolanaSuccess?.(result);
2617
+ exitSolanaView();
2618
+ },
2619
+ [exitSolanaView, onSolanaSuccess]
2620
+ );
2621
+ const handleSolanaError = React3.useCallback(
2622
+ (error) => {
2623
+ onSolanaError?.(error);
2624
+ },
2625
+ [onSolanaError]
2626
+ );
2627
+ const renderSavedTab = () => {
2628
+ if (!showStored) {
2629
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Saved payment methods are unavailable right now. Add a new card to get started." });
2685
2630
  }
2631
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
2632
+ /* @__PURE__ */ jsxRuntime.jsx(
2633
+ StoredPaymentMethods,
2634
+ {
2635
+ heading: "Saved cards",
2636
+ selectedMethodId,
2637
+ onMethodSelect: handleMethodSelect,
2638
+ description: "Select one of your stored payment methods.",
2639
+ showAddButton: false
2640
+ }
2641
+ ),
2642
+ /* @__PURE__ */ jsxRuntime.jsx(
2643
+ Button,
2644
+ {
2645
+ className: "w-full",
2646
+ disabled: !selectedMethodId || savedStatus === "processing",
2647
+ onClick: handleSavedPayment,
2648
+ children: savedStatus === "processing" ? "Processing\u2026" : "Pay with selected card"
2649
+ }
2650
+ ),
2651
+ savedError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: savedError })
2652
+ ] });
2686
2653
  };
2687
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-8", children: [
2688
- /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-border/60 bg-card/95", children: [
2689
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
2690
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2691
- /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2 text-lg text-foreground", children: [
2692
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-5 w-5 text-primary" }),
2693
- " Secure checkout"
2694
- ] }),
2695
- /* @__PURE__ */ jsxRuntime.jsxs(CardDescription, { children: [
2696
- "Amount due: $",
2697
- usdAmount.toFixed(2)
2698
- ] })
2699
- ] }),
2700
- checkoutSummary && /* @__PURE__ */ jsxRuntime.jsx("div", { children: checkoutSummary })
2701
- ] }),
2702
- /* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 lg:grid-cols-2", children: [
2703
- showStored && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
2704
- /* @__PURE__ */ jsxRuntime.jsx(
2705
- StoredPaymentMethods,
2706
- {
2707
- selectedMethodId,
2708
- onMethodSelect: handleMethodSelect,
2709
- heading: "Saved cards",
2710
- description: "Use or manage your saved payment methods."
2711
- }
2712
- ),
2713
- onSavedMethodPayment && /* @__PURE__ */ jsxRuntime.jsx(
2714
- Button,
2715
- {
2716
- className: "w-full",
2717
- disabled: !selectedMethodId || savedStatus === "processing",
2718
- onClick: handleSavedPayment,
2719
- children: savedStatus === "processing" ? "Processing\u2026" : "Pay with selected card"
2720
- }
2721
- ),
2722
- savedError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: savedError })
2723
- ] }),
2724
- showNewCard && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-border/60 bg-background/80 p-6", children: [
2725
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 space-y-1", children: [
2726
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [
2727
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }),
2728
- " Pay with a new card"
2729
- ] }),
2730
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Card details are tokenized via Collect.js and never hit your server." })
2731
- ] }),
2732
- /* @__PURE__ */ jsxRuntime.jsx(
2733
- CardDetailsForm,
2734
- {
2735
- visible: true,
2736
- submitLabel: "Pay now",
2737
- submitting: newCardStatus === "processing",
2738
- externalError: newCardError,
2739
- onTokenize: handleNewCardTokenize
2740
- }
2741
- )
2742
- ] }) })
2743
- ] }) })
2744
- ] }),
2745
- enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border border-primary/40 bg-primary/5", children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "flex flex-col gap-4 text-sm text-primary md:flex-row md:items-center md:justify-between", children: [
2746
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2747
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-base font-semibold text-primary", children: [
2748
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "h-4 w-4" }),
2749
- " Prefer Solana Pay?"
2750
- ] }),
2751
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-primary/80", children: "Use a Solana wallet or QR code for instant settlement." })
2752
- ] }),
2753
- /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => setSolanaModalOpen(true), children: "Open Solana Pay" })
2754
- ] }) }),
2755
- enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsx(
2756
- SolanaPaymentSelector,
2654
+ const renderNewTab = () => {
2655
+ if (!showNewCard) {
2656
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Select a subscription plan to add a new card." });
2657
+ }
2658
+ return /* @__PURE__ */ jsxRuntime.jsx(
2659
+ CardDetailsForm,
2757
2660
  {
2758
- isOpen: solanaModalOpen,
2759
- onClose: () => setSolanaModalOpen(false),
2760
- priceId,
2761
- usdAmount,
2762
- onSuccess: (result) => {
2763
- setSolanaModalOpen(false);
2764
- onSolanaSuccess?.(result);
2765
- },
2766
- onError: onSolanaError
2661
+ visible: true,
2662
+ submitLabel: "Pay now",
2663
+ externalError: newCardError,
2664
+ onTokenize: handleNewCardTokenize,
2665
+ submitting: newCardStatus === "processing"
2666
+ }
2667
+ );
2668
+ };
2669
+ const renderCardExperience = () => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2670
+ /* @__PURE__ */ jsxRuntime.jsxs(
2671
+ Tabs,
2672
+ {
2673
+ value: activeTab,
2674
+ onValueChange: (value) => setActiveTab(value),
2675
+ className: "space-y-3",
2676
+ children: [
2677
+ /* @__PURE__ */ jsxRuntime.jsxs(TabsList, { className: "grid w-full grid-cols-2 border border-border/60", children: [
2678
+ /* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { value: "saved", disabled: !showStored, children: "Use saved card" }),
2679
+ /* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { value: "new", disabled: !showNewCard, children: "Add new card" })
2680
+ ] }),
2681
+ /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "saved", className: "space-y-4", children: renderSavedTab() }),
2682
+ /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "new", className: "space-y-4", children: renderNewTab() })
2683
+ ]
2684
+ }
2685
+ ),
2686
+ enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsxs(Button, { className: "w-full", variant: "secondary", onClick: showSolanaView, children: [
2687
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "mr-2 h-4 w-4" }),
2688
+ " Pay with Solana"
2689
+ ] })
2690
+ ] });
2691
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6 pt-4", children: [
2692
+ mode === "cards" && renderCardExperience(),
2693
+ mode === "solana" && enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsx(
2694
+ SolanaPaymentView,
2695
+ {
2696
+ priceId,
2697
+ usdAmount,
2698
+ onSuccess: handleSolanaSuccess,
2699
+ onError: handleSolanaError,
2700
+ onClose: exitSolanaView
2767
2701
  }
2768
2702
  )
2769
2703
  ] });
2770
2704
  };
2705
+ var SubscriptionSuccessDialog = ({
2706
+ open,
2707
+ planName = "Premium Plan",
2708
+ amountLabel = "$0.00",
2709
+ billingPeriodLabel = "billing period",
2710
+ onClose
2711
+ }) => {
2712
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: (value) => {
2713
+ if (!value) onClose();
2714
+ }, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "w-full max-w-md overflow-hidden border border-border/70 bg-background/95 p-0 shadow-2xl", children: [
2715
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-gradient-to-b from-primary/25 via-primary/10 to-background px-6 py-8 text-center", children: [
2716
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-background/60", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-10 w-10 text-primary" }) }),
2717
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
2718
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-2xl font-semibold text-foreground", children: "Subscription activated" }),
2719
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogDescription, { className: "text-base text-muted-foreground", children: [
2720
+ "You now have access to ",
2721
+ planName,
2722
+ ". Billing: ",
2723
+ amountLabel,
2724
+ " / ",
2725
+ billingPeriodLabel,
2726
+ "."
2727
+ ] })
2728
+ ] })
2729
+ ] }),
2730
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-6", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { className: "w-full", onClick: onClose, children: "Continue exploring" }) })
2731
+ ] }) });
2732
+ };
2733
+ var useSubscriptionActions = () => {
2734
+ const { services } = usePaymentContext();
2735
+ const ensurePrice = (priceId) => {
2736
+ if (!priceId) {
2737
+ throw new Error("payments-ui: priceId is required for subscription actions");
2738
+ }
2739
+ return priceId;
2740
+ };
2741
+ const subscribeWithCard = React3.useCallback(
2742
+ async ({
2743
+ priceId,
2744
+ processor = "nmi",
2745
+ provider,
2746
+ paymentToken,
2747
+ billing
2748
+ }) => {
2749
+ const payload = {
2750
+ priceId: ensurePrice(priceId),
2751
+ paymentToken,
2752
+ processor,
2753
+ provider,
2754
+ email: billing.email,
2755
+ firstName: billing.firstName,
2756
+ lastName: billing.lastName,
2757
+ address1: billing.address1,
2758
+ city: billing.city,
2759
+ state: billing.stateRegion,
2760
+ zipCode: billing.postalCode,
2761
+ country: billing.country
2762
+ };
2763
+ return services.subscriptions.subscribe("nmi", payload);
2764
+ },
2765
+ [services]
2766
+ );
2767
+ const subscribeWithSavedMethod = React3.useCallback(
2768
+ async ({
2769
+ priceId,
2770
+ processor = "nmi",
2771
+ provider,
2772
+ paymentMethodId,
2773
+ email
2774
+ }) => {
2775
+ const payload = {
2776
+ priceId: ensurePrice(priceId),
2777
+ paymentMethodId,
2778
+ processor,
2779
+ provider,
2780
+ email
2781
+ };
2782
+ return services.subscriptions.subscribe("nmi", payload);
2783
+ },
2784
+ [services]
2785
+ );
2786
+ const subscribeWithCCBill = React3.useCallback(
2787
+ async ({
2788
+ priceId,
2789
+ email,
2790
+ firstName,
2791
+ lastName,
2792
+ zipCode,
2793
+ country,
2794
+ processor = "ccbill"
2795
+ }) => {
2796
+ const payload = {
2797
+ priceId: ensurePrice(priceId),
2798
+ email,
2799
+ firstName,
2800
+ lastName,
2801
+ zipCode,
2802
+ country,
2803
+ processor
2804
+ };
2805
+ return services.subscriptions.subscribe("ccbill", payload);
2806
+ },
2807
+ [services]
2808
+ );
2809
+ const generateFlexFormUrl = React3.useCallback(
2810
+ async ({
2811
+ priceId,
2812
+ firstName,
2813
+ lastName,
2814
+ address1,
2815
+ city,
2816
+ state,
2817
+ zipCode,
2818
+ country
2819
+ }) => {
2820
+ const payload = {
2821
+ price_id: ensurePrice(priceId),
2822
+ first_name: firstName,
2823
+ last_name: lastName,
2824
+ address1,
2825
+ city,
2826
+ state,
2827
+ zip_code: zipCode,
2828
+ country
2829
+ };
2830
+ return services.subscriptions.generateFlexFormUrl(payload);
2831
+ },
2832
+ [services]
2833
+ );
2834
+ return {
2835
+ subscribeWithCard,
2836
+ subscribeWithSavedMethod,
2837
+ subscribeWithCCBill,
2838
+ generateFlexFormUrl
2839
+ };
2840
+ };
2841
+ var SubscriptionCheckoutModal = ({
2842
+ open,
2843
+ onOpenChange,
2844
+ priceId,
2845
+ usdAmount = 0,
2846
+ planName,
2847
+ amountLabel,
2848
+ billingPeriodLabel,
2849
+ userEmail,
2850
+ provider = "mobius",
2851
+ onSuccess,
2852
+ enableSolanaPay = true,
2853
+ onSolanaSuccess,
2854
+ onSolanaError,
2855
+ initialMode = "cards"
2856
+ }) => {
2857
+ const [showSuccess, setShowSuccess] = React3.useState(false);
2858
+ const { subscribeWithCard, subscribeWithSavedMethod } = useSubscriptionActions();
2859
+ const handleClose = React3.useCallback(
2860
+ (nextOpen) => {
2861
+ onOpenChange(nextOpen);
2862
+ if (!nextOpen) setShowSuccess(false);
2863
+ },
2864
+ [onOpenChange]
2865
+ );
2866
+ const ensurePrice = () => {
2867
+ if (!priceId) throw new Error("Select a plan before subscribing.");
2868
+ return priceId;
2869
+ };
2870
+ const notifySuccess = (result) => {
2871
+ setShowSuccess(true);
2872
+ onSuccess?.();
2873
+ if (result && typeof window !== "undefined") {
2874
+ console.debug("[payments-ui] subscription success", result);
2875
+ }
2876
+ };
2877
+ const handleNewCardPayment = async ({ token, billing }) => {
2878
+ await subscribeWithCard({
2879
+ priceId: ensurePrice(),
2880
+ provider,
2881
+ paymentToken: token,
2882
+ billing
2883
+ });
2884
+ notifySuccess();
2885
+ };
2886
+ const handleSavedMethodPayment = async ({ paymentMethodId }) => {
2887
+ await subscribeWithSavedMethod({
2888
+ priceId: ensurePrice(),
2889
+ provider,
2890
+ paymentMethodId,
2891
+ email: userEmail ?? ""
2892
+ });
2893
+ notifySuccess();
2894
+ };
2895
+ const solanaSuccess = (result) => {
2896
+ notifySuccess(result);
2897
+ onSolanaSuccess?.(result);
2898
+ onOpenChange(false);
2899
+ };
2900
+ const solanaError = (error) => {
2901
+ onSolanaError?.(error);
2902
+ };
2903
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2904
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsx(DialogContent, { className: "w-full max-w-3xl max-h-[90vh] overflow-y-auto rounded-md border border-border/60 bg-background p-0 [&::-webkit-scrollbar]:hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-6", children: [
2905
+ !priceId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
2906
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
2907
+ " Select a subscription plan to continue."
2908
+ ] }),
2909
+ /* @__PURE__ */ jsxRuntime.jsx(
2910
+ PaymentExperience,
2911
+ {
2912
+ usdAmount,
2913
+ priceId: priceId ?? "",
2914
+ onSolanaSuccess: solanaSuccess,
2915
+ onSolanaError: solanaError,
2916
+ enableNewCard: Boolean(priceId),
2917
+ enableStoredMethods: Boolean(priceId),
2918
+ enableSolanaPay: enableSolanaPay && Boolean(priceId),
2919
+ onNewCardPayment: priceId ? handleNewCardPayment : void 0,
2920
+ onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
2921
+ initialMode
2922
+ }
2923
+ )
2924
+ ] }) }) }),
2925
+ /* @__PURE__ */ jsxRuntime.jsx(
2926
+ SubscriptionSuccessDialog,
2927
+ {
2928
+ open: showSuccess,
2929
+ onClose: () => setShowSuccess(false),
2930
+ planName,
2931
+ amountLabel: amountLabel ?? `$${usdAmount.toFixed(2)}`,
2932
+ billingPeriodLabel
2933
+ }
2934
+ )
2935
+ ] });
2936
+ };
2937
+ var wallets = [
2938
+ {
2939
+ id: "phantom",
2940
+ name: "Phantom",
2941
+ icon: "https://phantom.app/img/logo.png"
2942
+ },
2943
+ {
2944
+ id: "solflare",
2945
+ name: "Solflare",
2946
+ icon: "https://solflare.com/favicon.ico"
2947
+ }
2948
+ ];
2949
+ var WalletModal = ({ open, onOpenChange }) => {
2950
+ const [expandedWallet, setExpandedWallet] = React3.useState(null);
2951
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "w-full max-w-lg max-h-[90vh] overflow-y-auto rounded-md border border-border/70 bg-background/95 p-0 shadow-2xl [&::-webkit-scrollbar]:hidden", children: [
2952
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "border-b border-border/40 bg-gradient-to-r from-primary/10 via-background to-background px-6 py-5 text-left", children: [
2953
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex items-center gap-2 text-foreground", children: [
2954
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-5 w-5 text-primary" }),
2955
+ " Connect a Solana wallet"
2956
+ ] }),
2957
+ /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "text-sm text-muted-foreground", children: "Pick a supported wallet to link with Doujins. Verified wallets unlock Solana payments and withdrawals." })
2958
+ ] }),
2959
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-4", children: [
2960
+ wallets.map((wallet) => /* @__PURE__ */ jsxRuntime.jsxs(
2961
+ "div",
2962
+ {
2963
+ className: "rounded-2xl border border-border/60 bg-background/80 p-4 shadow-sm",
2964
+ children: [
2965
+ /* @__PURE__ */ jsxRuntime.jsxs(
2966
+ "button",
2967
+ {
2968
+ className: "flex w-full items-center justify-between",
2969
+ onClick: () => setExpandedWallet((prev) => prev === wallet.id ? null : wallet.id),
2970
+ children: [
2971
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-left", children: [
2972
+ /* @__PURE__ */ jsxRuntime.jsx("img", { src: wallet.icon, alt: wallet.name, className: "h-10 w-10 rounded-full" }),
2973
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2974
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-semibold text-foreground", children: wallet.name }),
2975
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Browser extension or mobile app" })
2976
+ ] })
2977
+ ] }),
2978
+ expandedWallet === wallet.id ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 text-muted-foreground" })
2979
+ ]
2980
+ }
2981
+ ),
2982
+ expandedWallet === wallet.id && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-3 text-sm text-muted-foreground", children: [
2983
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
2984
+ "Open the ",
2985
+ wallet.name,
2986
+ " wallet, approve the connection request, and confirm the signature prompt to finish linking."
2987
+ ] }),
2988
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { className: "w-full", variant: "outline", disabled: true, children: [
2989
+ "Connect with ",
2990
+ wallet.name,
2991
+ " (coming soon)"
2992
+ ] })
2993
+ ] })
2994
+ ]
2995
+ },
2996
+ wallet.id
2997
+ )),
2998
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-2xl border border-border/60 bg-muted/10 p-4 text-xs text-muted-foreground", children: "Don\u2019t see your wallet? Additional providers will be added soon. Contact support if you need manual verification." })
2999
+ ] })
3000
+ ] }) });
3001
+ };
3002
+ var createDialogState = () => ({
3003
+ isOpen: false,
3004
+ props: null
3005
+ });
3006
+ var PaymentsDialogContext = React3.createContext(void 0);
3007
+ var PaymentsDialogProvider = ({
3008
+ children
3009
+ }) => {
3010
+ const [checkoutState, setCheckoutState] = React3.useState(
3011
+ () => createDialogState()
3012
+ );
3013
+ const [walletState, setWalletState] = React3.useState(
3014
+ () => createDialogState()
3015
+ );
3016
+ const contextValue = React3.useMemo(() => {
3017
+ const openCheckout = (options) => setCheckoutState({
3018
+ isOpen: true,
3019
+ props: options
3020
+ });
3021
+ return {
3022
+ checkout: {
3023
+ isOpen: checkoutState.isOpen,
3024
+ open: openCheckout,
3025
+ close: () => setCheckoutState(createDialogState())
3026
+ },
3027
+ solana: {
3028
+ isOpen: checkoutState.isOpen && checkoutState.props?.initialMode === "solana",
3029
+ open: (options) => openCheckout({
3030
+ priceId: options.priceId,
3031
+ usdAmount: options.usdAmount,
3032
+ enableSolanaPay: true,
3033
+ initialMode: "solana",
3034
+ onSolanaSuccess: options.onSuccess,
3035
+ onSolanaError: options.onError
3036
+ }),
3037
+ close: () => setCheckoutState(createDialogState())
3038
+ },
3039
+ wallet: {
3040
+ isOpen: walletState.isOpen,
3041
+ open: (options) => setWalletState({
3042
+ isOpen: true,
3043
+ props: options ?? null
3044
+ }),
3045
+ close: () => setWalletState(createDialogState())
3046
+ }
3047
+ };
3048
+ }, [checkoutState, walletState.isOpen]);
3049
+ return /* @__PURE__ */ jsxRuntime.jsxs(PaymentsDialogContext.Provider, { value: contextValue, children: [
3050
+ children,
3051
+ checkoutState.props && /* @__PURE__ */ jsxRuntime.jsx(
3052
+ SubscriptionCheckoutModal,
3053
+ {
3054
+ open: checkoutState.isOpen,
3055
+ onOpenChange: (open) => open ? setCheckoutState((prev) => ({ ...prev, isOpen: true })) : setCheckoutState(createDialogState()),
3056
+ ...checkoutState.props
3057
+ }
3058
+ ),
3059
+ /* @__PURE__ */ jsxRuntime.jsx(
3060
+ WalletModal,
3061
+ {
3062
+ open: walletState.isOpen,
3063
+ onOpenChange: (open) => open ? setWalletState((prev) => ({ ...prev, isOpen: true })) : setWalletState(createDialogState()),
3064
+ ...walletState.props ?? {}
3065
+ }
3066
+ )
3067
+ ] });
3068
+ };
3069
+ var usePaymentDialogs = () => {
3070
+ const context = React3.useContext(PaymentsDialogContext);
3071
+ if (!context) {
3072
+ throw new Error("usePaymentDialogs must be used within PaymentProvider");
3073
+ }
3074
+ return context;
3075
+ };
3076
+ var PaymentContext = React3.createContext(void 0);
3077
+ var PaymentProvider = ({
3078
+ config,
3079
+ runtime: runtimeProp,
3080
+ children
3081
+ }) => {
3082
+ const runtime = React3.useMemo(
3083
+ () => runtimeProp ?? createPaymentsRuntime(config),
3084
+ [runtimeProp, config]
3085
+ );
3086
+ const solanaEndpoint = React3.useMemo(() => {
3087
+ if (config.solana?.endpoint) return config.solana.endpoint;
3088
+ const network = config.solana?.network ?? WalletAdapterNetwork.Mainnet;
3089
+ return web3_js.clusterApiUrl(network);
3090
+ }, [config.solana?.endpoint, config.solana?.network]);
3091
+ const walletAdapters = React3.useMemo(() => {
3092
+ if (config.solana?.wallets?.length) {
3093
+ return config.solana.wallets;
3094
+ }
3095
+ return [
3096
+ new walletAdapterPhantom.PhantomWalletAdapter(),
3097
+ new walletAdapterSolflare.SolflareWalletAdapter(),
3098
+ new walletAdapterTrust.TrustWalletAdapter(),
3099
+ new walletAdapterCoinbase.CoinbaseWalletAdapter()
3100
+ ];
3101
+ }, [config.solana?.wallets]);
3102
+ const autoConnect = config.solana?.autoConnect ?? true;
3103
+ const value = React3.useMemo(() => {
3104
+ return {
3105
+ config: runtime.config,
3106
+ fetcher: runtime.app.getFetcher(),
3107
+ resolveAuthToken: runtime.app.resolveAuthToken,
3108
+ app: runtime.app,
3109
+ services: runtime.services,
3110
+ queryClient: runtime.queryClient
3111
+ };
3112
+ }, [runtime]);
3113
+ React3.useEffect(() => {
3114
+ if (!config.collectJsKey) return;
3115
+ loadCollectJs(config.collectJsKey);
3116
+ }, [config.collectJsKey]);
3117
+ return /* @__PURE__ */ jsxRuntime.jsx(PaymentContext.Provider, { value, children: /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: runtime.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 }) }) }) }) }) });
3118
+ };
3119
+ var usePaymentContext = () => {
3120
+ const context = React3.useContext(PaymentContext);
3121
+ if (!context) {
3122
+ throw new Error("usePaymentContext must be used within a PaymentProvider");
3123
+ }
3124
+ return context;
3125
+ };
3126
+ var SolanaPaymentSelector = ({
3127
+ isOpen,
3128
+ onClose,
3129
+ ...props
3130
+ }) => {
3131
+ 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 border-border/70 bg-background/95 p-0 shadow-2xl [&::-webkit-scrollbar]:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(SolanaPaymentView, { ...props, onClose }) }) });
3132
+ };
2771
3133
  var Table = React3__namespace.forwardRef(
2772
3134
  ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2773
3135
  "table",
@@ -2952,7 +3314,7 @@ var CancelMembershipDialog = ({
2952
3314
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "mr-2 h-4 w-4" }),
2953
3315
  " Cancel Membership"
2954
3316
  ] }) }),
2955
- /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { className: "max-h-[90vh] overflow-y-auto rounded-xl border border-border bg-background", children: [
3317
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { className: "max-h-[90vh] overflow-y-auto rounded-md border border-border bg-background", children: [
2956
3318
  /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { children: [
2957
3319
  /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogTitle, { className: "flex items-center gap-2 text-lg font-semibold", children: [
2958
3320
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "h-5 w-5 text-destructive" }),
@@ -3913,45 +4275,6 @@ var SolanaWalletSection = ({
3913
4275
  ] });
3914
4276
  };
3915
4277
  var WalletManagement = (props) => /* @__PURE__ */ jsxRuntime.jsx(SolanaWalletSection, { ...props });
3916
- var wallets = [
3917
- {
3918
- id: "phantom",
3919
- name: "Phantom",
3920
- icon: "https://phantom.app/img/logo.png"
3921
- },
3922
- {
3923
- id: "solflare",
3924
- name: "Solflare",
3925
- icon: "https://solflare.com/favicon.ico"
3926
- }
3927
- ];
3928
- var WalletModal = ({ open, onOpenChange }) => {
3929
- const [expandedWallet, setExpandedWallet] = React3.useState(null);
3930
- return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsx(DialogContent, { className: "max-w-md border border-border bg-background", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: wallets.map((wallet) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-border/80", children: [
3931
- /* @__PURE__ */ jsxRuntime.jsxs(
3932
- "button",
3933
- {
3934
- className: "flex w-full items-center justify-between px-4 py-3",
3935
- onClick: () => setExpandedWallet((prev) => prev === wallet.id ? null : wallet.id),
3936
- children: [
3937
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-left", children: [
3938
- /* @__PURE__ */ jsxRuntime.jsx("img", { src: wallet.icon, alt: wallet.name, className: "h-8 w-8 rounded-full" }),
3939
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3940
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold", children: wallet.name }),
3941
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Connect via browser extension" })
3942
- ] })
3943
- ] }),
3944
- expandedWallet === wallet.id ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "h-4 w-4 text-muted-foreground" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4 text-muted-foreground" })
3945
- ]
3946
- }
3947
- ),
3948
- expandedWallet === wallet.id && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border/60 px-4 py-3 text-sm text-muted-foreground", children: [
3949
- "Follow the prompts in your ",
3950
- wallet.name,
3951
- " wallet to approve access."
3952
- ] })
3953
- ] }, wallet.id)) }) }) });
3954
- };
3955
4278
  var Checkbox = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3956
4279
  CheckboxPrimitive__namespace.Root,
3957
4280
  {
@@ -3971,7 +4294,7 @@ var Checkbox = React3__namespace.forwardRef(({ className, ...props }, ref) => /*
3971
4294
  }
3972
4295
  ));
3973
4296
  Checkbox.displayName = CheckboxPrimitive__namespace.Root.displayName;
3974
- var initialState2 = {
4297
+ var initialState = {
3975
4298
  nameOnCard: "",
3976
4299
  cardNumber: "",
3977
4300
  expiration: "",
@@ -3979,7 +4302,7 @@ var initialState2 = {
3979
4302
  termsAccepted: false
3980
4303
  };
3981
4304
  var WalletDialog = ({ open, onOpenChange }) => {
3982
- const [form, setForm] = React3.useState(initialState2);
4305
+ const [form, setForm] = React3.useState(initialState);
3983
4306
  const [errors, setErrors] = React3.useState({});
3984
4307
  const validators = React3.useMemo(
3985
4308
  () => ({
@@ -4012,7 +4335,7 @@ var WalletDialog = ({ open, onOpenChange }) => {
4012
4335
  if (!validate()) return;
4013
4336
  console.log("[payments-ui] wallet dialog submit", form);
4014
4337
  onOpenChange(false);
4015
- setForm(initialState2);
4338
+ setForm(initialState);
4016
4339
  };
4017
4340
  return /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { className: "max-h-[95vh] max-w-lg overflow-y-auto rounded-2xl border border-border bg-background", children: [
4018
4341
  /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { className: "border-b border-border/60 pb-4", children: [
@@ -4059,7 +4382,7 @@ var WalletDialog = ({ open, onOpenChange }) => {
4059
4382
  ] })
4060
4383
  ] })
4061
4384
  ] }),
4062
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-border/70 bg-muted/10 p-4", children: [
4385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 rounded-md border border-border/70 bg-muted/10 p-4", children: [
4063
4386
  /* @__PURE__ */ jsxRuntime.jsx(Checkbox, { id: "terms-agree", checked: form.termsAccepted, onCheckedChange: (checked) => updateField("termsAccepted", Boolean(checked)) }),
4064
4387
  /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "terms-agree", className: "text-sm text-muted-foreground", children: "By completing this order, I confirm that I am 18 years or older and agree to your privacy policy and terms." })
4065
4388
  ] }),
@@ -4071,245 +4394,6 @@ var WalletDialog = ({ open, onOpenChange }) => {
4071
4394
  ] })
4072
4395
  ] }) });
4073
4396
  };
4074
- var SubscriptionSuccessDialog = ({
4075
- open,
4076
- planName = "Premium Plan",
4077
- amountLabel = "$0.00",
4078
- billingPeriodLabel = "billing period",
4079
- onClose
4080
- }) => {
4081
- return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: (value) => {
4082
- if (!value) onClose();
4083
- }, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-w-sm text-center", children: [
4084
- /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
4085
- /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex flex-col items-center gap-3 text-foreground", children: [
4086
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-10 w-10 text-primary" }),
4087
- "Subscription activated"
4088
- ] }),
4089
- /* @__PURE__ */ jsxRuntime.jsxs(DialogDescription, { className: "text-base text-muted-foreground", children: [
4090
- "You now have access to ",
4091
- planName,
4092
- ". Billing: ",
4093
- amountLabel,
4094
- " / ",
4095
- billingPeriodLabel,
4096
- "."
4097
- ] })
4098
- ] }),
4099
- /* @__PURE__ */ jsxRuntime.jsx(Button, { className: "mt-6 w-full", onClick: onClose, children: "Continue" })
4100
- ] }) });
4101
- };
4102
- var useSubscriptionActions = () => {
4103
- const { services } = usePaymentContext();
4104
- const ensurePrice = (priceId) => {
4105
- if (!priceId) {
4106
- throw new Error("payments-ui: priceId is required for subscription actions");
4107
- }
4108
- return priceId;
4109
- };
4110
- const subscribeWithCard = React3.useCallback(
4111
- async ({
4112
- priceId,
4113
- processor = "nmi",
4114
- provider,
4115
- paymentToken,
4116
- billing
4117
- }) => {
4118
- const payload = {
4119
- priceId: ensurePrice(priceId),
4120
- paymentToken,
4121
- processor,
4122
- provider,
4123
- email: billing.email,
4124
- firstName: billing.firstName,
4125
- lastName: billing.lastName,
4126
- address1: billing.address1,
4127
- city: billing.city,
4128
- state: billing.stateRegion,
4129
- zipCode: billing.postalCode,
4130
- country: billing.country
4131
- };
4132
- return services.subscriptions.subscribe("nmi", payload);
4133
- },
4134
- [services]
4135
- );
4136
- const subscribeWithSavedMethod = React3.useCallback(
4137
- async ({
4138
- priceId,
4139
- processor = "nmi",
4140
- provider,
4141
- paymentMethodId,
4142
- email
4143
- }) => {
4144
- const payload = {
4145
- priceId: ensurePrice(priceId),
4146
- paymentMethodId,
4147
- processor,
4148
- provider,
4149
- email
4150
- };
4151
- return services.subscriptions.subscribe("nmi", payload);
4152
- },
4153
- [services]
4154
- );
4155
- const subscribeWithCCBill = React3.useCallback(
4156
- async ({
4157
- priceId,
4158
- email,
4159
- firstName,
4160
- lastName,
4161
- zipCode,
4162
- country,
4163
- processor = "ccbill"
4164
- }) => {
4165
- const payload = {
4166
- priceId: ensurePrice(priceId),
4167
- email,
4168
- firstName,
4169
- lastName,
4170
- zipCode,
4171
- country,
4172
- processor
4173
- };
4174
- return services.subscriptions.subscribe("ccbill", payload);
4175
- },
4176
- [services]
4177
- );
4178
- const generateFlexFormUrl = React3.useCallback(
4179
- async ({
4180
- priceId,
4181
- firstName,
4182
- lastName,
4183
- address1,
4184
- city,
4185
- state,
4186
- zipCode,
4187
- country
4188
- }) => {
4189
- const payload = {
4190
- price_id: ensurePrice(priceId),
4191
- first_name: firstName,
4192
- last_name: lastName,
4193
- address1,
4194
- city,
4195
- state,
4196
- zip_code: zipCode,
4197
- country
4198
- };
4199
- return services.subscriptions.generateFlexFormUrl(payload);
4200
- },
4201
- [services]
4202
- );
4203
- return {
4204
- subscribeWithCard,
4205
- subscribeWithSavedMethod,
4206
- subscribeWithCCBill,
4207
- generateFlexFormUrl
4208
- };
4209
- };
4210
- var SubscriptionCheckoutModal = ({
4211
- open,
4212
- onOpenChange,
4213
- priceId,
4214
- usdAmount = 0,
4215
- planName,
4216
- amountLabel,
4217
- billingPeriodLabel,
4218
- userEmail,
4219
- provider = "mobius",
4220
- onSuccess,
4221
- enableSolanaPay = true
4222
- }) => {
4223
- const [showSuccess, setShowSuccess] = React3.useState(false);
4224
- const { subscribeWithCard, subscribeWithSavedMethod } = useSubscriptionActions();
4225
- const handleClose = React3.useCallback(
4226
- (nextOpen) => {
4227
- onOpenChange(nextOpen);
4228
- if (!nextOpen) {
4229
- setShowSuccess(false);
4230
- }
4231
- },
4232
- [onOpenChange]
4233
- );
4234
- const ensurePrice = () => {
4235
- if (!priceId) {
4236
- throw new Error("Select a plan before subscribing.");
4237
- }
4238
- return priceId;
4239
- };
4240
- const notifySuccess = (result) => {
4241
- setShowSuccess(true);
4242
- onSuccess?.();
4243
- if (result && typeof window !== "undefined") {
4244
- console.debug("[payments-ui] subscription success", result);
4245
- }
4246
- };
4247
- const handleNewCardPayment = async ({ token, billing }) => {
4248
- await subscribeWithCard({
4249
- priceId: ensurePrice(),
4250
- provider,
4251
- paymentToken: token,
4252
- billing
4253
- });
4254
- notifySuccess();
4255
- };
4256
- const handleSavedMethodPayment = async ({ paymentMethodId }) => {
4257
- await subscribeWithSavedMethod({
4258
- priceId: ensurePrice(),
4259
- provider,
4260
- paymentMethodId,
4261
- email: userEmail ?? ""
4262
- });
4263
- notifySuccess();
4264
- };
4265
- const solanaSuccess = (result) => {
4266
- notifySuccess(result);
4267
- onOpenChange(false);
4268
- };
4269
- const summary = React3.useMemo(() => {
4270
- if (!planName && !amountLabel) return null;
4271
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border/60 bg-muted/10 p-3 text-sm text-muted-foreground", children: [
4272
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-foreground", children: planName ?? "Selected plan" }),
4273
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
4274
- amountLabel ?? `$${usdAmount.toFixed(2)}`,
4275
- " ",
4276
- billingPeriodLabel ? `/ ${billingPeriodLabel}` : ""
4277
- ] })
4278
- ] });
4279
- }, [planName, amountLabel, billingPeriodLabel, usdAmount]);
4280
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4281
- /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-3xl", children: [
4282
- !priceId && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 flex items-center gap-2 rounded-lg border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive", children: [
4283
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
4284
- " Select a subscription plan to continue."
4285
- ] }),
4286
- /* @__PURE__ */ jsxRuntime.jsx(
4287
- PaymentExperience,
4288
- {
4289
- priceId: priceId ?? "",
4290
- usdAmount,
4291
- checkoutSummary: summary,
4292
- onNewCardPayment: priceId ? handleNewCardPayment : void 0,
4293
- onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
4294
- enableNewCard: Boolean(priceId),
4295
- enableStoredMethods: Boolean(priceId),
4296
- enableSolanaPay: enableSolanaPay && Boolean(priceId),
4297
- onSolanaSuccess: solanaSuccess
4298
- }
4299
- )
4300
- ] }) }),
4301
- /* @__PURE__ */ jsxRuntime.jsx(
4302
- SubscriptionSuccessDialog,
4303
- {
4304
- open: showSuccess,
4305
- onClose: () => setShowSuccess(false),
4306
- planName,
4307
- amountLabel: amountLabel ?? `$${usdAmount.toFixed(2)}`,
4308
- billingPeriodLabel
4309
- }
4310
- )
4311
- ] });
4312
- };
4313
4397
  var useTokenBalance = (tokens) => {
4314
4398
  const { publicKey } = walletAdapterReact.useWallet();
4315
4399
  const { connection } = walletAdapterReact.useConnection();
@@ -4839,8 +4923,11 @@ exports.PaymentExperience = PaymentExperience;
4839
4923
  exports.PaymentMethodService = PaymentMethodService;
4840
4924
  exports.PaymentMethodsSection = PaymentMethodsSection;
4841
4925
  exports.PaymentProvider = PaymentProvider;
4926
+ exports.PaymentsDialogProvider = PaymentsDialogProvider;
4927
+ exports.PaymentsRuntime = PaymentsRuntime;
4842
4928
  exports.SolanaPaymentSelector = SolanaPaymentSelector;
4843
4929
  exports.SolanaPaymentService = SolanaPaymentService;
4930
+ exports.SolanaPaymentView = SolanaPaymentView;
4844
4931
  exports.SolanaWalletSection = SolanaWalletSection;
4845
4932
  exports.SolanaWalletService = SolanaWalletService;
4846
4933
  exports.StoredPaymentMethods = StoredPaymentMethods;
@@ -4853,14 +4940,15 @@ exports.WalletDialog = WalletDialog;
4853
4940
  exports.WalletGateway = WalletGateway;
4854
4941
  exports.WalletManagement = WalletManagement;
4855
4942
  exports.WalletModal = WalletModal;
4856
- exports.createPaymentStore = createPaymentStore;
4943
+ exports.createPaymentsRuntime = createPaymentsRuntime;
4857
4944
  exports.useAlternativePaymentProvider = useAlternativePaymentProvider;
4858
4945
  exports.useDirectWalletPayment = useDirectWalletPayment;
4859
4946
  exports.usePaymentContext = usePaymentContext;
4947
+ exports.usePaymentDialogs = usePaymentDialogs;
4860
4948
  exports.usePaymentMethodService = usePaymentMethodService;
4861
4949
  exports.usePaymentMethods = usePaymentMethods;
4950
+ exports.usePaymentNotifications = usePaymentNotifications;
4862
4951
  exports.usePaymentStatus = usePaymentStatus;
4863
- exports.usePaymentStore = usePaymentStore;
4864
4952
  exports.useSolanaDirectPayment = useSolanaDirectPayment;
4865
4953
  exports.useSolanaQrPayment = useSolanaQrPayment;
4866
4954
  exports.useSolanaService = useSolanaService;