@doujins/payments-ui 0.0.11 → 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,25 +1,32 @@
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');
27
+ var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
28
+ var bs58 = require('bs58');
29
+ var CheckboxPrimitive = require('@radix-ui/react-checkbox');
23
30
 
24
31
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
25
32
 
@@ -42,13 +49,16 @@ function _interopNamespace(e) {
42
49
  }
43
50
 
44
51
  var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
52
+ var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
45
53
  var countryList__default = /*#__PURE__*/_interopDefault(countryList);
46
54
  var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
47
55
  var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
48
- var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
49
56
  var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPrimitive);
50
- var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
51
57
  var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
58
+ var QRCode__default = /*#__PURE__*/_interopDefault(QRCode);
59
+ var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
60
+ var bs58__default = /*#__PURE__*/_interopDefault(bs58);
61
+ var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
52
62
 
53
63
  // src/context/PaymentContext.tsx
54
64
 
@@ -331,6 +341,38 @@ var SubscriptionService = class {
331
341
  body: { ...payload }
332
342
  });
333
343
  }
344
+ async getPaymentHistory(params) {
345
+ const limit = params?.limit ?? 10;
346
+ const offset = params?.offset ?? 0;
347
+ const query = {
348
+ limit: String(limit),
349
+ offset: String(offset)
350
+ };
351
+ if (params?.type) {
352
+ query.type = params.type;
353
+ }
354
+ const response = await this.api.get("/subscriptions/purchases", {
355
+ query
356
+ });
357
+ const totalItems = response?.total_items ?? 0;
358
+ const pageSize = limit;
359
+ const pageNumber = response?.page ?? (pageSize > 0 ? Math.floor(offset / pageSize) + 1 : 1);
360
+ const totalPages = response?.total_pages ?? (pageSize > 0 ? Math.ceil(totalItems / pageSize) : void 0);
361
+ return {
362
+ data: response?.data ?? [],
363
+ total_items: totalItems,
364
+ limit,
365
+ offset,
366
+ page: pageNumber,
367
+ page_size: pageSize,
368
+ total_pages: totalPages
369
+ };
370
+ }
371
+ async cancelSubscription(feedback) {
372
+ return this.api.post("/subscriptions/cancel", {
373
+ body: feedback ? { feedback } : void 0
374
+ });
375
+ }
334
376
  serializePayload(platform, payload) {
335
377
  if (platform === "nmi") {
336
378
  const data2 = payload;
@@ -375,6 +417,48 @@ var SubscriptionService = class {
375
417
  }
376
418
  };
377
419
 
420
+ // src/services/SolanaWalletService.ts
421
+ var SolanaWalletService = class {
422
+ constructor(api) {
423
+ this.api = api;
424
+ }
425
+ async list() {
426
+ const response = await this.api.get(
427
+ "/wallet/solana"
428
+ );
429
+ if (Array.isArray(response)) {
430
+ return response;
431
+ }
432
+ if ("wallets" in response && Array.isArray(response.wallets)) {
433
+ return response.wallets;
434
+ }
435
+ if ("wallet" in response) {
436
+ return response.wallet ? [response.wallet] : [];
437
+ }
438
+ if ("address" in response) {
439
+ return [response];
440
+ }
441
+ return [];
442
+ }
443
+ async requestChallenge(wallet) {
444
+ return this.api.post("/wallet/solana/challenge", {
445
+ body: { wallet }
446
+ });
447
+ }
448
+ async verify(wallet, signature, nonce) {
449
+ const body = { wallet, signature };
450
+ if (nonce) {
451
+ body.nonce = nonce;
452
+ }
453
+ return this.api.post("/wallet/solana/verify", { body });
454
+ }
455
+ async remove(wallet) {
456
+ await this.api.delete("/wallet/solana", {
457
+ query: { wallet }
458
+ });
459
+ }
460
+ };
461
+
378
462
  // src/core/PaymentApp.ts
379
463
  var PaymentApp = class {
380
464
  constructor(options) {
@@ -424,6 +508,7 @@ var PaymentApp = class {
424
508
  this.resolveAuthToken
425
509
  );
426
510
  const solanaPayments = new SolanaPaymentService(billingApi);
511
+ const solanaWallets = new SolanaWalletService(billingApi);
427
512
  const paymentMethods = new PaymentMethodService(accountApi);
428
513
  const cardPayments = new CardPaymentService(this.config);
429
514
  const walletGateway = new WalletGateway();
@@ -433,6 +518,7 @@ var PaymentApp = class {
433
518
  cardPayments,
434
519
  paymentMethods,
435
520
  solanaPayments,
521
+ solanaWallets,
436
522
  tokenCatalog,
437
523
  walletGateway,
438
524
  subscriptions,
@@ -441,141 +527,98 @@ var PaymentApp = class {
441
527
  };
442
528
  }
443
529
  };
444
- var initialState = {
445
- selectedMethodId: null,
446
- solanaModalOpen: false,
447
- savedPaymentStatus: "idle",
448
- savedPaymentError: null,
449
- newCardStatus: "idle",
450
- newCardError: null,
451
- solanaTab: "wallet",
452
- solanaStatus: "selecting",
453
- solanaError: null,
454
- solanaTransactionId: null,
455
- solanaSelectedToken: null,
456
- solanaTokenAmount: 0
457
- };
458
- var createPaymentStore = (options) => vanilla.createStore((set, get) => {
459
- const notifyStatus = (status, context) => {
460
- options?.callbacks?.onStatusChange?.({ status, context });
461
- };
462
- const notifySuccess = (payload) => {
463
- if (!options?.callbacks?.onSuccess) return;
464
- options.callbacks.onSuccess(payload ?? {});
465
- };
466
- const notifyError = (error) => {
467
- options?.callbacks?.onError?.(new Error(error));
468
- };
469
- return {
470
- ...initialState,
471
- setSelectedMethod: (methodId) => {
472
- if (get().selectedMethodId === methodId) return;
473
- set({ selectedMethodId: methodId });
474
- },
475
- setSolanaModalOpen: (open) => {
476
- if (get().solanaModalOpen === open) return;
477
- set({ solanaModalOpen: open });
478
- },
479
- setSolanaTab: (tab) => {
480
- if (get().solanaTab === tab) return;
481
- set({ solanaTab: tab });
482
- },
483
- setSolanaSelectedToken: (symbol) => {
484
- if (get().solanaSelectedToken === symbol) return;
485
- set({ solanaSelectedToken: symbol });
486
- },
487
- setSolanaTokenAmount: (amount) => {
488
- if (get().solanaTokenAmount === amount) return;
489
- set({ solanaTokenAmount: amount });
490
- },
491
- setSolanaTransactionId: (txId) => {
492
- if (get().solanaTransactionId === txId) return;
493
- set({ solanaTransactionId: txId });
494
- },
495
- startSavedPayment: () => {
496
- notifyStatus("processing", { source: "saved-payment" });
497
- set({ savedPaymentStatus: "processing", savedPaymentError: null });
498
- },
499
- completeSavedPayment: () => {
500
- notifyStatus("success", { source: "saved-payment" });
501
- set({ savedPaymentStatus: "success", savedPaymentError: null });
502
- },
503
- failSavedPayment: (error) => {
504
- notifyStatus("error", { source: "saved-payment" });
505
- notifyError(error);
506
- set({ savedPaymentStatus: "error", savedPaymentError: error });
507
- },
508
- resetSavedPayment: () => set({ savedPaymentStatus: "idle", savedPaymentError: null }),
509
- startNewCardPayment: () => {
510
- notifyStatus("processing", { source: "new-card" });
511
- set({ newCardStatus: "processing", newCardError: null });
512
- },
513
- completeNewCardPayment: () => {
514
- notifyStatus("success", { source: "new-card" });
515
- set({ newCardStatus: "success", newCardError: null });
516
- },
517
- failNewCardPayment: (error) => {
518
- notifyStatus("error", { source: "new-card" });
519
- notifyError(error);
520
- set({ newCardStatus: "error", newCardError: error });
521
- },
522
- resetNewCardPayment: () => set({ newCardStatus: "idle", newCardError: null }),
523
- startSolanaPayment: () => {
524
- notifyStatus("processing", { source: "solana" });
525
- set({ solanaStatus: "processing", solanaError: null });
526
- },
527
- confirmSolanaPayment: () => set({ solanaStatus: "confirming" }),
528
- completeSolanaPayment: (payload) => {
529
- notifyStatus("success", { source: "solana" });
530
- notifySuccess(payload);
531
- set({ solanaStatus: "success", solanaError: null });
532
- },
533
- failSolanaPayment: (error) => {
534
- notifyStatus("error", { source: "solana" });
535
- notifyError(error);
536
- 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
537
539
  },
538
- resetSolanaPayment: () => set({
539
- solanaStatus: "selecting",
540
- solanaError: null,
541
- solanaTransactionId: null
542
- }),
543
- resetAll: () => set(initialState)
544
- };
540
+ mutations: {
541
+ retry: 1
542
+ }
543
+ }
545
544
  });
546
- var PaymentContext = React3.createContext(void 0);
547
- var PaymentProvider = ({
548
- config,
549
- children
550
- }) => {
551
- const app = React3.useMemo(() => new PaymentApp({ config }), [config]);
552
- const store = React3.useMemo(
553
- () => createPaymentStore({ callbacks: config.callbacks }),
554
- [config.callbacks]
555
- );
556
- const value = React3.useMemo(() => {
557
- return {
558
- config: app.getConfig(),
559
- fetcher: app.getFetcher(),
560
- resolveAuthToken: app.resolveAuthToken,
561
- app,
562
- services: app.getServices(),
563
- store
564
- };
565
- }, [app, store]);
566
- React3.useEffect(() => {
567
- if (!value.config.collectJsKey) return;
568
- loadCollectJs(value.config.collectJsKey);
569
- }, [value.config.collectJsKey]);
570
- return /* @__PURE__ */ jsxRuntime.jsx(PaymentContext.Provider, { value, children });
571
- };
572
- var usePaymentContext = () => {
573
- const context = React3.useContext(PaymentContext);
574
- if (!context) {
575
- 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();
576
551
  }
577
- return context;
578
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;
579
622
  var customCountries = [
580
623
  { code: "TW", name: "Taiwan, Province of China" },
581
624
  { code: "KR", name: "Korea" },
@@ -705,9 +748,6 @@ function getElementRef(element) {
705
748
  }
706
749
  return element.props.ref || element.ref;
707
750
  }
708
- function cn(...inputs) {
709
- return tailwindMerge.twMerge(clsx.clsx(inputs));
710
- }
711
751
  var buttonVariants = classVarianceAuthority.cva(
712
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",
713
753
  {
@@ -850,7 +890,6 @@ var defaultBilling = {
850
890
  firstName: "",
851
891
  lastName: "",
852
892
  address1: "",
853
- address2: "",
854
893
  city: "",
855
894
  stateRegion: "",
856
895
  postalCode: "",
@@ -884,7 +923,6 @@ var CardDetailsForm = ({
884
923
  const [firstName, setFirstName] = React3.useState(mergedDefaults.firstName);
885
924
  const [lastName, setLastName] = React3.useState(mergedDefaults.lastName);
886
925
  const [address1, setAddress1] = React3.useState(mergedDefaults.address1);
887
- const [address2, setAddress2] = React3.useState(mergedDefaults.address2 ?? "");
888
926
  const [city, setCity] = React3.useState(mergedDefaults.city);
889
927
  const [stateRegion, setStateRegion] = React3.useState(mergedDefaults.stateRegion ?? "");
890
928
  const [postalCode, setPostalCode] = React3.useState(mergedDefaults.postalCode);
@@ -903,7 +941,6 @@ var CardDetailsForm = ({
903
941
  setFirstName(mergedDefaults.firstName);
904
942
  setLastName(mergedDefaults.lastName);
905
943
  setAddress1(mergedDefaults.address1);
906
- setAddress2(mergedDefaults.address2 ?? "");
907
944
  setCity(mergedDefaults.city);
908
945
  setStateRegion(mergedDefaults.stateRegion ?? "");
909
946
  setPostalCode(mergedDefaults.postalCode);
@@ -916,7 +953,6 @@ var CardDetailsForm = ({
916
953
  firstName,
917
954
  lastName,
918
955
  address1,
919
- address2,
920
956
  city,
921
957
  stateRegion,
922
958
  postalCode,
@@ -928,7 +964,6 @@ var CardDetailsForm = ({
928
964
  firstName,
929
965
  lastName,
930
966
  address1,
931
- address2,
932
967
  city,
933
968
  stateRegion,
934
969
  postalCode,
@@ -952,7 +987,6 @@ var CardDetailsForm = ({
952
987
  firstName,
953
988
  lastName,
954
989
  address1,
955
- address2,
956
990
  city,
957
991
  stateRegion,
958
992
  postalCode,
@@ -983,7 +1017,6 @@ var CardDetailsForm = ({
983
1017
  firstName,
984
1018
  lastName,
985
1019
  address1,
986
- address2,
987
1020
  city,
988
1021
  stateRegion,
989
1022
  postalCode,
@@ -1012,19 +1045,16 @@ var CardDetailsForm = ({
1012
1045
  window.CollectJS.startPaymentRequest();
1013
1046
  };
1014
1047
  const errorMessage = localError ?? externalError;
1015
- 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";
1016
1049
  return /* @__PURE__ */ jsxRuntime.jsxs(
1017
1050
  "form",
1018
1051
  {
1019
- className: cn(
1020
- "space-y-6 rounded-2xl border border-border/60 bg-card/90 p-6 shadow-lg",
1021
- className
1022
- ),
1052
+ className: cn("space-y-5", className),
1023
1053
  onSubmit: handleSubmit,
1024
1054
  noValidate: true,
1025
1055
  children: [
1026
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 }),
1027
- /* @__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: [
1028
1058
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1029
1059
  /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-first", className: "flex items-center gap-2 text-muted-foreground", children: [
1030
1060
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "h-4 w-4" }),
@@ -1070,7 +1100,7 @@ var CardDetailsForm = ({
1070
1100
  )
1071
1101
  ] }),
1072
1102
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1073
- /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-address1", children: "Address line 1" }),
1103
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-address1", children: "Address" }),
1074
1104
  /* @__PURE__ */ jsxRuntime.jsx(
1075
1105
  Input,
1076
1106
  {
@@ -1081,18 +1111,7 @@ var CardDetailsForm = ({
1081
1111
  }
1082
1112
  )
1083
1113
  ] }),
1084
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1085
- /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-address2", children: "Address line 2 (optional)" }),
1086
- /* @__PURE__ */ jsxRuntime.jsx(
1087
- Input,
1088
- {
1089
- id: "payments-address2",
1090
- value: address2,
1091
- onChange: (e) => setAddress2(e.target.value)
1092
- }
1093
- )
1094
- ] }),
1095
- /* @__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: [
1096
1115
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1097
1116
  /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "payments-city", children: "City" }),
1098
1117
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1117,7 +1136,7 @@ var CardDetailsForm = ({
1117
1136
  )
1118
1137
  ] })
1119
1138
  ] }),
1120
- /* @__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: [
1121
1140
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1122
1141
  /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: "payments-postal", className: "flex items-center gap-2 text-muted-foreground", children: [
1123
1142
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-4 w-4" }),
@@ -1137,7 +1156,7 @@ var CardDetailsForm = ({
1137
1156
  /* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Country" }),
1138
1157
  /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: country, onValueChange: setCountry, children: [
1139
1158
  /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select a country" }) }),
1140
- /* @__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)) })
1141
1160
  ] })
1142
1161
  ] })
1143
1162
  ] }),
@@ -1226,63 +1245,6 @@ var usePaymentMethods = () => {
1226
1245
  deleteMutation
1227
1246
  };
1228
1247
  };
1229
- var Dialog = DialogPrimitive__namespace.Root;
1230
- var DialogPortal = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(DialogPrimitive__namespace.Portal, { className: cn(className), ...props });
1231
- DialogPortal.displayName = DialogPrimitive__namespace.Portal.displayName;
1232
- var DialogOverlay = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1233
- DialogPrimitive__namespace.Overlay,
1234
- {
1235
- ref,
1236
- className: cn(
1237
- "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",
1238
- className
1239
- ),
1240
- ...props
1241
- }
1242
- ));
1243
- DialogOverlay.displayName = DialogPrimitive__namespace.Overlay.displayName;
1244
- var DialogContent = React3__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { children: [
1245
- /* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
1246
- /* @__PURE__ */ jsxRuntime.jsxs(
1247
- DialogPrimitive__namespace.Content,
1248
- {
1249
- ref,
1250
- className: cn(
1251
- "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%]",
1252
- className
1253
- ),
1254
- ...props,
1255
- children: [
1256
- children,
1257
- /* @__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: [
1258
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }),
1259
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
1260
- ] })
1261
- ]
1262
- }
1263
- )
1264
- ] }));
1265
- DialogContent.displayName = DialogPrimitive__namespace.Content.displayName;
1266
- var DialogHeader = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className), ...props });
1267
- DialogHeader.displayName = "DialogHeader";
1268
- var DialogTitle = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1269
- DialogPrimitive__namespace.Title,
1270
- {
1271
- ref,
1272
- className: cn("text-lg font-semibold leading-none tracking-tight", className),
1273
- ...props
1274
- }
1275
- ));
1276
- DialogTitle.displayName = DialogPrimitive__namespace.Title.displayName;
1277
- var DialogDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1278
- DialogPrimitive__namespace.Description,
1279
- {
1280
- ref,
1281
- className: cn("text-sm text-muted-foreground", className),
1282
- ...props
1283
- }
1284
- ));
1285
- DialogDescription.displayName = DialogPrimitive__namespace.Description.displayName;
1286
1248
  var badgeVariants = classVarianceAuthority.cva(
1287
1249
  "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none",
1288
1250
  {
@@ -1332,43 +1294,6 @@ var ScrollBar = React3__namespace.forwardRef(({ className, orientation = "vertic
1332
1294
  }
1333
1295
  ));
1334
1296
  ScrollBar.displayName = ScrollAreaPrimitive__namespace.ScrollAreaScrollbar.displayName;
1335
- var Card = React3__namespace.forwardRef(
1336
- ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1337
- "div",
1338
- {
1339
- ref,
1340
- className: cn("rounded-xl border bg-card text-card-foreground shadow", className),
1341
- ...props
1342
- }
1343
- )
1344
- );
1345
- Card.displayName = "Card";
1346
- var CardHeader = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1347
- "div",
1348
- {
1349
- ref,
1350
- className: cn("flex flex-col space-y-1.5 p-6", className),
1351
- ...props
1352
- }
1353
- ));
1354
- CardHeader.displayName = "CardHeader";
1355
- var CardTitle = React3__namespace.forwardRef(
1356
- ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
1357
- );
1358
- CardTitle.displayName = "CardTitle";
1359
- var CardDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("p", { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
1360
- CardDescription.displayName = "CardDescription";
1361
- var CardContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
1362
- CardContent.displayName = "CardContent";
1363
- var CardFooter = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1364
- "div",
1365
- {
1366
- ref,
1367
- className: cn("flex items-center p-6 pt-0", className),
1368
- ...props
1369
- }
1370
- ));
1371
- CardFooter.displayName = "CardFooter";
1372
1297
  var formatCardLabel = (method) => {
1373
1298
  const brand = method.card_type ? method.card_type.toUpperCase() : "CARD";
1374
1299
  const lastFour = method.last_four ? `\u2022\u2022\u2022\u2022 ${method.last_four}` : "";
@@ -1397,22 +1322,22 @@ var StoredPaymentMethods = ({
1397
1322
  }
1398
1323
  );
1399
1324
  };
1400
- return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-border/60 bg-card/95", children: [
1401
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-row items-start justify-between space-y-0", children: [
1402
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1403
- /* @__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: [
1404
1329
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WalletCards, { className: "h-4 w-4" }),
1405
1330
  " ",
1406
1331
  heading
1407
- ] }) }),
1408
- /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: description })
1332
+ ] }),
1333
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: description })
1409
1334
  ] }),
1410
- 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: [
1411
1336
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
1412
1337
  " Add card"
1413
1338
  ] })
1414
1339
  ] }),
1415
- /* @__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: [
1416
1341
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
1417
1342
  " Loading cards\u2026"
1418
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) => {
@@ -1470,8 +1395,8 @@ var StoredPaymentMethods = ({
1470
1395
  },
1471
1396
  method.id
1472
1397
  );
1473
- }) }) }) }),
1474
- /* @__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: [
1475
1400
  /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
1476
1401
  /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Add a new card" }),
1477
1402
  /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "Your card details are tokenized securely via our payment provider." })
@@ -1490,6 +1415,71 @@ var StoredPaymentMethods = ({
1490
1415
  ] }) })
1491
1416
  ] });
1492
1417
  };
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
+ };
1493
1483
  var useSolanaService = () => {
1494
1484
  const { services } = usePaymentContext();
1495
1485
  return React3.useMemo(() => services.solanaPayments, [services]);
@@ -1766,6 +1756,43 @@ var useSolanaDirectPayment = (options) => {
1766
1756
  pay
1767
1757
  };
1768
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";
1769
1796
  var DirectPayment = ({
1770
1797
  priceId,
1771
1798
  tokenAmount,
@@ -1786,7 +1813,7 @@ var DirectPayment = ({
1786
1813
  onSuccess: onPaymentSuccess,
1787
1814
  onError: onPaymentError
1788
1815
  });
1789
- 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: [
1790
1817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
1791
1818
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [
1792
1819
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "h-4 w-4" }),
@@ -2018,9 +2045,9 @@ var QRCodePayment = ({
2018
2045
  onSuccess: onPaymentSuccess
2019
2046
  });
2020
2047
  if (!selectedToken) {
2021
- 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." });
2022
2049
  }
2023
- 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: [
2024
2051
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
2025
2052
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2026
2053
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-foreground", children: "Scan with Solana Pay" }),
@@ -2249,109 +2276,21 @@ var useSupportedTokens = () => {
2249
2276
  tokenCount: tokens.length
2250
2277
  };
2251
2278
  };
2252
- var usePaymentStore = (selector) => {
2253
- const { store } = usePaymentContext();
2254
- return zustand.useStore(store, selector);
2255
- };
2256
-
2257
- // src/state/selectors.ts
2258
- var selectCheckoutFlow = (state) => ({
2259
- selectedMethodId: state.selectedMethodId,
2260
- savedStatus: state.savedPaymentStatus,
2261
- savedError: state.savedPaymentError,
2262
- newCardStatus: state.newCardStatus,
2263
- newCardError: state.newCardError,
2264
- solanaModalOpen: state.solanaModalOpen,
2265
- setSelectedMethod: state.setSelectedMethod,
2266
- setSolanaModalOpen: state.setSolanaModalOpen,
2267
- startSavedPayment: state.startSavedPayment,
2268
- completeSavedPayment: state.completeSavedPayment,
2269
- failSavedPayment: state.failSavedPayment,
2270
- startNewCardPayment: state.startNewCardPayment,
2271
- completeNewCardPayment: state.completeNewCardPayment,
2272
- failNewCardPayment: state.failNewCardPayment,
2273
- resetSavedPayment: state.resetSavedPayment
2274
- });
2275
- var selectSolanaFlow = (state) => ({
2276
- tab: state.solanaTab,
2277
- status: state.solanaStatus,
2278
- error: state.solanaError,
2279
- transactionId: state.solanaTransactionId,
2280
- tokenAmount: state.solanaTokenAmount,
2281
- selectedTokenSymbol: state.solanaSelectedToken,
2282
- setTab: state.setSolanaTab,
2283
- setTokenAmount: state.setSolanaTokenAmount,
2284
- setTransactionId: state.setSolanaTransactionId,
2285
- setSelectedTokenSymbol: state.setSolanaSelectedToken,
2286
- startSolanaPayment: state.startSolanaPayment,
2287
- confirmSolanaPayment: state.confirmSolanaPayment,
2288
- completeSolanaPayment: state.completeSolanaPayment,
2289
- failSolanaPayment: state.failSolanaPayment,
2290
- resetSolanaPayment: state.resetSolanaPayment
2291
- });
2292
- var Tabs = TabsPrimitive__namespace.Root;
2293
- var TabsList = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2294
- TabsPrimitive__namespace.List,
2295
- {
2296
- ref,
2297
- className: cn(
2298
- "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
2299
- className
2300
- ),
2301
- ...props
2302
- }
2303
- ));
2304
- TabsList.displayName = TabsPrimitive__namespace.List.displayName;
2305
- var TabsTrigger = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2306
- TabsPrimitive__namespace.Trigger,
2307
- {
2308
- ref,
2309
- className: cn(
2310
- "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",
2311
- className
2312
- ),
2313
- ...props
2314
- }
2315
- ));
2316
- TabsTrigger.displayName = TabsPrimitive__namespace.Trigger.displayName;
2317
- var TabsContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
2318
- TabsPrimitive__namespace.Content,
2319
- {
2320
- ref,
2321
- className: cn(
2322
- "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
2323
- className
2324
- ),
2325
- ...props
2326
- }
2327
- ));
2328
- TabsContent.displayName = TabsPrimitive__namespace.Content.displayName;
2329
- var SolanaPaymentSelector = ({
2330
- isOpen,
2331
- onClose,
2279
+ var SolanaPaymentView = ({
2332
2280
  priceId,
2333
2281
  usdAmount,
2334
2282
  onSuccess,
2335
- onError
2283
+ onError,
2284
+ onClose
2336
2285
  }) => {
2337
2286
  const { connected } = walletAdapterReact.useWallet();
2338
- const {
2339
- tab: activeTab,
2340
- status: paymentState,
2341
- error: errorMessage,
2342
- transactionId,
2343
- tokenAmount,
2344
- selectedTokenSymbol,
2345
- setTab,
2346
- setTokenAmount,
2347
- setTransactionId,
2348
- setSelectedTokenSymbol,
2349
- startSolanaPayment,
2350
- confirmSolanaPayment,
2351
- completeSolanaPayment,
2352
- failSolanaPayment,
2353
- resetSolanaPayment
2354
- } = 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);
2355
2294
  const {
2356
2295
  tokens,
2357
2296
  isLoading: tokensLoading,
@@ -2367,60 +2306,70 @@ var SolanaPaymentSelector = ({
2367
2306
  const defaultToken = tokens.find((token) => token.symbol === "SOL") || tokens[0];
2368
2307
  setSelectedTokenSymbol(defaultToken.symbol);
2369
2308
  }
2370
- }, [tokens, selectedTokenSymbol, setSelectedTokenSymbol]);
2309
+ }, [tokens, selectedTokenSymbol]);
2371
2310
  const handlePaymentStart = React3.useCallback(() => {
2372
- startSolanaPayment();
2373
- }, [startSolanaPayment]);
2311
+ setPaymentState("processing");
2312
+ setErrorMessage(null);
2313
+ notifyStatus("processing", { source: "solana" });
2314
+ }, [notifyStatus]);
2374
2315
  const handlePaymentConfirming = React3.useCallback(() => {
2375
- confirmSolanaPayment();
2376
- }, [confirmSolanaPayment]);
2316
+ setPaymentState("confirming");
2317
+ }, []);
2377
2318
  const handlePaymentSuccess = React3.useCallback(
2378
2319
  (result, txId) => {
2379
2320
  const resolvedTx = txId || (typeof result === "string" ? result : result.transaction_id);
2380
2321
  setTransactionId(resolvedTx);
2381
- completeSolanaPayment(
2382
- typeof result === "string" ? {
2383
- transactionId: resolvedTx,
2384
- processor: "solana",
2385
- metadata: { source: "solana-pay" }
2386
- } : {
2387
- transactionId: result.transaction_id,
2388
- intentId: result.intent_id,
2389
- processor: "solana",
2390
- metadata: {
2391
- purchaseId: result.purchase_id,
2392
- amount: result.amount,
2393
- currency: result.currency
2394
- }
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
2395
2336
  }
2396
- );
2337
+ };
2338
+ notifyStatus("success", { source: "solana" });
2339
+ notifySuccess(payload);
2397
2340
  setTimeout(() => {
2398
2341
  onSuccess(result);
2399
2342
  }, 1500);
2400
2343
  },
2401
- [completeSolanaPayment, onSuccess, setTransactionId]
2344
+ [notifyStatus, notifySuccess, onSuccess]
2402
2345
  );
2403
2346
  const handlePaymentError = React3.useCallback(
2404
2347
  (error) => {
2405
- failSolanaPayment(error);
2348
+ setPaymentState("error");
2349
+ setErrorMessage(error);
2350
+ notifyStatus("error", { source: "solana" });
2351
+ notifyError(error);
2406
2352
  onError?.(error);
2407
2353
  },
2408
- [failSolanaPayment, onError]
2354
+ [notifyError, notifyStatus, onError]
2409
2355
  );
2410
- const handleRetry = React3.useCallback(() => {
2411
- resetSolanaPayment();
2356
+ const resetState = React3.useCallback(() => {
2357
+ setPaymentState("selecting");
2358
+ setErrorMessage(null);
2412
2359
  setTransactionId(null);
2413
- }, [resetSolanaPayment, setTransactionId]);
2360
+ }, []);
2361
+ const handleRetry = React3.useCallback(() => {
2362
+ resetState();
2363
+ }, [resetState]);
2414
2364
  const handleClose = React3.useCallback(() => {
2415
2365
  if (paymentState === "processing" || paymentState === "confirming") {
2416
2366
  return;
2417
2367
  }
2418
- resetSolanaPayment();
2419
- setTransactionId(null);
2420
- onClose();
2421
- }, [paymentState, resetSolanaPayment, setTransactionId, onClose]);
2368
+ resetState();
2369
+ onClose?.();
2370
+ }, [paymentState, onClose, resetState]);
2422
2371
  React3.useEffect(() => {
2423
- if (!isOpen || !selectedToken || usdAmount === 0) {
2372
+ if (!selectedToken || usdAmount === 0) {
2424
2373
  setTokenAmount(0);
2425
2374
  return;
2426
2375
  }
@@ -2430,23 +2379,20 @@ var SolanaPaymentSelector = ({
2430
2379
  return;
2431
2380
  }
2432
2381
  setTokenAmount(usdAmount / price);
2433
- }, [isOpen, usdAmount, selectedToken, setTokenAmount]);
2434
- const handleTokenChange = React3.useCallback(
2435
- (value) => {
2436
- setSelectedTokenSymbol(value);
2437
- },
2438
- [setSelectedTokenSymbol]
2439
- );
2382
+ }, [usdAmount, selectedToken]);
2383
+ const handleTokenChange = React3.useCallback((value) => {
2384
+ setSelectedTokenSymbol(value);
2385
+ }, []);
2440
2386
  const wasConnectedRef = React3.useRef(connected);
2441
2387
  React3.useEffect(() => {
2442
2388
  if (connected && !wasConnectedRef.current) {
2443
- setTab("wallet");
2389
+ setActiveTab("wallet");
2444
2390
  }
2445
2391
  if (!connected && wasConnectedRef.current) {
2446
- setTab("qr");
2392
+ setActiveTab("qr");
2447
2393
  }
2448
2394
  wasConnectedRef.current = connected;
2449
- }, [connected, setTab]);
2395
+ }, [connected]);
2450
2396
  const renderBody = () => {
2451
2397
  if (paymentState !== "selecting") {
2452
2398
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -2462,63 +2408,79 @@ var SolanaPaymentSelector = ({
2462
2408
  }
2463
2409
  );
2464
2410
  }
2465
- 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: [
2466
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
2467
- " Loading supported tokens\u2026"
2468
- ] }) : 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: [
2469
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border/60 bg-muted/10 p-4 text-center", children: [
2470
- /* @__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: [
2471
2427
  "$",
2472
2428
  usdAmount.toFixed(2),
2473
2429
  " USD"
2474
2430
  ] }),
2475
- 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: [
2476
2432
  "\u2248 ",
2477
2433
  tokenAmount.toFixed(selectedToken.symbol === "SOL" ? 4 : 2),
2478
2434
  " ",
2479
2435
  selectedToken.symbol
2480
2436
  ] })
2481
2437
  ] }),
2482
- /* @__PURE__ */ jsxRuntime.jsxs(Select, { value: selectedToken?.symbol ?? "", onValueChange: handleTokenChange, children: [
2483
- /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Select token" }) }),
2484
- /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { className: "max-h-64", children: tokens.map((token) => /* @__PURE__ */ jsxRuntime.jsxs(SelectItem, { value: token.symbol, children: [
2485
- token.name,
2486
- " (",
2487
- token.symbol,
2488
- ")"
2489
- ] }, 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
+ ] })
2490
2449
  ] }),
2491
- /* @__PURE__ */ jsxRuntime.jsxs(
2450
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
2492
2451
  Tabs,
2493
2452
  {
2494
2453
  value: activeTab,
2495
- onValueChange: (value) => setTab(value),
2496
- className: "w-full",
2454
+ onValueChange: (value) => setActiveTab(value),
2455
+ className: "w-full space-y-3",
2497
2456
  children: [
2498
- /* @__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: [
2499
2458
  /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "wallet", disabled: !connected, children: [
2500
2459
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "mr-2 h-4 w-4" }),
2501
- " Pay with Wallet"
2460
+ " Wallet"
2502
2461
  ] }),
2503
2462
  /* @__PURE__ */ jsxRuntime.jsxs(TabsTrigger, { value: "qr", children: [
2504
2463
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
2505
- " Scan QR Code"
2464
+ " QR Code"
2506
2465
  ] })
2507
2466
  ] }),
2508
- /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: "wallet", className: "mt-4", children: activeTab === "wallet" && /* @__PURE__ */ jsxRuntime.jsx(
2509
- DirectPayment,
2510
- {
2511
- priceId,
2512
- tokenAmount,
2513
- selectedToken,
2514
- supportedTokens: tokens,
2515
- onPaymentStart: handlePaymentStart,
2516
- onPaymentConfirming: handlePaymentConfirming,
2517
- onPaymentSuccess: handlePaymentSuccess,
2518
- onPaymentError: handlePaymentError
2519
- }
2520
- ) }),
2521
- /* @__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(
2522
2484
  QRCodePayment,
2523
2485
  {
2524
2486
  priceId,
@@ -2529,17 +2491,34 @@ var SolanaPaymentSelector = ({
2529
2491
  ) })
2530
2492
  ]
2531
2493
  }
2532
- ),
2533
- !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." })
2534
- ] }) });
2494
+ ) })
2495
+ ] });
2535
2496
  };
2536
- return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-lg", children: [
2537
- /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { className: "space-y-1", children: [
2538
- /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Complete your payment" }),
2539
- /* @__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
+ )
2540
2519
  ] }),
2541
2520
  renderBody()
2542
- ] }) });
2521
+ ] });
2543
2522
  };
2544
2523
  var PaymentExperience = ({
2545
2524
  priceId,
@@ -2549,138 +2528,176 @@ var PaymentExperience = ({
2549
2528
  enableNewCard = true,
2550
2529
  enableStoredMethods = true,
2551
2530
  enableSolanaPay = true,
2552
- checkoutSummary,
2553
2531
  onSolanaSuccess,
2554
- onSolanaError
2532
+ onSolanaError,
2533
+ initialMode = "cards"
2555
2534
  }) => {
2556
2535
  const showNewCard = enableNewCard && Boolean(onNewCardPayment);
2557
- const showStored = enableStoredMethods;
2558
- const {
2559
- selectedMethodId,
2560
- savedStatus,
2561
- savedError,
2562
- newCardStatus,
2563
- newCardError,
2564
- solanaModalOpen,
2565
- setSelectedMethod,
2566
- setSolanaModalOpen,
2567
- startSavedPayment,
2568
- completeSavedPayment,
2569
- failSavedPayment,
2570
- startNewCardPayment,
2571
- completeNewCardPayment,
2572
- failNewCardPayment,
2573
- resetSavedPayment
2574
- } = usePaymentStore(selectCheckoutFlow);
2575
- const handleMethodSelect = (method) => {
2576
- setSelectedMethod(method.id);
2577
- resetSavedPayment();
2578
- };
2579
- const handleNewCardTokenize = async (token, billing) => {
2580
- if (!onNewCardPayment) return;
2581
- try {
2582
- startNewCardPayment();
2583
- await onNewCardPayment({ token, billing });
2584
- completeNewCardPayment();
2585
- } catch (error) {
2586
- const message = error instanceof Error ? error.message : "Unable to complete payment";
2587
- 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;
2588
2555
  }
2589
- };
2590
- 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 () => {
2591
2568
  if (!onSavedMethodPayment || !selectedMethodId) return;
2592
2569
  try {
2593
- startSavedPayment();
2570
+ setSavedStatus("processing");
2571
+ setSavedError(null);
2572
+ notifyStatus("processing", { source: "saved-payment" });
2594
2573
  await onSavedMethodPayment({
2595
2574
  paymentMethodId: selectedMethodId,
2596
2575
  amount: usdAmount
2597
2576
  });
2598
- completeSavedPayment();
2577
+ setSavedStatus("success");
2578
+ notifyStatus("success", { source: "saved-payment" });
2599
2579
  } catch (error) {
2600
2580
  const message = error instanceof Error ? error.message : "Unable to complete payment with saved card";
2601
- 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." });
2602
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
+ ] });
2603
2653
  };
2604
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-8", children: [
2605
- /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-border/60 bg-card/95", children: [
2606
- /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
2607
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2608
- /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2 text-lg text-foreground", children: [
2609
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-5 w-5 text-primary" }),
2610
- " Secure checkout"
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,
2660
+ {
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" })
2611
2680
  ] }),
2612
- /* @__PURE__ */ jsxRuntime.jsxs(CardDescription, { children: [
2613
- "Amount due: $",
2614
- usdAmount.toFixed(2)
2615
- ] })
2616
- ] }),
2617
- checkoutSummary && /* @__PURE__ */ jsxRuntime.jsx("div", { children: checkoutSummary })
2618
- ] }),
2619
- /* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-8 lg:grid-cols-2", children: [
2620
- showStored && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
2621
- /* @__PURE__ */ jsxRuntime.jsx(
2622
- StoredPaymentMethods,
2623
- {
2624
- selectedMethodId,
2625
- onMethodSelect: handleMethodSelect,
2626
- heading: "Saved cards",
2627
- description: "Use or manage your saved payment methods."
2628
- }
2629
- ),
2630
- onSavedMethodPayment && /* @__PURE__ */ jsxRuntime.jsx(
2631
- Button,
2632
- {
2633
- className: "w-full",
2634
- disabled: !selectedMethodId || savedStatus === "processing",
2635
- onClick: handleSavedPayment,
2636
- children: savedStatus === "processing" ? "Processing\u2026" : "Pay with selected card"
2637
- }
2638
- ),
2639
- savedError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: savedError })
2640
- ] }),
2641
- 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: [
2642
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4 space-y-1", children: [
2643
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [
2644
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }),
2645
- " Pay with a new card"
2646
- ] }),
2647
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Card details are tokenized via Collect.js and never hit your server." })
2648
- ] }),
2649
- /* @__PURE__ */ jsxRuntime.jsx(
2650
- CardDetailsForm,
2651
- {
2652
- visible: true,
2653
- submitLabel: "Pay now",
2654
- submitting: newCardStatus === "processing",
2655
- externalError: newCardError,
2656
- onTokenize: handleNewCardTokenize
2657
- }
2658
- )
2659
- ] }) })
2660
- ] }) })
2661
- ] }),
2662
- 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: [
2663
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2664
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-2 text-base font-semibold text-primary", children: [
2665
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "h-4 w-4" }),
2666
- " Prefer Solana Pay?"
2667
- ] }),
2668
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-primary/80", children: "Use a Solana wallet or QR code for instant settlement." })
2669
- ] }),
2670
- /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => setSolanaModalOpen(true), children: "Open Solana Pay" })
2671
- ] }) }),
2672
- enableSolanaPay && /* @__PURE__ */ jsxRuntime.jsx(
2673
- SolanaPaymentSelector,
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,
2674
2695
  {
2675
- isOpen: solanaModalOpen,
2676
- onClose: () => setSolanaModalOpen(false),
2677
2696
  priceId,
2678
2697
  usdAmount,
2679
- onSuccess: (result) => {
2680
- setSolanaModalOpen(false);
2681
- onSolanaSuccess?.(result);
2682
- },
2683
- onError: onSolanaError
2698
+ onSuccess: handleSolanaSuccess,
2699
+ onError: handleSolanaError,
2700
+ onClose: exitSolanaView
2684
2701
  }
2685
2702
  )
2686
2703
  ] });
@@ -2694,23 +2711,23 @@ var SubscriptionSuccessDialog = ({
2694
2711
  }) => {
2695
2712
  return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: (value) => {
2696
2713
  if (!value) onClose();
2697
- }, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-w-sm text-center", children: [
2698
- /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
2699
- /* @__PURE__ */ jsxRuntime.jsxs(DialogTitle, { className: "flex flex-col items-center gap-3 text-foreground", children: [
2700
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-10 w-10 text-primary" }),
2701
- "Subscription activated"
2702
- ] }),
2703
- /* @__PURE__ */ jsxRuntime.jsxs(DialogDescription, { className: "text-base text-muted-foreground", children: [
2704
- "You now have access to ",
2705
- planName,
2706
- ". Billing: ",
2707
- amountLabel,
2708
- " / ",
2709
- billingPeriodLabel,
2710
- "."
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
+ ] })
2711
2728
  ] })
2712
2729
  ] }),
2713
- /* @__PURE__ */ jsxRuntime.jsx(Button, { className: "mt-6 w-full", onClick: onClose, children: "Continue" })
2730
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-6", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { className: "w-full", onClick: onClose, children: "Continue exploring" }) })
2714
2731
  ] }) });
2715
2732
  };
2716
2733
  var useSubscriptionActions = () => {
@@ -2832,23 +2849,22 @@ var SubscriptionCheckoutModal = ({
2832
2849
  userEmail,
2833
2850
  provider = "mobius",
2834
2851
  onSuccess,
2835
- enableSolanaPay = true
2852
+ enableSolanaPay = true,
2853
+ onSolanaSuccess,
2854
+ onSolanaError,
2855
+ initialMode = "cards"
2836
2856
  }) => {
2837
2857
  const [showSuccess, setShowSuccess] = React3.useState(false);
2838
2858
  const { subscribeWithCard, subscribeWithSavedMethod } = useSubscriptionActions();
2839
2859
  const handleClose = React3.useCallback(
2840
2860
  (nextOpen) => {
2841
2861
  onOpenChange(nextOpen);
2842
- if (!nextOpen) {
2843
- setShowSuccess(false);
2844
- }
2862
+ if (!nextOpen) setShowSuccess(false);
2845
2863
  },
2846
2864
  [onOpenChange]
2847
2865
  );
2848
2866
  const ensurePrice = () => {
2849
- if (!priceId) {
2850
- throw new Error("Select a plan before subscribing.");
2851
- }
2867
+ if (!priceId) throw new Error("Select a plan before subscribing.");
2852
2868
  return priceId;
2853
2869
  };
2854
2870
  const notifySuccess = (result) => {
@@ -2878,40 +2894,34 @@ var SubscriptionCheckoutModal = ({
2878
2894
  };
2879
2895
  const solanaSuccess = (result) => {
2880
2896
  notifySuccess(result);
2897
+ onSolanaSuccess?.(result);
2881
2898
  onOpenChange(false);
2882
2899
  };
2883
- const summary = React3.useMemo(() => {
2884
- if (!planName && !amountLabel) return null;
2885
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border/60 bg-muted/10 p-3 text-sm text-muted-foreground", children: [
2886
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-foreground", children: planName ?? "Selected plan" }),
2887
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
2888
- amountLabel ?? `$${usdAmount.toFixed(2)}`,
2889
- " ",
2890
- billingPeriodLabel ? `/ ${billingPeriodLabel}` : ""
2891
- ] })
2892
- ] });
2893
- }, [planName, amountLabel, billingPeriodLabel, usdAmount]);
2900
+ const solanaError = (error) => {
2901
+ onSolanaError?.(error);
2902
+ };
2894
2903
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2895
- /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-3xl", children: [
2896
- !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: [
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: [
2897
2906
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-4 w-4" }),
2898
2907
  " Select a subscription plan to continue."
2899
2908
  ] }),
2900
2909
  /* @__PURE__ */ jsxRuntime.jsx(
2901
2910
  PaymentExperience,
2902
2911
  {
2903
- priceId: priceId ?? "",
2904
2912
  usdAmount,
2905
- checkoutSummary: summary,
2906
- onNewCardPayment: priceId ? handleNewCardPayment : void 0,
2907
- onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
2913
+ priceId: priceId ?? "",
2914
+ onSolanaSuccess: solanaSuccess,
2915
+ onSolanaError: solanaError,
2908
2916
  enableNewCard: Boolean(priceId),
2909
2917
  enableStoredMethods: Boolean(priceId),
2910
2918
  enableSolanaPay: enableSolanaPay && Boolean(priceId),
2911
- onSolanaSuccess: solanaSuccess
2919
+ onNewCardPayment: priceId ? handleNewCardPayment : void 0,
2920
+ onSavedMethodPayment: priceId ? handleSavedMethodPayment : void 0,
2921
+ initialMode
2912
2922
  }
2913
2923
  )
2914
- ] }) }),
2924
+ ] }) }) }),
2915
2925
  /* @__PURE__ */ jsxRuntime.jsx(
2916
2926
  SubscriptionSuccessDialog,
2917
2927
  {
@@ -2924,6 +2934,1466 @@ var SubscriptionCheckoutModal = ({
2924
2934
  )
2925
2935
  ] });
2926
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
+ };
3133
+ var Table = React3__namespace.forwardRef(
3134
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3135
+ "table",
3136
+ {
3137
+ ref,
3138
+ className: cn("w-full caption-bottom text-sm", className),
3139
+ ...props
3140
+ }
3141
+ )
3142
+ );
3143
+ Table.displayName = "Table";
3144
+ var TableHeader = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
3145
+ TableHeader.displayName = "TableHeader";
3146
+ var TableBody = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tbody", { ref, className: cn("[&_tr:last-child]:border-0", className), ...props }));
3147
+ TableBody.displayName = "TableBody";
3148
+ var TableFooter = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tfoot", { ref, className: cn("bg-muted/50 font-medium text-muted-foreground", className), ...props }));
3149
+ TableFooter.displayName = "TableFooter";
3150
+ var TableRow = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("tr", { ref, className: cn("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted", className), ...props }));
3151
+ TableRow.displayName = "TableRow";
3152
+ var TableHead = React3__namespace.forwardRef(
3153
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3154
+ "th",
3155
+ {
3156
+ ref,
3157
+ className: cn(
3158
+ "h-10 px-2 text-left align-middle text-xs font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
3159
+ className
3160
+ ),
3161
+ ...props
3162
+ }
3163
+ )
3164
+ );
3165
+ TableHead.displayName = "TableHead";
3166
+ var TableCell = React3__namespace.forwardRef(
3167
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3168
+ "td",
3169
+ {
3170
+ ref,
3171
+ className: cn("p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className),
3172
+ ...props
3173
+ }
3174
+ )
3175
+ );
3176
+ TableCell.displayName = "TableCell";
3177
+ var TableCaption = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("caption", { ref, className: cn("mt-4 text-sm text-muted-foreground", className), ...props }));
3178
+ TableCaption.displayName = "TableCaption";
3179
+ var AlertDialog = AlertDialogPrimitive__namespace.Root;
3180
+ var AlertDialogTrigger = AlertDialogPrimitive__namespace.Trigger;
3181
+ var AlertDialogPortal = AlertDialogPrimitive__namespace.Portal;
3182
+ var AlertDialogOverlay = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3183
+ AlertDialogPrimitive__namespace.Overlay,
3184
+ {
3185
+ ref,
3186
+ className: cn(
3187
+ "fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0",
3188
+ className
3189
+ ),
3190
+ ...props
3191
+ }
3192
+ ));
3193
+ AlertDialogOverlay.displayName = AlertDialogPrimitive__namespace.Overlay.displayName;
3194
+ var AlertDialogContent = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogPortal, { children: [
3195
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogOverlay, {}),
3196
+ /* @__PURE__ */ jsxRuntime.jsx(
3197
+ AlertDialogPrimitive__namespace.Content,
3198
+ {
3199
+ ref,
3200
+ className: cn(
3201
+ "fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-popover p-6 text-popover-foreground shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
3202
+ className
3203
+ ),
3204
+ ...props
3205
+ }
3206
+ )
3207
+ ] }));
3208
+ AlertDialogContent.displayName = AlertDialogPrimitive__namespace.Content.displayName;
3209
+ var AlertDialogHeader = ({
3210
+ className,
3211
+ ...props
3212
+ }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex flex-col space-y-2 text-center sm:text-left", className), ...props });
3213
+ AlertDialogHeader.displayName = "AlertDialogHeader";
3214
+ var AlertDialogFooter = ({
3215
+ className,
3216
+ ...props
3217
+ }) => /* @__PURE__ */ jsxRuntime.jsx(
3218
+ "div",
3219
+ {
3220
+ className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:gap-2", className),
3221
+ ...props
3222
+ }
3223
+ );
3224
+ AlertDialogFooter.displayName = "AlertDialogFooter";
3225
+ var AlertDialogTitle = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Title, { ref, className: cn("text-lg font-semibold", className), ...props }));
3226
+ AlertDialogTitle.displayName = AlertDialogPrimitive__namespace.Title.displayName;
3227
+ var AlertDialogDescription = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Description, { ref, className: cn("text-sm text-muted-foreground", className), ...props }));
3228
+ AlertDialogDescription.displayName = AlertDialogPrimitive__namespace.Description.displayName;
3229
+ var AlertDialogAction = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(AlertDialogPrimitive__namespace.Action, { ref, className: cn(buttonVariants(), className), ...props }));
3230
+ AlertDialogAction.displayName = AlertDialogPrimitive__namespace.Action.displayName;
3231
+ var AlertDialogCancel = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3232
+ AlertDialogPrimitive__namespace.Cancel,
3233
+ {
3234
+ ref,
3235
+ className: cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className),
3236
+ ...props
3237
+ }
3238
+ ));
3239
+ AlertDialogCancel.displayName = AlertDialogPrimitive__namespace.Cancel.displayName;
3240
+ var Textarea = React3__namespace.forwardRef(
3241
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
3242
+ "textarea",
3243
+ {
3244
+ ref,
3245
+ className: cn(
3246
+ "flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
3247
+ className
3248
+ ),
3249
+ ...props
3250
+ }
3251
+ )
3252
+ );
3253
+ Textarea.displayName = "Textarea";
3254
+ var notifyDefault = (payload) => {
3255
+ const level = payload.status === "destructive" ? "error" : "info";
3256
+ console[level === "error" ? "error" : "log"]("[payments-ui] cancellation", payload);
3257
+ };
3258
+ var CancelMembershipDialog = ({
3259
+ minReasonLength = 15,
3260
+ onCancelled,
3261
+ onNotify
3262
+ }) => {
3263
+ const { services } = usePaymentContext();
3264
+ const notify = onNotify ?? notifyDefault;
3265
+ const [cancelReason, setCancelReason] = React3.useState("");
3266
+ const [isOpen, setIsOpen] = React3.useState(false);
3267
+ const [isReasonValid, setIsReasonValid] = React3.useState(false);
3268
+ const [hasInteracted, setHasInteracted] = React3.useState(false);
3269
+ const [isSubmitting, setIsSubmitting] = React3.useState(false);
3270
+ React3.useEffect(() => {
3271
+ const trimmed = cancelReason.trim();
3272
+ setIsReasonValid(trimmed.length >= minReasonLength);
3273
+ }, [cancelReason, minReasonLength]);
3274
+ const handleOpenChange = (open) => {
3275
+ setIsOpen(open);
3276
+ if (!open) {
3277
+ setCancelReason("");
3278
+ setIsReasonValid(false);
3279
+ setHasInteracted(false);
3280
+ setIsSubmitting(false);
3281
+ }
3282
+ };
3283
+ const handleReasonChange = (e) => {
3284
+ setCancelReason(e.target.value);
3285
+ if (!hasInteracted) {
3286
+ setHasInteracted(true);
3287
+ }
3288
+ };
3289
+ const handleConfirm = async () => {
3290
+ if (!isReasonValid) {
3291
+ setHasInteracted(true);
3292
+ return;
3293
+ }
3294
+ setIsSubmitting(true);
3295
+ try {
3296
+ await services.subscriptions.cancelSubscription(cancelReason.trim());
3297
+ notify({
3298
+ title: "Membership cancelled",
3299
+ description: "Your subscription has been cancelled successfully.",
3300
+ status: "success"
3301
+ });
3302
+ onCancelled?.();
3303
+ handleOpenChange(false);
3304
+ } catch (error) {
3305
+ const message = error instanceof Error ? error.message : "Unable to cancel membership";
3306
+ notify({ title: "Cancellation failed", description: message, status: "destructive" });
3307
+ } finally {
3308
+ setIsSubmitting(false);
3309
+ }
3310
+ };
3311
+ const showError = hasInteracted && !isReasonValid;
3312
+ return /* @__PURE__ */ jsxRuntime.jsxs(AlertDialog, { open: isOpen, onOpenChange: handleOpenChange, children: [
3313
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "outline", className: "border-destructive/50 text-destructive", children: [
3314
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Ban, { className: "mr-2 h-4 w-4" }),
3315
+ " Cancel Membership"
3316
+ ] }) }),
3317
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { className: "max-h-[90vh] overflow-y-auto rounded-md border border-border bg-background", children: [
3318
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { children: [
3319
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogTitle, { className: "flex items-center gap-2 text-lg font-semibold", children: [
3320
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.TriangleAlert, { className: "h-5 w-5 text-destructive" }),
3321
+ " Confirm Membership Cancellation"
3322
+ ] }),
3323
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogDescription, { className: "mt-3 space-y-3 text-muted-foreground", children: [
3324
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "You are about to cancel your membership. Please review the consequences:" }),
3325
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "list-disc space-y-1 pl-5 text-sm", children: [
3326
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "You will immediately lose access to premium features upon confirmation." }),
3327
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Your benefits remain active until the end of the billing cycle." }),
3328
+ /* @__PURE__ */ jsxRuntime.jsx("li", { children: "Your account will revert to the free plan afterwards." })
3329
+ ] })
3330
+ ] })
3331
+ ] }),
3332
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-4 space-y-2 py-2", children: [
3333
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "cancelReason", className: "text-sm font-medium", children: "Please provide a reason for cancellation (required):" }),
3334
+ /* @__PURE__ */ jsxRuntime.jsx(
3335
+ Textarea,
3336
+ {
3337
+ id: "cancelReason",
3338
+ value: cancelReason,
3339
+ onChange: handleReasonChange,
3340
+ placeholder: "Your feedback helps us improve...",
3341
+ className: cn(
3342
+ "w-full resize-none border-border bg-background",
3343
+ showError && "border-destructive"
3344
+ ),
3345
+ rows: 4,
3346
+ "aria-describedby": "reason-hint",
3347
+ "aria-invalid": showError
3348
+ }
3349
+ ),
3350
+ /* @__PURE__ */ jsxRuntime.jsx(
3351
+ "p",
3352
+ {
3353
+ id: "reason-hint",
3354
+ className: `text-xs ${showError ? "text-destructive" : "text-muted-foreground"}`,
3355
+ children: showError ? `Reason must be at least ${minReasonLength} characters long.` : `Minimum ${minReasonLength} characters required.`
3356
+ }
3357
+ )
3358
+ ] }),
3359
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogFooter, { className: "mt-6 gap-2", children: [
3360
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", className: "border-border text-muted-foreground", children: "Keep Membership" }) }),
3361
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogAction, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3362
+ Button,
3363
+ {
3364
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
3365
+ onClick: handleConfirm,
3366
+ disabled: !isReasonValid || isSubmitting,
3367
+ children: isSubmitting ? "Cancelling..." : "Confirm Cancellation"
3368
+ }
3369
+ ) })
3370
+ ] })
3371
+ ] })
3372
+ ] });
3373
+ };
3374
+ var notifyDefault2 = (payload) => {
3375
+ const level = payload.status === "destructive" ? "error" : "info";
3376
+ console[level === "error" ? "error" : "log"]("[payments-ui] billing", payload);
3377
+ };
3378
+ var BillingHistory = ({
3379
+ pageSize = 10,
3380
+ initialPage = 1,
3381
+ enableCancel = true,
3382
+ onNotify
3383
+ }) => {
3384
+ const { services } = usePaymentContext();
3385
+ const notify = onNotify ?? notifyDefault2;
3386
+ const [isExpanded, setIsExpanded] = React3.useState(false);
3387
+ const observerRef = React3.useRef(null);
3388
+ const loadMoreRef = React3.useRef(null);
3389
+ const historyQuery = reactQuery.useInfiniteQuery({
3390
+ queryKey: ["payments-ui", "billing-history", pageSize],
3391
+ queryFn: async ({ pageParam = initialPage }) => {
3392
+ const offset = (pageParam - 1) * pageSize;
3393
+ return services.subscriptions.getPaymentHistory({ limit: pageSize, offset });
3394
+ },
3395
+ initialPageParam: initialPage,
3396
+ getNextPageParam: (lastPage) => {
3397
+ const nextOffset = (lastPage.offset ?? 0) + lastPage.data.length;
3398
+ if (lastPage.total_items <= nextOffset) {
3399
+ return void 0;
3400
+ }
3401
+ return lastPage.page ? lastPage.page + 1 : initialPage + 1;
3402
+ },
3403
+ staleTime: 5 * 60 * 1e3
3404
+ });
3405
+ React3.useEffect(() => {
3406
+ if (!loadMoreRef.current || !isExpanded) return;
3407
+ observerRef.current = new IntersectionObserver((entries) => {
3408
+ const [entry] = entries;
3409
+ if (entry?.isIntersecting && historyQuery.hasNextPage && !historyQuery.isFetchingNextPage) {
3410
+ historyQuery.fetchNextPage().catch(() => {
3411
+ notify({ title: "Failed to load more history", status: "destructive" });
3412
+ });
3413
+ }
3414
+ });
3415
+ observerRef.current.observe(loadMoreRef.current);
3416
+ return () => {
3417
+ observerRef.current?.disconnect();
3418
+ };
3419
+ }, [historyQuery, isExpanded, notify]);
3420
+ const payments = React3.useMemo(() => {
3421
+ const data = historyQuery.data;
3422
+ return data?.pages ?? [];
3423
+ }, [historyQuery.data]);
3424
+ const formatDate = (value) => new Date(value).toLocaleDateString("en-US", {
3425
+ year: "numeric",
3426
+ month: "short",
3427
+ day: "numeric"
3428
+ });
3429
+ const formatAmount = (amount, currency) => {
3430
+ try {
3431
+ return new Intl.NumberFormat("en-US", {
3432
+ style: "currency",
3433
+ currency
3434
+ }).format(amount);
3435
+ } catch {
3436
+ return `${amount.toFixed(2)} ${currency}`;
3437
+ }
3438
+ };
3439
+ return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "border-0 bg-background/5 shadow-lg", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 sm:p-6", children: [
3440
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex cursor-pointer items-center justify-between", onClick: () => setIsExpanded((prev) => !prev), children: [
3441
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3442
+ /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-xl font-semibold", children: "Transaction History" }),
3443
+ /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "Record of billing history" })
3444
+ ] }),
3445
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: cn("h-5 w-5 text-muted-foreground transition-transform", isExpanded && "rotate-180") })
3446
+ ] }),
3447
+ /* @__PURE__ */ jsxRuntime.jsx(
3448
+ "div",
3449
+ {
3450
+ className: cn(
3451
+ "overflow-hidden transition-all duration-300",
3452
+ isExpanded ? "mt-4 max-h-[1000px] opacity-100" : "max-h-0 opacity-0"
3453
+ ),
3454
+ children: /* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "p-0 pt-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
3455
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between", children: [
3456
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Review your account activity below" }),
3457
+ enableCancel && /* @__PURE__ */ jsxRuntime.jsx(CancelMembershipDialog, { onNotify: notify })
3458
+ ] }),
3459
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-[300px] overflow-y-auto rounded-lg border border-border/70", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: historyQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-4 text-center text-sm text-muted-foreground", children: "Loading..." }) : historyQuery.isError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "p-4 text-center text-sm text-destructive", children: "Error loading billing history." }) : /* @__PURE__ */ jsxRuntime.jsxs(Table, { children: [
3460
+ /* @__PURE__ */ jsxRuntime.jsx(TableHeader, { children: /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { className: "border-border/60", children: [
3461
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: "Reference" }),
3462
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: "Date" }),
3463
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: "Amount" }),
3464
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: "Processor" }),
3465
+ /* @__PURE__ */ jsxRuntime.jsx(TableHead, { children: "Status" })
3466
+ ] }) }),
3467
+ /* @__PURE__ */ jsxRuntime.jsx(TableBody, { children: payments.map(
3468
+ (page) => page.data.map((payment) => /* @__PURE__ */ jsxRuntime.jsxs(TableRow, { className: "border-border/40", children: [
3469
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "font-mono text-sm", children: payment.id.slice(0, 7).toUpperCase() }),
3470
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: formatDate(payment.purchased_at) }),
3471
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: formatAmount(payment.amount, payment.currency) }),
3472
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { className: "capitalize", children: payment.processor }),
3473
+ /* @__PURE__ */ jsxRuntime.jsx(TableCell, { children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { className: "bg-emerald-500/10 text-emerald-400", children: (payment.status || "completed").toLowerCase() }) })
3474
+ ] }, payment.id))
3475
+ ) })
3476
+ ] }) }) }),
3477
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: loadMoreRef, className: "h-10 w-full", children: historyQuery.isFetchingNextPage && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-center text-sm text-muted-foreground", children: "Loading more..." }) })
3478
+ ] }) })
3479
+ }
3480
+ )
3481
+ ] }) });
3482
+ };
3483
+ var formatCardLabel2 = (method) => {
3484
+ const brand = method.card_type ? method.card_type.toUpperCase() : "CARD";
3485
+ const lastFour = method.last_four ? `\u2022\u2022\u2022\u2022 ${method.last_four}` : "";
3486
+ return `${brand} ${lastFour}`.trim();
3487
+ };
3488
+ var notifyDefault3 = (payload) => {
3489
+ const level = payload.status === "destructive" ? "error" : "info";
3490
+ console[level === "error" ? "error" : "log"]("[payments-ui] notification", payload);
3491
+ };
3492
+ var PaymentMethodsSection = ({
3493
+ isAuthenticated = true,
3494
+ userEmail,
3495
+ provider = "mobius",
3496
+ defaultCountry = "US",
3497
+ collectPrefix = "account-card",
3498
+ onNotify
3499
+ }) => {
3500
+ const paymentMethods = usePaymentMethodService();
3501
+ const queryClient = reactQuery.useQueryClient();
3502
+ const [isModalOpen, setIsModalOpen] = React3.useState(false);
3503
+ const [deletingId, setDeletingId] = React3.useState(null);
3504
+ const notify = onNotify ?? notifyDefault3;
3505
+ const queryKey = ["payments-ui", "payment-methods"];
3506
+ const paymentQuery = reactQuery.useQuery({
3507
+ queryKey,
3508
+ queryFn: () => paymentMethods.list({ pageSize: 50 }),
3509
+ enabled: isAuthenticated,
3510
+ staleTime: 3e4
3511
+ });
3512
+ const createMutation = reactQuery.useMutation({
3513
+ mutationFn: (payload) => paymentMethods.create(payload),
3514
+ onSuccess: () => {
3515
+ notify({ title: "Card added successfully", status: "success" });
3516
+ setIsModalOpen(false);
3517
+ void queryClient.invalidateQueries({ queryKey });
3518
+ },
3519
+ onError: (error) => {
3520
+ notify({
3521
+ title: "Unable to add card",
3522
+ description: error.message,
3523
+ status: "destructive"
3524
+ });
3525
+ }
3526
+ });
3527
+ const deleteMutation = reactQuery.useMutation({
3528
+ mutationFn: (id) => paymentMethods.remove(id),
3529
+ onMutate: (id) => setDeletingId(id),
3530
+ onSuccess: () => {
3531
+ notify({ title: "Card removed", status: "success" });
3532
+ void queryClient.invalidateQueries({ queryKey });
3533
+ },
3534
+ onError: (error) => {
3535
+ notify({
3536
+ title: "Unable to remove card",
3537
+ description: error.message,
3538
+ status: "destructive"
3539
+ });
3540
+ },
3541
+ onSettled: () => setDeletingId(null)
3542
+ });
3543
+ React3.useEffect(() => {
3544
+ if (!isModalOpen) {
3545
+ createMutation.reset();
3546
+ }
3547
+ }, [createMutation, isModalOpen]);
3548
+ const payments = React3.useMemo(() => paymentQuery.data?.data ?? [], [paymentQuery.data]);
3549
+ const loading = paymentQuery.isLoading || paymentQuery.isFetching;
3550
+ const handleCardTokenize = (token, billing) => {
3551
+ const payload = {
3552
+ payment_token: token,
3553
+ first_name: billing.firstName,
3554
+ last_name: billing.lastName,
3555
+ address1: billing.address1,
3556
+ address2: billing.address2,
3557
+ city: billing.city,
3558
+ state: billing.stateRegion,
3559
+ zip: billing.postalCode,
3560
+ country: billing.country,
3561
+ email: billing.email,
3562
+ provider: billing.provider
3563
+ };
3564
+ createMutation.mutate(payload);
3565
+ };
3566
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-background/5 shadow-lg", children: [
3567
+ /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { className: "flex flex-col gap-4 md:flex-row md:items-center md:justify-between", children: [
3568
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3569
+ /* @__PURE__ */ jsxRuntime.jsxs(CardTitle, { className: "flex items-center gap-2 text-xl", children: [
3570
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.WalletCards, { className: "h-5 w-5 text-primary" }),
3571
+ " Payment Methods"
3572
+ ] }),
3573
+ /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "Manage your saved billing cards" })
3574
+ ] }),
3575
+ /* @__PURE__ */ jsxRuntime.jsxs(Button, { onClick: () => setIsModalOpen(true), children: [
3576
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "mr-2 h-4 w-4" }),
3577
+ " Add card"
3578
+ ] })
3579
+ ] }),
3580
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "space-y-4", children: loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-10 text-muted-foreground", children: [
3581
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-5 w-5 animate-spin" }),
3582
+ " Loading cards..."
3583
+ ] }) : payments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-dashed border-border/60 bg-muted/10 p-6 text-sm text-muted-foreground", children: "No saved payment methods yet." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: payments.map((method) => /* @__PURE__ */ jsxRuntime.jsxs(
3584
+ "div",
3585
+ {
3586
+ className: "rounded-lg border border-border/80 bg-background/40 p-4 shadow-sm",
3587
+ children: [
3588
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 md:flex-row md:items-center md:justify-between", children: [
3589
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3590
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-base font-medium text-foreground", children: formatCardLabel2(method) }),
3591
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: [
3592
+ "Added on",
3593
+ " ",
3594
+ method.created_at ? new Date(method.created_at).toLocaleDateString() : "unknown date"
3595
+ ] })
3596
+ ] }),
3597
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
3598
+ /* @__PURE__ */ jsxRuntime.jsx(
3599
+ Badge,
3600
+ {
3601
+ variant: method.is_active ? "default" : "secondary",
3602
+ className: method.is_active ? "bg-emerald-500/20 text-emerald-400" : "",
3603
+ children: method.is_active ? "Active" : "Inactive"
3604
+ }
3605
+ ),
3606
+ method.failure_reason && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "destructive", children: method.failure_reason })
3607
+ ] })
3608
+ ] }),
3609
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
3610
+ Button,
3611
+ {
3612
+ variant: "ghost",
3613
+ className: "text-destructive hover:text-destructive",
3614
+ disabled: deletingId === method.id && deleteMutation.isPending,
3615
+ onClick: () => deleteMutation.mutate(method.id),
3616
+ children: [
3617
+ deletingId === method.id && deleteMutation.isPending ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "mr-2 h-4 w-4" }),
3618
+ "Remove"
3619
+ ]
3620
+ }
3621
+ ) })
3622
+ ]
3623
+ },
3624
+ method.id
3625
+ )) }) }),
3626
+ /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: isModalOpen, onOpenChange: setIsModalOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "max-h-[95vh] overflow-y-auto border border-border bg-background", children: [
3627
+ /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
3628
+ /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: "Add a new card" }),
3629
+ /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: "Your card details are tokenized securely via our payment provider." })
3630
+ ] }),
3631
+ /* @__PURE__ */ jsxRuntime.jsx(
3632
+ CardDetailsForm,
3633
+ {
3634
+ visible: isModalOpen,
3635
+ collectPrefix,
3636
+ submitting: createMutation.isPending,
3637
+ submitLabel: "Save card",
3638
+ defaultValues: {
3639
+ email: userEmail ?? "",
3640
+ country: defaultCountry,
3641
+ provider
3642
+ },
3643
+ externalError: createMutation.error?.message ?? null,
3644
+ onTokenize: handleCardTokenize,
3645
+ className: "rounded-2xl border border-border bg-muted/20 p-6"
3646
+ }
3647
+ )
3648
+ ] }) })
3649
+ ] });
3650
+ };
3651
+ var useWalletList = (options = {}) => {
3652
+ const { services } = usePaymentContext();
3653
+ const [state, setState] = React3.useState({
3654
+ wallets: [],
3655
+ isLoading: false,
3656
+ error: null
3657
+ });
3658
+ const fetchWallets = React3.useCallback(async () => {
3659
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
3660
+ try {
3661
+ const wallets2 = await services.solanaWallets.list();
3662
+ setState({ wallets: wallets2, isLoading: false, error: null });
3663
+ return wallets2;
3664
+ } catch (error) {
3665
+ const message = error instanceof Error ? error.message : "Failed to load wallets";
3666
+ console.error("payments-ui: wallet list fetch failed", error);
3667
+ setState((prev) => ({ ...prev, isLoading: false, error: message }));
3668
+ throw error;
3669
+ }
3670
+ }, [services.solanaWallets]);
3671
+ const deleteWallet = React3.useCallback(
3672
+ async (walletIdOrAddress) => {
3673
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
3674
+ try {
3675
+ await services.solanaWallets.remove(walletIdOrAddress);
3676
+ setState((prev) => ({
3677
+ ...prev,
3678
+ wallets: prev.wallets.filter(
3679
+ (wallet) => wallet.id !== walletIdOrAddress && wallet.address !== walletIdOrAddress
3680
+ ),
3681
+ isLoading: false
3682
+ }));
3683
+ } catch (error) {
3684
+ const message = error instanceof Error ? error.message : "Failed to remove wallet";
3685
+ console.error("payments-ui: wallet removal failed", error);
3686
+ setState((prev) => ({ ...prev, isLoading: false, error: message }));
3687
+ throw error;
3688
+ }
3689
+ },
3690
+ [services.solanaWallets]
3691
+ );
3692
+ const addWallet = React3.useCallback((wallet) => {
3693
+ setState((prev) => ({ ...prev, wallets: [...prev.wallets, wallet] }));
3694
+ }, []);
3695
+ const updateWallet = React3.useCallback((walletId, updates) => {
3696
+ setState((prev) => ({
3697
+ ...prev,
3698
+ wallets: prev.wallets.map(
3699
+ (wallet) => wallet.id === walletId ? { ...wallet, ...updates } : wallet
3700
+ )
3701
+ }));
3702
+ }, []);
3703
+ const clearError = React3.useCallback(() => {
3704
+ setState((prev) => ({ ...prev, error: null }));
3705
+ }, []);
3706
+ const findWalletByAddress = React3.useCallback(
3707
+ (address) => state.wallets.find((wallet) => wallet.address === address),
3708
+ [state.wallets]
3709
+ );
3710
+ const getVerifiedWallets = React3.useCallback(
3711
+ () => state.wallets.filter((wallet) => wallet.is_verified),
3712
+ [state.wallets]
3713
+ );
3714
+ React3.useEffect(() => {
3715
+ if (options.autoFetch !== false) {
3716
+ fetchWallets().catch(() => {
3717
+ });
3718
+ }
3719
+ }, [fetchWallets, options.autoFetch]);
3720
+ return {
3721
+ wallets: state.wallets,
3722
+ isLoading: state.isLoading,
3723
+ error: state.error,
3724
+ fetchWallets,
3725
+ deleteWallet,
3726
+ addWallet,
3727
+ updateWallet,
3728
+ clearError,
3729
+ findWalletByAddress,
3730
+ getVerifiedWallets,
3731
+ hasVerifiedWallets: state.wallets.some((w) => w.is_verified),
3732
+ totalWallets: state.wallets.length
3733
+ };
3734
+ };
3735
+ var useWalletVerification = () => {
3736
+ const { services } = usePaymentContext();
3737
+ const { publicKey, signMessage } = walletAdapterReact.useWallet();
3738
+ const [state, setState] = React3.useState({
3739
+ isVerifying: false,
3740
+ isVerified: false,
3741
+ error: null
3742
+ });
3743
+ const signAndVerifyWallet = React3.useCallback(
3744
+ async (walletAddress, message, nonce) => {
3745
+ if (!publicKey || !signMessage) {
3746
+ throw new Error("Wallet not connected or signing unavailable");
3747
+ }
3748
+ if (publicKey.toBase58() !== walletAddress) {
3749
+ throw new Error("Connected wallet does not match target wallet");
3750
+ }
3751
+ setState((prev) => ({ ...prev, isVerifying: true, error: null }));
3752
+ try {
3753
+ const encodedMessage = new TextEncoder().encode(message);
3754
+ const signature = await signMessage(encodedMessage);
3755
+ const signatureBase58 = bs58__default.default.encode(signature);
3756
+ const response = await services.solanaWallets.verify(
3757
+ walletAddress,
3758
+ signatureBase58,
3759
+ nonce
3760
+ );
3761
+ setState({ isVerifying: false, isVerified: response.verified, error: null });
3762
+ return response;
3763
+ } catch (error) {
3764
+ const message2 = error instanceof Error ? error.message : "Wallet verification failed";
3765
+ console.error("payments-ui: wallet verification failed", error);
3766
+ setState({ isVerifying: false, isVerified: false, error: message2 });
3767
+ throw error;
3768
+ }
3769
+ },
3770
+ [publicKey, signMessage, services.solanaWallets]
3771
+ );
3772
+ const clearError = React3.useCallback(() => {
3773
+ setState((prev) => ({ ...prev, error: null }));
3774
+ }, []);
3775
+ const resetVerification = React3.useCallback(() => {
3776
+ setState({ isVerifying: false, isVerified: false, error: null });
3777
+ }, []);
3778
+ const autoVerifyWallet = React3.useCallback(
3779
+ async (walletAddress, message, nonce) => {
3780
+ try {
3781
+ return await signAndVerifyWallet(walletAddress, message, nonce);
3782
+ } catch (error) {
3783
+ console.warn("payments-ui: auto-verification skipped", error);
3784
+ return null;
3785
+ }
3786
+ },
3787
+ [signAndVerifyWallet]
3788
+ );
3789
+ return {
3790
+ ...state,
3791
+ signAndVerifyWallet,
3792
+ autoVerifyWallet,
3793
+ clearError,
3794
+ resetVerification
3795
+ };
3796
+ };
3797
+ var useWalletConnection = () => {
3798
+ const { services } = usePaymentContext();
3799
+ const { publicKey, connected, connecting, disconnect, wallet } = walletAdapterReact.useWallet();
3800
+ const [state, setState] = React3.useState({
3801
+ isConnected: false,
3802
+ isConnecting: false,
3803
+ publicKey: null,
3804
+ wallets: [],
3805
+ isLoading: false,
3806
+ error: null
3807
+ });
3808
+ React3.useEffect(() => {
3809
+ setState((prev) => ({
3810
+ ...prev,
3811
+ isConnected: connected,
3812
+ isConnecting: connecting,
3813
+ publicKey: publicKey?.toBase58() ?? null
3814
+ }));
3815
+ }, [connected, connecting, publicKey]);
3816
+ const connectWalletToBackend = React3.useCallback(
3817
+ async (address) => {
3818
+ if (!address) {
3819
+ throw new Error("Wallet address is required");
3820
+ }
3821
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
3822
+ try {
3823
+ const challenge = await services.solanaWallets.requestChallenge(address);
3824
+ setState((prev) => ({ ...prev, isLoading: false }));
3825
+ return challenge;
3826
+ } catch (error) {
3827
+ const message = error instanceof Error ? error.message : "Wallet challenge failed";
3828
+ console.error("payments-ui: wallet challenge failed", error);
3829
+ setState((prev) => ({ ...prev, isLoading: false, error: message }));
3830
+ throw error;
3831
+ }
3832
+ },
3833
+ [services.solanaWallets]
3834
+ );
3835
+ const connectWallet = React3.useCallback(async () => {
3836
+ if (!wallet) {
3837
+ throw new Error("No wallet adapter selected");
3838
+ }
3839
+ setState((prev) => ({ ...prev, isConnecting: true, error: null }));
3840
+ try {
3841
+ await wallet.adapter.connect();
3842
+ if (publicKey) {
3843
+ await connectWalletToBackend(publicKey.toBase58());
3844
+ }
3845
+ } catch (error) {
3846
+ const message = error instanceof Error ? error.message : "Failed to connect wallet";
3847
+ console.error("payments-ui: wallet connection failed", error);
3848
+ setState((prev) => ({ ...prev, isConnecting: false, error: message }));
3849
+ throw error;
3850
+ } finally {
3851
+ setState((prev) => ({ ...prev, isConnecting: false }));
3852
+ }
3853
+ }, [wallet, publicKey, connectWalletToBackend]);
3854
+ const disconnectWallet = React3.useCallback(async () => {
3855
+ try {
3856
+ await disconnect();
3857
+ setState((prev) => ({
3858
+ ...prev,
3859
+ isConnected: false,
3860
+ publicKey: null,
3861
+ wallets: [],
3862
+ error: null
3863
+ }));
3864
+ } catch (error) {
3865
+ const message = error instanceof Error ? error.message : "Failed to disconnect wallet";
3866
+ console.error("payments-ui: wallet disconnect failed", error);
3867
+ setState((prev) => ({ ...prev, error: message }));
3868
+ throw error;
3869
+ }
3870
+ }, [disconnect]);
3871
+ const clearError = React3.useCallback(() => {
3872
+ setState((prev) => ({ ...prev, error: null }));
3873
+ }, []);
3874
+ return {
3875
+ ...state,
3876
+ walletName: wallet?.adapter.name,
3877
+ walletIcon: wallet?.adapter.icon,
3878
+ connectWallet,
3879
+ disconnectWallet,
3880
+ connectWalletToBackend,
3881
+ clearError
3882
+ };
3883
+ };
3884
+ var notifyDefault4 = (payload) => {
3885
+ console.log("[payments-ui] wallet-card", payload);
3886
+ };
3887
+ var WalletCard = ({
3888
+ wallet,
3889
+ isPrimary = false,
3890
+ isConnected = false,
3891
+ balance,
3892
+ onSetPrimary,
3893
+ onVerify,
3894
+ onDelete,
3895
+ isVerifying = false,
3896
+ isDeleting = false,
3897
+ notify = notifyDefault4
3898
+ }) => {
3899
+ const [isCopying, setIsCopying] = React3.useState(false);
3900
+ const formatAddress = (address) => address.length <= 12 ? address : `${address.slice(0, 4)}...${address.slice(-4)}`;
3901
+ const copyToClipboard = async (text) => {
3902
+ setIsCopying(true);
3903
+ try {
3904
+ await navigator.clipboard.writeText(text);
3905
+ notify({ title: "Copied", description: "Wallet address copied to clipboard" });
3906
+ } catch (error) {
3907
+ notify({ title: "Failed to copy", description: error.message, status: "destructive" });
3908
+ } finally {
3909
+ setTimeout(() => setIsCopying(false), 500);
3910
+ }
3911
+ };
3912
+ const openExplorer = () => {
3913
+ window.open(`https://solscan.io/account/${wallet.address}`, "_blank", "noopener,noreferrer");
3914
+ };
3915
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3916
+ "div",
3917
+ {
3918
+ className: cn(
3919
+ "rounded-lg border bg-background/40 p-4 transition-shadow",
3920
+ isPrimary && "border-primary/50 shadow-lg",
3921
+ isConnected && "ring-1 ring-primary"
3922
+ ),
3923
+ children: [
3924
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
3925
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
3926
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-primary/20", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-5 w-5 rounded-full bg-gradient-to-br from-primary to-primary/60" }) }),
3927
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
3928
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3929
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-sm font-medium", children: formatAddress(wallet.address) }),
3930
+ isPrimary && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 rounded-full bg-yellow-500/20 px-2 py-0.5 text-xs text-yellow-500", children: [
3931
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Star, { className: "h-3 w-3 fill-yellow-500 text-yellow-500" }),
3932
+ " Primary"
3933
+ ] }),
3934
+ wallet.is_verified ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-xs text-emerald-400", children: [
3935
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-3.5 w-3.5" }),
3936
+ " Verified"
3937
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-xs text-amber-400", children: [
3938
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-3.5 w-3.5" }),
3939
+ " Unverified"
3940
+ ] }),
3941
+ isConnected && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-blue-500/20 px-2 py-0.5 text-xs text-blue-400", children: "Connected" })
3942
+ ] }),
3943
+ balance !== null && typeof balance !== "undefined" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-1 text-sm text-muted-foreground", children: [
3944
+ "Balance: ",
3945
+ balance.toFixed(4),
3946
+ " SOL"
3947
+ ] }),
3948
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
3949
+ "Added ",
3950
+ new Date(wallet.created_at).toLocaleDateString()
3951
+ ] })
3952
+ ] })
3953
+ ] }) }),
3954
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
3955
+ /* @__PURE__ */ jsxRuntime.jsx(
3956
+ Button,
3957
+ {
3958
+ variant: "ghost",
3959
+ size: "icon",
3960
+ className: "h-8 w-8",
3961
+ onClick: () => copyToClipboard(wallet.address),
3962
+ disabled: isCopying,
3963
+ children: isCopying ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "h-4 w-4" })
3964
+ }
3965
+ ),
3966
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8", onClick: openExplorer, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "h-4 w-4" }) })
3967
+ ] })
3968
+ ] }),
3969
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [
3970
+ !isPrimary && onSetPrimary && wallet.is_verified && /* @__PURE__ */ jsxRuntime.jsxs(
3971
+ Button,
3972
+ {
3973
+ variant: "outline",
3974
+ size: "sm",
3975
+ className: "border-primary/40 text-primary",
3976
+ onClick: () => onSetPrimary(wallet.id),
3977
+ children: [
3978
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Star, { className: "mr-1 h-3 w-3" }),
3979
+ " Set Primary"
3980
+ ]
3981
+ }
3982
+ ),
3983
+ !wallet.is_verified && onVerify && isConnected && /* @__PURE__ */ jsxRuntime.jsx(
3984
+ Button,
3985
+ {
3986
+ variant: "outline",
3987
+ size: "sm",
3988
+ className: "border-emerald-500/40 text-emerald-400",
3989
+ onClick: () => onVerify(wallet),
3990
+ disabled: isVerifying,
3991
+ children: isVerifying ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3992
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-1 h-3 w-3 animate-spin" }),
3993
+ " Verifying..."
3994
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3995
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shield, { className: "mr-1 h-3 w-3" }),
3996
+ " Verify"
3997
+ ] })
3998
+ }
3999
+ ),
4000
+ onDelete && /* @__PURE__ */ jsxRuntime.jsx(
4001
+ Button,
4002
+ {
4003
+ variant: "outline",
4004
+ size: "sm",
4005
+ className: "ml-auto border-destructive/40 text-destructive",
4006
+ onClick: () => onDelete(wallet.id),
4007
+ disabled: isDeleting,
4008
+ children: isDeleting ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-3 w-3" })
4009
+ }
4010
+ )
4011
+ ] })
4012
+ ]
4013
+ }
4014
+ );
4015
+ };
4016
+ var EmptyWalletState = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
4017
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Wallet, { className: "mb-4 h-12 w-12 text-muted-foreground" }),
4018
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-2 text-lg font-medium", children: "No wallets connected" }),
4019
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-6 text-sm text-muted-foreground", children: "Connect your Solana wallet to get started" }),
4020
+ /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletMultiButton, { className: "!bg-primary text-primary-foreground hover:!bg-primary/90" })
4021
+ ] });
4022
+ var notifyDefault5 = (payload) => {
4023
+ console.log("[payments-ui] solana-wallets", payload);
4024
+ };
4025
+ var SolanaWalletSection = ({
4026
+ onNotify,
4027
+ rpcUrl
4028
+ }) => {
4029
+ const notify = onNotify ?? notifyDefault5;
4030
+ const { config } = usePaymentContext();
4031
+ const { connected, publicKey, disconnect } = walletAdapterReact.useWallet();
4032
+ const { wallets: wallets2, isLoading, deleteWallet, fetchWallets } = useWalletList();
4033
+ const { signAndVerifyWallet } = useWalletVerification();
4034
+ const walletConnection = useWalletConnection();
4035
+ const [primaryWalletId, setPrimaryWalletId] = React3.useState(null);
4036
+ const [showOtherWallets, setShowOtherWallets] = React3.useState(false);
4037
+ const [balances, setBalances] = React3.useState({});
4038
+ const [verifyingWalletId, setVerifyingWalletId] = React3.useState(null);
4039
+ const [deletingWalletId, setDeletingWalletId] = React3.useState(null);
4040
+ const [walletToDelete, setWalletToDelete] = React3.useState(null);
4041
+ const [isRegistering, setIsRegistering] = React3.useState(false);
4042
+ const rpcEndpoint = rpcUrl || config.solanaRpcUrl || "https://api.mainnet-beta.solana.com";
4043
+ const connection = React3.useMemo(() => new web3_js.Connection(rpcEndpoint), [rpcEndpoint]);
4044
+ const primaryWallet = wallets2.find((w) => w.id === primaryWalletId) ?? wallets2.find((w) => w.is_verified) ?? null;
4045
+ const otherWallets = wallets2.filter((w) => w.id !== primaryWallet?.id);
4046
+ const fetchBalance = React3.useCallback(
4047
+ async (address) => {
4048
+ try {
4049
+ const pubkey = new web3_js.PublicKey(address);
4050
+ const balance = await connection.getBalance(pubkey);
4051
+ return balance / web3_js.LAMPORTS_PER_SOL;
4052
+ } catch (error) {
4053
+ console.error("payments-ui: failed to fetch balance", error);
4054
+ return null;
4055
+ }
4056
+ },
4057
+ [connection]
4058
+ );
4059
+ const fetchAllBalances = React3.useCallback(async () => {
4060
+ const results = await Promise.all(
4061
+ wallets2.map(async (wallet) => ({ address: wallet.address, balance: await fetchBalance(wallet.address) }))
4062
+ );
4063
+ const next = {};
4064
+ results.forEach(({ address, balance }) => {
4065
+ if (balance !== null && typeof balance !== "undefined") {
4066
+ next[address] = balance;
4067
+ }
4068
+ });
4069
+ setBalances(next);
4070
+ }, [wallets2, fetchBalance]);
4071
+ React3.useEffect(() => {
4072
+ if (wallets2.length > 0) {
4073
+ fetchAllBalances().catch(() => void 0);
4074
+ }
4075
+ }, [wallets2, fetchAllBalances]);
4076
+ React3.useEffect(() => {
4077
+ const verifiedWallet = wallets2.find((w) => w.is_verified);
4078
+ if (verifiedWallet && !primaryWalletId) {
4079
+ setPrimaryWalletId(verifiedWallet.id);
4080
+ }
4081
+ }, [wallets2, primaryWalletId]);
4082
+ const registerWallet = React3.useCallback(async () => {
4083
+ if (!connected || !publicKey || isRegistering) return;
4084
+ setIsRegistering(true);
4085
+ try {
4086
+ const challenge = await walletConnection.connectWalletToBackend(publicKey.toBase58());
4087
+ if (!challenge?.message) {
4088
+ throw new Error("Failed to retrieve wallet verification challenge");
4089
+ }
4090
+ await signAndVerifyWallet(challenge.wallet, challenge.message, challenge.nonce);
4091
+ await fetchWallets();
4092
+ notify({
4093
+ title: "Wallet verified",
4094
+ description: "Your wallet has been linked successfully.",
4095
+ status: "success"
4096
+ });
4097
+ } catch (error) {
4098
+ notify({
4099
+ title: "Wallet verification failed",
4100
+ description: error instanceof Error ? error.message : "Failed to verify wallet",
4101
+ status: "destructive"
4102
+ });
4103
+ } finally {
4104
+ setIsRegistering(false);
4105
+ }
4106
+ }, [connected, publicKey, isRegistering, walletConnection, signAndVerifyWallet, fetchWallets, notify]);
4107
+ React3.useEffect(() => {
4108
+ if (connected && publicKey && !walletConnection.isConnecting && wallets2.length === 0) {
4109
+ registerWallet().catch(() => void 0);
4110
+ }
4111
+ }, [connected, publicKey, walletConnection.isConnecting, wallets2.length, registerWallet]);
4112
+ const handleVerifyWallet = React3.useCallback(
4113
+ async (wallet) => {
4114
+ if (!connected || publicKey?.toBase58() !== wallet.address) {
4115
+ notify({
4116
+ title: "Connect wallet first",
4117
+ description: "Please connect the wallet you want to verify.",
4118
+ status: "destructive"
4119
+ });
4120
+ return;
4121
+ }
4122
+ setVerifyingWalletId(wallet.id);
4123
+ try {
4124
+ const challenge = await walletConnection.connectWalletToBackend(wallet.address);
4125
+ if (!challenge?.message) {
4126
+ throw new Error("Failed to retrieve verification challenge");
4127
+ }
4128
+ await signAndVerifyWallet(challenge.wallet, challenge.message, challenge.nonce);
4129
+ await fetchWallets();
4130
+ notify({ title: "Wallet verified", status: "success" });
4131
+ } catch (error) {
4132
+ notify({
4133
+ title: "Verification failed",
4134
+ description: error instanceof Error ? error.message : "Failed to verify wallet",
4135
+ status: "destructive"
4136
+ });
4137
+ } finally {
4138
+ setVerifyingWalletId(null);
4139
+ }
4140
+ },
4141
+ [connected, publicKey, walletConnection, signAndVerifyWallet, fetchWallets, notify]
4142
+ );
4143
+ const handleDeleteWallet = React3.useCallback(
4144
+ async (walletId) => {
4145
+ setDeletingWalletId(walletId);
4146
+ try {
4147
+ await deleteWallet(walletId);
4148
+ if (primaryWalletId === walletId) {
4149
+ setPrimaryWalletId(null);
4150
+ }
4151
+ if (connected && publicKey) {
4152
+ const deletedWallet = wallets2.find((w) => w.id === walletId);
4153
+ if (deletedWallet?.address === publicKey.toBase58()) {
4154
+ await disconnect();
4155
+ }
4156
+ }
4157
+ notify({ title: "Wallet removed", status: "success" });
4158
+ } catch (error) {
4159
+ notify({
4160
+ title: "Failed to remove wallet",
4161
+ description: error instanceof Error ? error.message : "Please try again",
4162
+ status: "destructive"
4163
+ });
4164
+ } finally {
4165
+ setDeletingWalletId(null);
4166
+ setWalletToDelete(null);
4167
+ }
4168
+ },
4169
+ [deleteWallet, primaryWalletId, connected, publicKey, wallets2, disconnect, notify]
4170
+ );
4171
+ const handleSetPrimary = (walletId) => {
4172
+ setPrimaryWalletId(walletId);
4173
+ notify({ title: "Primary wallet updated", status: "success" });
4174
+ };
4175
+ const isWalletRegistered = connected && publicKey && wallets2.some((w) => w.address === publicKey.toBase58());
4176
+ if (isLoading && wallets2.length === 0) {
4177
+ return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-background/5", children: [
4178
+ /* @__PURE__ */ jsxRuntime.jsx(CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-xl", children: "Solana Wallets" }) }),
4179
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center py-8", children: [
4180
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-6 w-6 animate-spin text-muted-foreground" }),
4181
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Loading wallets..." })
4182
+ ] }) })
4183
+ ] });
4184
+ }
4185
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4186
+ /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: "border-0 bg-background/5", children: [
4187
+ /* @__PURE__ */ jsxRuntime.jsxs(CardHeader, { children: [
4188
+ /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-xl", children: "Solana Wallets" }),
4189
+ /* @__PURE__ */ jsxRuntime.jsx(CardDescription, { children: "Connect and manage your Solana wallets for payments" })
4190
+ ] }),
4191
+ /* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "space-y-4", children: wallets2.length === 0 && !connected ? /* @__PURE__ */ jsxRuntime.jsx(EmptyWalletState, {}) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4192
+ primaryWallet && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4193
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-3 text-sm font-medium uppercase tracking-wide text-muted-foreground", children: "Primary Wallet" }),
4194
+ /* @__PURE__ */ jsxRuntime.jsx(
4195
+ WalletCard,
4196
+ {
4197
+ wallet: primaryWallet,
4198
+ isPrimary: true,
4199
+ isConnected: connected && publicKey?.toBase58() === primaryWallet.address,
4200
+ balance: balances[primaryWallet.address],
4201
+ onVerify: handleVerifyWallet,
4202
+ onDelete: (id) => {
4203
+ const target = wallets2.find((w) => w.id === id);
4204
+ if (target) setWalletToDelete(target);
4205
+ },
4206
+ isVerifying: verifyingWalletId === primaryWallet.id,
4207
+ isDeleting: deletingWalletId === primaryWallet.id,
4208
+ notify
4209
+ }
4210
+ )
4211
+ ] }),
4212
+ otherWallets.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4213
+ /* @__PURE__ */ jsxRuntime.jsxs(
4214
+ "button",
4215
+ {
4216
+ className: "mb-3 flex w-full items-center justify-between text-left",
4217
+ onClick: () => setShowOtherWallets((prev) => !prev),
4218
+ children: [
4219
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-sm font-medium uppercase tracking-wide text-muted-foreground", children: [
4220
+ "Other Wallets (",
4221
+ otherWallets.length,
4222
+ ")"
4223
+ ] }),
4224
+ showOtherWallets ? /* @__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" })
4225
+ ]
4226
+ }
4227
+ ),
4228
+ showOtherWallets && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: otherWallets.map((wallet) => /* @__PURE__ */ jsxRuntime.jsx(
4229
+ WalletCard,
4230
+ {
4231
+ wallet,
4232
+ isConnected: connected && publicKey?.toBase58() === wallet.address,
4233
+ balance: balances[wallet.address],
4234
+ onSetPrimary: handleSetPrimary,
4235
+ onVerify: handleVerifyWallet,
4236
+ onDelete: (id) => {
4237
+ const target = wallets2.find((w) => w.id === id);
4238
+ if (target) setWalletToDelete(target);
4239
+ },
4240
+ isVerifying: verifyingWalletId === wallet.id,
4241
+ isDeleting: deletingWalletId === wallet.id,
4242
+ notify
4243
+ },
4244
+ wallet.id
4245
+ )) })
4246
+ ] }),
4247
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-4", children: connected && publicKey ? isWalletRegistered ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
4248
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-emerald-500/40 bg-emerald-500/10 p-3 text-sm text-emerald-200", children: [
4249
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle, { className: "h-4 w-4" }),
4250
+ " Connected wallet is verified and linked to your account."
4251
+ ] }),
4252
+ /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletMultiButton, { className: "w-full !bg-primary text-primary-foreground" })
4253
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
4254
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-amber-500/40 bg-amber-500/10 p-3 text-sm text-amber-200", children: "Your connected wallet is not registered with your account." }),
4255
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
4256
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: registerWallet, disabled: isRegistering || walletConnection.isConnecting, className: "flex-1 bg-primary text-primary-foreground", children: isRegistering ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4257
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
4258
+ " Registering..."
4259
+ ] }) : "Register This Wallet" }),
4260
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => disconnect(), variant: "outline", className: "border-border", children: "Disconnect" })
4261
+ ] })
4262
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(walletAdapterReactUi.WalletMultiButton, { className: "w-full !bg-primary text-primary-foreground" }) })
4263
+ ] }) })
4264
+ ] }),
4265
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialog, { open: !!walletToDelete, onOpenChange: () => setWalletToDelete(null), children: /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogContent, { children: [
4266
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { children: [
4267
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogTitle, { children: "Remove Wallet" }),
4268
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogDescription, { children: "Are you sure you want to remove this wallet from your account? This action cannot be undone." })
4269
+ ] }),
4270
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogFooter, { children: [
4271
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { children: "Cancel" }),
4272
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogAction, { onClick: () => walletToDelete && handleDeleteWallet(walletToDelete.id), className: "bg-destructive text-destructive-foreground", children: "Remove" })
4273
+ ] })
4274
+ ] }) })
4275
+ ] });
4276
+ };
4277
+ var WalletManagement = (props) => /* @__PURE__ */ jsxRuntime.jsx(SolanaWalletSection, { ...props });
4278
+ var Checkbox = React3__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
4279
+ CheckboxPrimitive__namespace.Root,
4280
+ {
4281
+ ref,
4282
+ className: cn(
4283
+ "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
4284
+ className
4285
+ ),
4286
+ ...props,
4287
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4288
+ CheckboxPrimitive__namespace.Indicator,
4289
+ {
4290
+ className: cn("flex items-center justify-center text-current"),
4291
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3" })
4292
+ }
4293
+ )
4294
+ }
4295
+ ));
4296
+ Checkbox.displayName = CheckboxPrimitive__namespace.Root.displayName;
4297
+ var initialState = {
4298
+ nameOnCard: "",
4299
+ cardNumber: "",
4300
+ expiration: "",
4301
+ cvv: "",
4302
+ termsAccepted: false
4303
+ };
4304
+ var WalletDialog = ({ open, onOpenChange }) => {
4305
+ const [form, setForm] = React3.useState(initialState);
4306
+ const [errors, setErrors] = React3.useState({});
4307
+ const validators = React3.useMemo(
4308
+ () => ({
4309
+ nameOnCard: (value) => !value ? "Name is required" : void 0,
4310
+ cardNumber: (value) => /^\d{16}$/.test(value) ? void 0 : "Card number must be 16 digits",
4311
+ expiration: (value) => /^(0[1-9]|1[0-2])\/([2-9]\d)$/.test(value) ? void 0 : "Must be in MM/YY format",
4312
+ cvv: (value) => /^\d{3,4}$/.test(value) ? void 0 : "CVV must be 3 or 4 digits",
4313
+ termsAccepted: (value) => value ? void 0 : "You must accept the terms"
4314
+ }),
4315
+ []
4316
+ );
4317
+ const updateField = (field, value) => {
4318
+ setForm((prev) => ({ ...prev, [field]: value }));
4319
+ setErrors((prev) => ({ ...prev, [field]: void 0 }));
4320
+ };
4321
+ const validate = () => {
4322
+ const next = {};
4323
+ Object.keys(validators).forEach((key) => {
4324
+ const validator = validators[key];
4325
+ const message = validator?.(form[key]);
4326
+ if (message) {
4327
+ next[key] = message;
4328
+ }
4329
+ });
4330
+ setErrors(next);
4331
+ return Object.keys(next).length === 0;
4332
+ };
4333
+ const handleSubmit = (event) => {
4334
+ event.preventDefault();
4335
+ if (!validate()) return;
4336
+ console.log("[payments-ui] wallet dialog submit", form);
4337
+ onOpenChange(false);
4338
+ setForm(initialState);
4339
+ };
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: [
4341
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogHeader, { className: "border-b border-border/60 pb-4", children: [
4342
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2", children: [
4343
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shield, { className: "h-5 w-5 text-primary" }),
4344
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogTitle, { className: "text-center text-base font-semibold uppercase tracking-wide", children: "Secure Payment via Mobius Pay" })
4345
+ ] }),
4346
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-center text-sm text-muted-foreground", children: "$23 USD per month, cancel at any time." })
4347
+ ] }),
4348
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "space-y-5 px-2 py-4 sm:px-4", children: [
4349
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
4350
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4351
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "mb-1 block text-sm text-muted-foreground", children: "Name on Card" }),
4352
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
4353
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.UserRound, { className: "h-4 w-4" }) }),
4354
+ /* @__PURE__ */ jsxRuntime.jsx(Input, { value: form.nameOnCard, onChange: (e) => updateField("nameOnCard", e.target.value), className: "pl-10" })
4355
+ ] }),
4356
+ errors.nameOnCard && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-destructive", children: errors.nameOnCard })
4357
+ ] }),
4358
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
4359
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "mb-1 block text-sm text-muted-foreground", children: "Credit Card Number" }),
4360
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
4361
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4" }) }),
4362
+ /* @__PURE__ */ jsxRuntime.jsx(Input, { value: form.cardNumber, onChange: (e) => updateField("cardNumber", e.target.value), className: "pl-10" })
4363
+ ] }),
4364
+ errors.cardNumber && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-destructive", children: errors.cardNumber })
4365
+ ] }),
4366
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
4367
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
4368
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "mb-1 block text-sm text-muted-foreground", children: "Expiration" }),
4369
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
4370
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-4 w-4" }) }),
4371
+ /* @__PURE__ */ jsxRuntime.jsx(Input, { value: form.expiration, onChange: (e) => updateField("expiration", e.target.value), className: "pl-10", placeholder: "MM/YY" })
4372
+ ] }),
4373
+ errors.expiration && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-destructive", children: errors.expiration })
4374
+ ] }),
4375
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
4376
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "mb-1 block text-sm text-muted-foreground", children: "CVV" }),
4377
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
4378
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.KeyRound, { className: "h-4 w-4" }) }),
4379
+ /* @__PURE__ */ jsxRuntime.jsx(Input, { value: form.cvv, onChange: (e) => updateField("cvv", e.target.value), className: "pl-10" })
4380
+ ] }),
4381
+ errors.cvv && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-destructive", children: errors.cvv })
4382
+ ] })
4383
+ ] })
4384
+ ] }),
4385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 rounded-md border border-border/70 bg-muted/10 p-4", children: [
4386
+ /* @__PURE__ */ jsxRuntime.jsx(Checkbox, { id: "terms-agree", checked: form.termsAccepted, onCheckedChange: (checked) => updateField("termsAccepted", Boolean(checked)) }),
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." })
4388
+ ] }),
4389
+ errors.termsAccepted && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-destructive", children: errors.termsAccepted }),
4390
+ /* @__PURE__ */ jsxRuntime.jsxs(AlertDialogFooter, { className: "flex gap-2", children: [
4391
+ /* @__PURE__ */ jsxRuntime.jsx(Button, { type: "submit", className: "flex-1", children: "Subscribe" }),
4392
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDialogCancel, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", className: "flex-1", children: "Close" }) })
4393
+ ] })
4394
+ ] })
4395
+ ] }) });
4396
+ };
2927
4397
  var useTokenBalance = (tokens) => {
2928
4398
  const { publicKey } = walletAdapterReact.useWallet();
2929
4399
  const { connection } = walletAdapterReact.useConnection();
@@ -3443,33 +4913,50 @@ var useAlternativePaymentProvider = () => {
3443
4913
  return { openFlexForm, isLoading, error };
3444
4914
  };
3445
4915
 
4916
+ exports.BillingHistory = BillingHistory;
4917
+ exports.CancelMembershipDialog = CancelMembershipDialog;
3446
4918
  exports.CardDetailsForm = CardDetailsForm;
3447
4919
  exports.CardPaymentService = CardPaymentService;
4920
+ exports.EmptyWalletState = EmptyWalletState;
3448
4921
  exports.PaymentApp = PaymentApp;
3449
4922
  exports.PaymentExperience = PaymentExperience;
3450
4923
  exports.PaymentMethodService = PaymentMethodService;
4924
+ exports.PaymentMethodsSection = PaymentMethodsSection;
3451
4925
  exports.PaymentProvider = PaymentProvider;
4926
+ exports.PaymentsDialogProvider = PaymentsDialogProvider;
4927
+ exports.PaymentsRuntime = PaymentsRuntime;
3452
4928
  exports.SolanaPaymentSelector = SolanaPaymentSelector;
3453
4929
  exports.SolanaPaymentService = SolanaPaymentService;
4930
+ exports.SolanaPaymentView = SolanaPaymentView;
4931
+ exports.SolanaWalletSection = SolanaWalletSection;
4932
+ exports.SolanaWalletService = SolanaWalletService;
3454
4933
  exports.StoredPaymentMethods = StoredPaymentMethods;
3455
4934
  exports.SubscriptionCheckoutModal = SubscriptionCheckoutModal;
3456
4935
  exports.SubscriptionService = SubscriptionService;
3457
4936
  exports.SubscriptionSuccessDialog = SubscriptionSuccessDialog;
3458
4937
  exports.TokenCatalog = TokenCatalog;
4938
+ exports.WalletCard = WalletCard;
4939
+ exports.WalletDialog = WalletDialog;
3459
4940
  exports.WalletGateway = WalletGateway;
3460
- exports.createPaymentStore = createPaymentStore;
4941
+ exports.WalletManagement = WalletManagement;
4942
+ exports.WalletModal = WalletModal;
4943
+ exports.createPaymentsRuntime = createPaymentsRuntime;
3461
4944
  exports.useAlternativePaymentProvider = useAlternativePaymentProvider;
3462
4945
  exports.useDirectWalletPayment = useDirectWalletPayment;
3463
4946
  exports.usePaymentContext = usePaymentContext;
4947
+ exports.usePaymentDialogs = usePaymentDialogs;
3464
4948
  exports.usePaymentMethodService = usePaymentMethodService;
3465
4949
  exports.usePaymentMethods = usePaymentMethods;
4950
+ exports.usePaymentNotifications = usePaymentNotifications;
3466
4951
  exports.usePaymentStatus = usePaymentStatus;
3467
- exports.usePaymentStore = usePaymentStore;
3468
4952
  exports.useSolanaDirectPayment = useSolanaDirectPayment;
3469
4953
  exports.useSolanaQrPayment = useSolanaQrPayment;
3470
4954
  exports.useSolanaService = useSolanaService;
3471
4955
  exports.useSubscriptionActions = useSubscriptionActions;
3472
4956
  exports.useSupportedTokens = useSupportedTokens;
3473
4957
  exports.useTokenBalance = useTokenBalance;
4958
+ exports.useWalletConnection = useWalletConnection;
4959
+ exports.useWalletList = useWalletList;
4960
+ exports.useWalletVerification = useWalletVerification;
3474
4961
  //# sourceMappingURL=index.cjs.map
3475
4962
  //# sourceMappingURL=index.cjs.map