@b3dotfun/sdk 0.0.10 → 0.0.11-alpha.0

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.
Files changed (46) hide show
  1. package/dist/cjs/anyspend/react/components/AnySpendCustom.js +1 -1
  2. package/dist/cjs/anyspend/react/components/common/PaymentStripeWeb2.js +62 -25
  3. package/dist/cjs/anyspend/react/components/webview/WebviewOnrampPayment.js +29 -6
  4. package/dist/cjs/anyspend/react/providers/AnyspendProvider.d.ts +1 -0
  5. package/dist/cjs/anyspend/react/providers/AnyspendProvider.js +3 -1
  6. package/dist/cjs/anyspend/react/providers/StripeRedirectHandler.d.ts +8 -0
  7. package/dist/cjs/anyspend/react/providers/StripeRedirectHandler.js +41 -0
  8. package/dist/cjs/global-account/react/components/B3DynamicModal.js +2 -2
  9. package/dist/cjs/global-account/react/components/ui/dialog.js +1 -1
  10. package/dist/cjs/global-account/react/hooks/index.d.ts +1 -0
  11. package/dist/cjs/global-account/react/hooks/index.js +4 -1
  12. package/dist/cjs/global-account/react/hooks/useAccountWallet.js +0 -4
  13. package/dist/cjs/global-account/react/hooks/useProfile.d.ts +38 -0
  14. package/dist/cjs/global-account/react/hooks/useProfile.js +72 -0
  15. package/dist/esm/anyspend/react/components/AnySpendCustom.js +1 -1
  16. package/dist/esm/anyspend/react/components/common/PaymentStripeWeb2.js +64 -27
  17. package/dist/esm/anyspend/react/components/webview/WebviewOnrampPayment.js +30 -7
  18. package/dist/esm/anyspend/react/providers/AnyspendProvider.d.ts +1 -0
  19. package/dist/esm/anyspend/react/providers/AnyspendProvider.js +4 -2
  20. package/dist/esm/anyspend/react/providers/StripeRedirectHandler.d.ts +8 -0
  21. package/dist/esm/anyspend/react/providers/StripeRedirectHandler.js +38 -0
  22. package/dist/esm/global-account/react/components/B3DynamicModal.js +2 -2
  23. package/dist/esm/global-account/react/components/ui/dialog.js +1 -1
  24. package/dist/esm/global-account/react/hooks/index.d.ts +1 -0
  25. package/dist/esm/global-account/react/hooks/index.js +1 -0
  26. package/dist/esm/global-account/react/hooks/useAccountWallet.js +0 -4
  27. package/dist/esm/global-account/react/hooks/useProfile.d.ts +38 -0
  28. package/dist/esm/global-account/react/hooks/useProfile.js +68 -0
  29. package/dist/styles/index.css +1 -1
  30. package/dist/types/anyspend/react/providers/AnyspendProvider.d.ts +1 -0
  31. package/dist/types/anyspend/react/providers/StripeRedirectHandler.d.ts +8 -0
  32. package/dist/types/global-account/react/hooks/index.d.ts +1 -0
  33. package/dist/types/global-account/react/hooks/useProfile.d.ts +38 -0
  34. package/package.json +2 -2
  35. package/src/anyspend/react/components/AnySpendCustom.tsx +1 -1
  36. package/src/anyspend/react/components/common/PaymentStripeWeb2.tsx +86 -35
  37. package/src/anyspend/react/components/webview/WebviewOnrampPayment.tsx +39 -7
  38. package/src/anyspend/react/providers/AnyspendProvider.tsx +6 -1
  39. package/src/anyspend/react/providers/StripeRedirectHandler.tsx +45 -0
  40. package/src/global-account/react/components/B3DynamicModal.tsx +2 -2
  41. package/src/global-account/react/components/ui/dialog.tsx +3 -4
  42. package/src/global-account/react/components/ui/drawer.tsx +0 -2
  43. package/src/global-account/react/hooks/index.ts +7 -0
  44. package/src/global-account/react/hooks/useAccountWallet.tsx +0 -5
  45. package/src/global-account/react/hooks/useProfile.ts +141 -0
  46. package/src/styles/index.css +1 -1
@@ -369,7 +369,7 @@ function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", recipient
369
369
  const historyView = ((0, jsx_runtime_1.jsx)("div", { className: (0, utils_1.cn)("mx-auto flex w-full max-w-2xl flex-col items-center p-5", mode === "modal" && "bg-b3-react-background"), children: (0, jsx_runtime_1.jsx)(OrderHistory_1.OrderHistory, { mode: mode, onBack: () => {
370
370
  setActivePanel(PanelView.HISTORY);
371
371
  }, onSelectOrder: onSelectOrder }) }));
372
- const orderDetailsView = ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("mx-auto flex max-h-[90dvh] w-full flex-col items-center gap-4 overflow-y-auto p-5", mode === "modal" && "bg-b3-react-background"), children: [oat && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(OrderStatus_1.OrderStatus, { order: oat.data.order }), (0, jsx_runtime_1.jsx)(OrderDetails_1.OrderDetails, { isMainnet: isMainnet, mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, onBack: () => {
372
+ const orderDetailsView = ((0, jsx_runtime_1.jsxs)("div", { className: (0, utils_1.cn)("mx-auto flex w-full flex-col items-center gap-4 p-5", mode === "modal" && "bg-b3-react-background"), children: [oat && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(OrderStatus_1.OrderStatus, { order: oat.data.order }), (0, jsx_runtime_1.jsx)(OrderDetails_1.OrderDetails, { isMainnet: isMainnet, mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, onBack: () => {
373
373
  setOrderId(undefined);
374
374
  setActivePanel(PanelView.CONFIRM_ORDER);
375
375
  // Remove orderId from URL when canceling
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.default = PaymentStripeWeb2;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const anyspend_1 = require("../../../../anyspend");
9
- const react_1 = require("../../../../anyspend/react");
10
9
  const constants_1 = require("../../../../anyspend/constants");
10
+ const react_1 = require("../../../../anyspend/react");
11
11
  const react_2 = require("../../../../global-account/react");
12
12
  const payment_utils_1 = require("../../../../shared/utils/payment.utils");
13
13
  const react_stripe_js_1 = require("@stripe/react-stripe-js");
@@ -40,11 +40,13 @@ function StripeErrorState({ error }) {
40
40
  function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
41
41
  const stripe = (0, react_stripe_js_1.useStripe)();
42
42
  const elements = (0, react_stripe_js_1.useElements)();
43
+ const setB3ModalOpen = (0, react_2.useModalStore)(state => state.setB3ModalOpen);
43
44
  const [loading, setLoading] = (0, react_3.useState)(false);
44
45
  const [message, setMessage] = (0, react_3.useState)(null);
45
46
  const [amount, setAmount] = (0, react_3.useState)(null);
46
47
  const [stripeReady, setStripeReady] = (0, react_3.useState)(false);
47
48
  const [showHowItWorks, setShowHowItWorks] = (0, react_3.useState)(false);
49
+ const [showAddressElement, setShowAddressElement] = (0, react_3.useState)(false);
48
50
  (0, react_3.useEffect)(() => {
49
51
  if (stripe && elements) {
50
52
  setStripeReady(true);
@@ -68,6 +70,12 @@ function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
68
70
  };
69
71
  fetchPaymentIntent();
70
72
  }, [clientSecret, stripe]);
73
+ // Handle payment element changes
74
+ const handlePaymentElementChange = (event) => {
75
+ // Show address element only for card payments
76
+ console.log("@@stripe-web2-payment:payment-element-change:", JSON.stringify(event, null, 2));
77
+ setShowAddressElement(event.value.type === "card");
78
+ };
71
79
  const handleSubmit = async (e) => {
72
80
  e.preventDefault();
73
81
  if (!stripe || !elements) {
@@ -78,25 +86,29 @@ function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
78
86
  setMessage(null);
79
87
  try {
80
88
  console.log("@@stripe-web2-payment:confirming-payment:", JSON.stringify({ orderId: order.id }, null, 2));
81
- const { error, paymentIntent } = await stripe.confirmPayment({
89
+ const result = (await stripe.confirmPayment({
82
90
  elements,
83
- redirect: "if_required",
84
- });
85
- if (error) {
86
- console.error("@@stripe-web2-payment:error:", JSON.stringify(error, null, 2));
87
- setMessage(error.message || "An unexpected error occurred.");
88
- }
89
- else if (paymentIntent && paymentIntent.status === "succeeded") {
90
- console.log("@@stripe-web2-payment:success:", JSON.stringify({ orderId: order.id, paymentIntentId: paymentIntent.id }, null, 2));
91
- // Payment succeeded without redirect - handle success in the modal
92
- setMessage(null);
93
- // Add waitingForDeposit=true to query params
94
- const currentUrl = new URL(window.location.href);
95
- currentUrl.searchParams.set("waitingForDeposit", "true");
96
- window.history.replaceState(null, "", currentUrl.toString());
97
- // Call the success callback if provided
98
- onPaymentSuccess?.(paymentIntent);
91
+ confirmParams: {
92
+ return_url: `${window.location.origin}/?orderId=${order.id}&waitingForDeposit=true&fromStripe=true`,
93
+ },
94
+ }));
95
+ if (result.error) {
96
+ // This point will only be reached if there is an immediate error.
97
+ // Otherwise, the customer will be redirected to the `return_url`.
98
+ console.error("@@stripe-web2-payment:error:", JSON.stringify(result.error, null, 2));
99
+ setMessage(result.error.message || "An unexpected error occurred.");
100
+ return;
99
101
  }
102
+ // At this point TypeScript knows result.paymentIntent exists and error is undefined
103
+ console.log("@@stripe-web2-payment:success:", JSON.stringify({ orderId: order.id, paymentIntentId: result.paymentIntent.id }, null, 2));
104
+ // Payment succeeded without redirect - handle success in the modal
105
+ setMessage(null);
106
+ // Add waitingForDeposit=true to query params
107
+ const currentUrl = new URL(window.location.href);
108
+ currentUrl.searchParams.set("waitingForDeposit", "true");
109
+ window.history.replaceState(null, "", currentUrl.toString());
110
+ // Call the success callback if provided
111
+ onPaymentSuccess?.(result.paymentIntent);
100
112
  }
101
113
  catch (error) {
102
114
  console.error("@@stripe-web2-payment:confirmation-error:", JSON.stringify(error, null, 2));
@@ -106,17 +118,27 @@ function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
106
118
  setLoading(false);
107
119
  }
108
120
  };
121
+ // Handle 3DS redirect
122
+ (0, react_3.useEffect)(() => {
123
+ // Check if we're returning from Stripe
124
+ const url = new URL(window.location.href);
125
+ const fromStripe = url.searchParams.get("fromStripe");
126
+ const paymentIntent = url.searchParams.get("payment_intent");
127
+ console.log("@@stripe-web2-payment:fromStripe:", fromStripe);
128
+ console.log("@@stripe-web2-payment:paymentIntent:", paymentIntent);
129
+ if (fromStripe && paymentIntent) {
130
+ // Close the modal as we're returning from 3DS
131
+ setB3ModalOpen(true);
132
+ // Clean up URL params
133
+ url.searchParams.delete("fromStripe");
134
+ window.history.replaceState({}, "", url.toString());
135
+ }
136
+ }, [setB3ModalOpen]);
109
137
  if (!stripeReady) {
110
138
  return (0, jsx_runtime_1.jsx)(StripeLoadingState, {});
111
139
  }
112
140
  const stripeElementOptions = {
113
141
  layout: "tabs",
114
- defaultValues: {
115
- billingDetails: {
116
- name: "",
117
- email: "",
118
- },
119
- },
120
142
  fields: {
121
143
  billingDetails: "auto",
122
144
  },
@@ -144,7 +166,22 @@ function StripePaymentForm({ order, clientSecret, onPaymentSuccess, }) {
144
166
  const finalAmount = Number(amount);
145
167
  const calculatedFee = finalAmount - originalAmount;
146
168
  return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between text-sm", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-primary/60", children: "Amount" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-as-primary", children: ["$", originalAmount.toFixed(2)] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between text-sm", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-primary/60", children: "Processing fee" }), (0, jsx_runtime_1.jsx)(Tooltip, { content: `Credit card companies charge a processing fee of 5.4% + $0.30 for all transactions.\n\nThis fee covers secure payment processing and fraud protection.`, children: (0, jsx_runtime_1.jsx)(lucide_react_1.Info, { className: "text-as-primary/40 hover:text-as-primary/60 h-3 w-3 transition-colors" }) })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-as-primary", children: ["$", calculatedFee.toFixed(2)] })] }), (0, jsx_runtime_1.jsx)("div", { className: "border-as-stroke border-t pt-2", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-as-primary font-semibold", children: "Total Amount" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-as-primary text-2xl font-bold", children: ["$", finalAmount.toFixed(2), " USD"] })] }) })] }));
147
- })()] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-as-on-surface-1 w-full rounded-2xl p-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-primary mb-4 text-lg font-semibold", children: "Payment Details" }), (0, jsx_runtime_1.jsx)(react_stripe_js_1.PaymentElement, { options: stripeElementOptions })] }), message && ((0, jsx_runtime_1.jsxs)("div", { className: "bg-as-red/10 border-as-red/20 flex w-full items-center gap-3 rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-as-red flex h-6 w-6 shrink-0 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-4 w-4 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-red text-sm font-medium", children: message })] })), (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { type: "submit", accentColor: "hsl(var(--as-brand))", disabled: !stripe || !elements || loading, className: "relative w-full py-4 text-lg font-semibold", children: loading ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-5 w-5 animate-spin rounded-full border-2 border-current border-t-transparent" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white", children: "Processing Payment..." })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-white", children: "Complete Payment" }), amount && (0, jsx_runtime_1.jsxs)("span", { className: "text-white/90", children: ["$", Number(amount).toFixed(2)] })] })) })] }), showHowItWorks && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-as-on-surface-1 relative max-h-[80vh] w-full max-w-2xl overflow-y-auto rounded-2xl p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-6 flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-xl font-semibold", children: "How it works" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowHowItWorks(false), className: "text-as-primary/60 hover:text-as-primary transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-6 w-6" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsx)(PaymentMethodIcons_1.default, {}), (0, jsx_runtime_1.jsx)(HowItWorks_1.default, { steps: howItWorksSteps })] })] }) }))] }));
169
+ })()] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-as-on-surface-1 w-full rounded-2xl p-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-primary mb-4 text-lg font-semibold", children: "Payment Details" }), (0, jsx_runtime_1.jsx)(react_stripe_js_1.PaymentElement, { onChange: handlePaymentElementChange, options: stripeElementOptions }), showAddressElement && ((0, jsx_runtime_1.jsx)(react_stripe_js_1.AddressElement, { options: {
170
+ mode: "billing",
171
+ fields: {
172
+ phone: "always",
173
+ },
174
+ // More granular control
175
+ display: {
176
+ name: "split", // or 'split' for first/last name separately
177
+ },
178
+ // Validation
179
+ validation: {
180
+ phone: {
181
+ required: "auto", // or 'always', 'never'
182
+ },
183
+ },
184
+ } }))] }), message && ((0, jsx_runtime_1.jsxs)("div", { className: "bg-as-red/10 border-as-red/20 flex w-full items-center gap-3 rounded-2xl border p-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "bg-as-red flex h-6 w-6 shrink-0 items-center justify-center rounded-full", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-4 w-4 text-white", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-red text-sm font-medium", children: message })] })), (0, jsx_runtime_1.jsx)(react_2.ShinyButton, { type: "submit", accentColor: "hsl(var(--as-brand))", disabled: !stripe || !elements || loading, className: "relative w-full py-4 text-lg font-semibold", children: loading ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "h-5 w-5 animate-spin rounded-full border-2 border-current border-t-transparent" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white", children: "Processing Payment..." })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-white", children: "Complete Payment" }), amount && (0, jsx_runtime_1.jsxs)("span", { className: "text-white/90", children: ["$", Number(amount).toFixed(2)] })] })) })] }), showHowItWorks && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-as-on-surface-1 relative max-h-[80vh] w-full max-w-2xl overflow-y-auto rounded-2xl p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-6 flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-as-primary text-xl font-semibold", children: "How it works" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowHowItWorks(false), className: "text-as-primary/60 hover:text-as-primary transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-6 w-6" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsx)(PaymentMethodIcons_1.default, {}), (0, jsx_runtime_1.jsx)(HowItWorks_1.default, { steps: howItWorksSteps })] })] }) }))] }));
148
185
  }
149
186
  // Add tooltip component
150
187
  function Tooltip({ children, content }) {
@@ -22,6 +22,7 @@ function StripePaymentForm({ order, onPaymentSuccess, }) {
22
22
  const elements = (0, react_stripe_js_1.useElements)();
23
23
  const [isProcessing, setIsProcessing] = (0, react_2.useState)(false);
24
24
  const [error, setError] = (0, react_2.useState)(null);
25
+ const [showAddressElement, setShowAddressElement] = (0, react_2.useState)(false);
25
26
  const handleSubmit = async (e) => {
26
27
  e.preventDefault();
27
28
  if (!stripe || !elements) {
@@ -51,16 +52,38 @@ function StripePaymentForm({ order, onPaymentSuccess, }) {
51
52
  setIsProcessing(false);
52
53
  }
53
54
  };
55
+ // Handle payment element changes
56
+ const handlePaymentElementChange = (event) => {
57
+ // Show address element only for card payments
58
+ console.log("@@stripe-web2-payment:payment-element-change:", JSON.stringify(event, null, 2));
59
+ setShowAddressElement(event.value.type === "card");
60
+ };
54
61
  const stripeElementOptions = {
55
62
  layout: "tabs",
56
- defaultValues: {
57
- billingDetails: {
58
- name: "",
59
- email: "",
60
- },
63
+ fields: {
64
+ billingDetails: "auto",
65
+ },
66
+ wallets: {
67
+ applePay: "auto",
68
+ googlePay: "auto",
61
69
  },
62
70
  };
63
- return ((0, jsx_runtime_1.jsx)("form", { onSubmit: handleSubmit, className: "w-full", children: (0, jsx_runtime_1.jsx)("div", { className: "overflow-hidden rounded-xl bg-white", children: (0, jsx_runtime_1.jsxs)("div", { className: "px-6 py-4", children: [(0, jsx_runtime_1.jsx)("h2", { className: "mb-4 text-lg font-semibold", children: "Payment Details" }), (0, jsx_runtime_1.jsx)(react_stripe_js_1.PaymentElement, { options: stripeElementOptions }), error && ((0, jsx_runtime_1.jsx)("div", { className: "mt-4 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error })), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: !stripe || isProcessing, className: "mt-6 w-full rounded-xl bg-blue-600 px-4 py-3 font-medium text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50", children: isProcessing ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-5 w-5 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { children: "Processing..." })] })) : ((0, jsx_runtime_1.jsx)("span", { children: "Complete Payment" })) })] }) }) }));
71
+ return ((0, jsx_runtime_1.jsx)("form", { onSubmit: handleSubmit, className: "w-full", children: (0, jsx_runtime_1.jsx)("div", { className: "overflow-hidden rounded-xl bg-white", children: (0, jsx_runtime_1.jsxs)("div", { className: "px-6 py-4", children: [(0, jsx_runtime_1.jsx)("h2", { className: "mb-4 text-lg font-semibold", children: "Payment Details" }), (0, jsx_runtime_1.jsx)(react_stripe_js_1.PaymentElement, { options: stripeElementOptions, onChange: handlePaymentElementChange }), showAddressElement && ((0, jsx_runtime_1.jsx)("div", { className: "mt-4", children: (0, jsx_runtime_1.jsx)(react_stripe_js_1.AddressElement, { options: {
72
+ mode: "billing",
73
+ fields: {
74
+ phone: "always",
75
+ },
76
+ // More granular control
77
+ display: {
78
+ name: "split", // or 'split' for first/last name separately
79
+ },
80
+ // Validation
81
+ validation: {
82
+ phone: {
83
+ required: "auto", // or 'always', 'never'
84
+ },
85
+ },
86
+ } }) })), error && ((0, jsx_runtime_1.jsx)("div", { className: "mt-4 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-600", children: error })), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: !stripe || isProcessing, className: "mt-6 w-full rounded-xl bg-blue-600 px-4 py-3 font-medium text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50", children: isProcessing ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center gap-2", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-5 w-5 animate-spin" }), (0, jsx_runtime_1.jsx)("span", { children: "Processing..." })] })) : ((0, jsx_runtime_1.jsx)("span", { children: "Complete Payment" })) })] }) }) }));
64
87
  }
65
88
  function WebviewOnrampPayment({ srcAmountOnRamp, recipientAddress, destinationToken, anyspendQuote, onPaymentSuccess, userId, partnerId, }) {
66
89
  const [stableAmountForGeo, setStableAmountForGeo] = (0, react_2.useState)(srcAmountOnRamp);
@@ -11,6 +11,7 @@ interface AnyspendProviderProps {
11
11
  * - Optimized for performance with React.memo
12
12
  * - Safe to use at the application root
13
13
  * - Configures sensible defaults for query caching
14
+ * - Handles Stripe payment redirects and modal state
14
15
  *
15
16
  * @example
16
17
  * ```tsx
@@ -6,6 +6,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  const react_1 = require("../../../global-account/react");
7
7
  const react_query_1 = require("@tanstack/react-query");
8
8
  const react_2 = require("react");
9
+ const StripeRedirectHandler_1 = require("./StripeRedirectHandler");
9
10
  const defaultQueryClientConfig = {
10
11
  defaultOptions: {
11
12
  queries: {
@@ -24,6 +25,7 @@ const defaultQueryClientConfig = {
24
25
  * - Optimized for performance with React.memo
25
26
  * - Safe to use at the application root
26
27
  * - Configures sensible defaults for query caching
28
+ * - Handles Stripe payment redirects and modal state
27
29
  *
28
30
  * @example
29
31
  * ```tsx
@@ -38,6 +40,6 @@ const defaultQueryClientConfig = {
38
40
  */
39
41
  const AnyspendProvider = function AnyspendProvider({ children }) {
40
42
  const [queryClient] = (0, react_2.useState)(() => new react_query_1.QueryClient(defaultQueryClientConfig));
41
- return ((0, jsx_runtime_1.jsx)(react_query_1.QueryClientProvider, { client: queryClient, children: (0, jsx_runtime_1.jsx)(react_1.TooltipProvider, { children: children }) }));
43
+ return ((0, jsx_runtime_1.jsx)(react_query_1.QueryClientProvider, { client: queryClient, children: (0, jsx_runtime_1.jsxs)(react_1.TooltipProvider, { children: [(0, jsx_runtime_1.jsx)(StripeRedirectHandler_1.StripeRedirectHandler, {}), children] }) }));
42
44
  };
43
45
  exports.AnyspendProvider = AnyspendProvider;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Handles Stripe payment redirects by showing the order details modal
3
+ * when returning from Stripe's payment flow.
4
+ *
5
+ * This component should be mounted inside AnyspendProvider to ensure
6
+ * proper modal state management.
7
+ */
8
+ export declare function StripeRedirectHandler(): null;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ "use client";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.StripeRedirectHandler = StripeRedirectHandler;
5
+ const react_1 = require("../../../global-account/react");
6
+ const react_2 = require("react");
7
+ /**
8
+ * Handles Stripe payment redirects by showing the order details modal
9
+ * when returning from Stripe's payment flow.
10
+ *
11
+ * This component should be mounted inside AnyspendProvider to ensure
12
+ * proper modal state management.
13
+ */
14
+ function StripeRedirectHandler() {
15
+ const setB3ModalOpen = (0, react_1.useModalStore)(state => state.setB3ModalOpen);
16
+ const setB3ModalContentType = (0, react_1.useModalStore)(state => state.setB3ModalContentType);
17
+ (0, react_2.useEffect)(() => {
18
+ const url = new URL(window.location.href);
19
+ const fromStripe = url.searchParams.get("fromStripe");
20
+ const paymentIntent = url.searchParams.get("payment_intent");
21
+ const orderId = url.searchParams.get("orderId");
22
+ console.log("@@stripe-web2-payment:fromStripe:", fromStripe);
23
+ console.log("@@stripe-web2-payment:paymentIntent:", paymentIntent);
24
+ console.log("@@stripe-web2-payment:orderId:", orderId);
25
+ if (fromStripe && paymentIntent && orderId) {
26
+ // Re-open the modal with the order details
27
+ setB3ModalOpen(true);
28
+ setB3ModalContentType({
29
+ type: "anyspendOrderDetails",
30
+ orderId,
31
+ });
32
+ // Clean up URL params
33
+ url.searchParams.delete("fromStripe");
34
+ url.searchParams.delete("payment_intent");
35
+ url.searchParams.delete("payment_intent_client_secret");
36
+ url.searchParams.delete("redirect_status");
37
+ window.history.replaceState({}, "", url.toString());
38
+ }
39
+ }, [setB3ModalOpen, setB3ModalContentType]);
40
+ return null;
41
+ }
@@ -31,7 +31,7 @@ function B3DynamicModal() {
31
31
  "anySpendSignatureMint",
32
32
  "anySpendBondKit",
33
33
  ].find(type => contentType?.type === type)) {
34
- contentClass += " max-h-[90dvh] overflow-y-auto no-scrollbar w-full";
34
+ contentClass += " w-full";
35
35
  }
36
36
  if ([
37
37
  "anySpendNft",
@@ -93,5 +93,5 @@ function B3DynamicModal() {
93
93
  const ModalContent = isMobile ? drawer_1.DrawerContent : dialog_1.DialogContent;
94
94
  const ModalTitle = isMobile ? drawer_1.DrawerTitle : dialog_1.DialogTitle;
95
95
  const ModalDescription = isMobile ? drawer_1.DrawerDescription : dialog_1.DialogDescription;
96
- return ((0, jsx_runtime_1.jsx)(ModalComponent, { open: isOpen, onOpenChange: setB3ModalOpen, children: (0, jsx_runtime_1.jsxs)(ModalContent, { className: contentClass, hideCloseButton: hideCloseButton, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: "overflow-auto", children: [history.length > 0 && contentType?.showBackButton && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "b3-modal-back-button mb-4 flex items-center gap-2 transition-colors hover:text-white", children: [(0, jsx_runtime_1.jsx)("span", { children: "\u2190" }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm", children: "Back" })] })), renderContent()] })] }) }));
96
+ return ((0, jsx_runtime_1.jsx)(ModalComponent, { open: isOpen, onOpenChange: setB3ModalOpen, children: (0, jsx_runtime_1.jsxs)(ModalContent, { className: contentClass, hideCloseButton: hideCloseButton, children: [(0, jsx_runtime_1.jsx)(ModalTitle, { className: "sr-only hidden", children: contentType?.type || "Modal" }), (0, jsx_runtime_1.jsx)(ModalDescription, { className: "sr-only hidden", children: contentType?.type || "Modal Body" }), (0, jsx_runtime_1.jsxs)("div", { className: "no-scrollbar max-h-[90dvh] overflow-auto sm:max-h-[80dvh]", children: [history.length > 0 && contentType?.showBackButton && ((0, jsx_runtime_1.jsxs)("button", { onClick: navigateBack, className: "b3-modal-back-button mb-4 flex items-center gap-2 transition-colors hover:text-white", children: [(0, jsx_runtime_1.jsx)("span", { children: "\u2190" }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm", children: "Back" })] })), renderContent()] })] }) }));
97
97
  }
@@ -53,7 +53,7 @@ exports.DialogOverlay = DialogOverlay;
53
53
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
54
54
  const DialogContent = React.forwardRef(({ className, children, hideCloseButton = false, closeBtnClassName, ...props }, ref) => {
55
55
  const container = typeof window !== "undefined" ? document.getElementById("b3-root") : null;
56
- return ((0, jsx_runtime_1.jsxs)(DialogPortal, { container: container, children: [(0, jsx_runtime_1.jsx)(DialogOverlay, {}), (0, jsx_runtime_1.jsxs)(DialogPrimitive.Content, { ref: ref, className: (0, utils_1.cn)("bg-b3-react-background fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg !outline-none", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 duration-500", "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%]", "data-[state=closed]:rotate-x-10 data-[state=open]:rotate-x-0", "[perspective:1200px] [transform-style:preserve-3d] sm:rounded-xl", "ease-spring transition-all", className), ...props, children: [children, !hideCloseButton && ((0, jsx_runtime_1.jsxs)(DialogPrimitive.Close, { className: (0, utils_1.cn)("data-[state=open]:bg-accent data-[state=open]:text-b3-react-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400", closeBtnClassName), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-5 w-5" }), (0, jsx_runtime_1.jsx)("span", { className: "sr-only", children: "Close" })] }))] })] }));
56
+ return ((0, jsx_runtime_1.jsxs)(DialogPortal, { container: container, children: [(0, jsx_runtime_1.jsx)(DialogOverlay, {}), (0, jsx_runtime_1.jsxs)(DialogPrimitive.Content, { ref: ref, className: (0, utils_1.cn)("bg-b3-react-background fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border p-6 shadow-lg !outline-none", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 duration-500", "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%]", "[perspective:1200px] [transform-style:preserve-3d] sm:rounded-xl", "transition-all ease-out", className), ...props, children: [children, !hideCloseButton && ((0, jsx_runtime_1.jsxs)(DialogPrimitive.Close, { className: (0, utils_1.cn)("data-[state=open]:bg-b3-react-background data-[state=open]:text-b3-react-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none dark:data-[state=open]:bg-gray-800 dark:data-[state=open]:text-gray-400", closeBtnClassName), children: [(0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "h-5 w-5" }), (0, jsx_runtime_1.jsx)("span", { className: "sr-only", children: "Close" })] }))] })] }));
57
57
  });
58
58
  exports.DialogContent = DialogContent;
59
59
  DialogContent.displayName = DialogPrimitive.Content.displayName;
@@ -20,6 +20,7 @@ export { useMediaQuery } from "./useMediaQuery";
20
20
  export { useNativeBalance, useNativeBalanceFromRPC } from "./useNativeBalance";
21
21
  export { useOnchainName } from "./useOnchainName";
22
22
  export { useOneBalance } from "./useOneBalance";
23
+ export { useProfile, useProfilePreference, type Profile, type CombinedProfile, type PreferenceRequestBody, } from "./useProfile";
23
24
  export { useQueryB3 } from "./useQueryB3";
24
25
  export { useQueryBSMNT } from "./useQueryBSMNT";
25
26
  export { useRemoveSessionKey } from "./useRemoveSessionKey";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useURLParams = exports.useTokensFromAddress = exports.useTokenPriceWithFallback = exports.useTokenPrice = exports.useTokenFromUrl = exports.useTokenData = exports.useTokenBalancesByChain = exports.useTokenBalance = exports.useSiwe = exports.useSearchParamsSSR = exports.useRouter = exports.useRemoveSessionKey = exports.useQueryBSMNT = exports.useQueryB3 = exports.useOneBalance = exports.useOnchainName = exports.useNativeBalanceFromRPC = exports.useNativeBalance = exports.useMediaQuery = exports.useIsomorphicLayoutEffect = exports.useIsMobile = exports.useHasMounted = exports.useHandleConnectWithPrivy = exports.useGetGeo = exports.useGetAllTWSigners = exports.useExchangeRate = exports.useConnect = exports.useClaim = exports.useChainSwitchWithAction = exports.useBsmntProfile = exports.useBestTransactionPath = exports.useB3EnsName = exports.useB3BalanceFromAddresses = exports.useAuthentication = exports.useAddTWSessionKey = exports.useAccountWallet = exports.useAccountAssets = void 0;
3
+ exports.useURLParams = exports.useTokensFromAddress = exports.useTokenPriceWithFallback = exports.useTokenPrice = exports.useTokenFromUrl = exports.useTokenData = exports.useTokenBalancesByChain = exports.useTokenBalance = exports.useSiwe = exports.useSearchParamsSSR = exports.useRouter = exports.useRemoveSessionKey = exports.useQueryBSMNT = exports.useQueryB3 = exports.useProfilePreference = exports.useProfile = exports.useOneBalance = exports.useOnchainName = exports.useNativeBalanceFromRPC = exports.useNativeBalance = exports.useMediaQuery = exports.useIsomorphicLayoutEffect = exports.useIsMobile = exports.useHasMounted = exports.useHandleConnectWithPrivy = exports.useGetGeo = exports.useGetAllTWSigners = exports.useExchangeRate = exports.useConnect = exports.useClaim = exports.useChainSwitchWithAction = exports.useBsmntProfile = exports.useBestTransactionPath = exports.useB3EnsName = exports.useB3BalanceFromAddresses = exports.useAuthentication = exports.useAddTWSessionKey = exports.useAccountWallet = exports.useAccountAssets = void 0;
4
4
  var useAccountAssets_1 = require("./useAccountAssets");
5
5
  Object.defineProperty(exports, "useAccountAssets", { enumerable: true, get: function () { return useAccountAssets_1.useAccountAssets; } });
6
6
  var useAccountWallet_1 = require("./useAccountWallet");
@@ -46,6 +46,9 @@ var useOnchainName_1 = require("./useOnchainName");
46
46
  Object.defineProperty(exports, "useOnchainName", { enumerable: true, get: function () { return useOnchainName_1.useOnchainName; } });
47
47
  var useOneBalance_1 = require("./useOneBalance");
48
48
  Object.defineProperty(exports, "useOneBalance", { enumerable: true, get: function () { return useOneBalance_1.useOneBalance; } });
49
+ var useProfile_1 = require("./useProfile");
50
+ Object.defineProperty(exports, "useProfile", { enumerable: true, get: function () { return useProfile_1.useProfile; } });
51
+ Object.defineProperty(exports, "useProfilePreference", { enumerable: true, get: function () { return useProfile_1.useProfilePreference; } });
49
52
  var useQueryB3_1 = require("./useQueryB3");
50
53
  Object.defineProperty(exports, "useQueryB3", { enumerable: true, get: function () { return useQueryB3_1.useQueryB3; } });
51
54
  var useQueryBSMNT_1 = require("./useQueryBSMNT");
@@ -62,9 +62,5 @@ function useAccountWallet() {
62
62
  smartWalletIcon,
63
63
  walletImage,
64
64
  ]);
65
- (0, react_2.useEffect)(() => {
66
- console.log(`account`, account);
67
- console.log(`useAccountWallet`, res);
68
- }, [account, res]);
69
65
  return res;
70
66
  }
@@ -0,0 +1,38 @@
1
+ export interface Profile {
2
+ type: string;
3
+ address?: string;
4
+ name?: string;
5
+ avatar?: string | null;
6
+ bio?: string | null;
7
+ displayName?: string | null;
8
+ }
9
+ export interface CombinedProfile {
10
+ name: string | null;
11
+ address: string | null;
12
+ avatar: string | null;
13
+ bio: string | null;
14
+ displayName: string | null;
15
+ profiles: Profile[];
16
+ }
17
+ export interface PreferenceRequestBody {
18
+ key: string;
19
+ preferredType: string;
20
+ signature: string;
21
+ signer: string;
22
+ timestamp: number;
23
+ }
24
+ export declare function useProfile({ address, name, fresh, }: {
25
+ address?: string;
26
+ name?: string;
27
+ fresh?: boolean;
28
+ }, options?: {
29
+ enabled?: boolean;
30
+ refetchInterval?: number;
31
+ staleTime?: number;
32
+ }): import("@tanstack/react-query").UseQueryResult<CombinedProfile, Error>;
33
+ export declare function useProfilePreference(): {
34
+ setPreference: (key: string, preferredType: string, signerAddress: string, signMessage: (message: string) => Promise<string>) => Promise<{
35
+ success: boolean;
36
+ }>;
37
+ };
38
+ export default useProfile;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useProfile = useProfile;
4
+ exports.useProfilePreference = useProfilePreference;
5
+ const react_query_1 = require("@tanstack/react-query");
6
+ const PROFILES_API_URL = "https://profiles.b3.fun";
7
+ async function fetchProfile({ address, name, fresh = false, }) {
8
+ if (!address && !name) {
9
+ throw new Error("Either address or name must be provided");
10
+ }
11
+ const params = new URLSearchParams();
12
+ if (address)
13
+ params.append("address", address);
14
+ if (name)
15
+ params.append("name", name);
16
+ if (fresh)
17
+ params.append("fresh", "true");
18
+ const response = await fetch(`${PROFILES_API_URL}?${params.toString()}`);
19
+ if (!response.ok) {
20
+ throw new Error(`Failed to fetch profile: ${response.statusText}`);
21
+ }
22
+ return response.json();
23
+ }
24
+ async function setProfilePreference({ key, preferredType, signature, signer, timestamp, }) {
25
+ const response = await fetch(`${PROFILES_API_URL}/preference`, {
26
+ method: "POST",
27
+ headers: {
28
+ "Content-Type": "application/json",
29
+ },
30
+ body: JSON.stringify({
31
+ key,
32
+ preferredType,
33
+ signature,
34
+ signer,
35
+ timestamp,
36
+ }),
37
+ });
38
+ if (!response.ok) {
39
+ throw new Error(`Failed to set preference: ${response.statusText}`);
40
+ }
41
+ return response.json();
42
+ }
43
+ function useProfile({ address, name, fresh = false, }, options) {
44
+ return (0, react_query_1.useQuery)({
45
+ queryKey: ["profile", address || name, fresh],
46
+ queryFn: () => fetchProfile({ address, name, fresh }),
47
+ enabled: (options?.enabled ?? true) && (!!address || !!name),
48
+ refetchInterval: options?.refetchInterval,
49
+ staleTime: options?.staleTime ?? 5 * 60 * 1000, // 5 minutes default
50
+ });
51
+ }
52
+ function useProfilePreference() {
53
+ const setPreference = async (key, preferredType, signerAddress, signMessage) => {
54
+ const timestamp = Math.floor(Date.now() / 1000);
55
+ const message = `SetProfilePreference:${key}:${preferredType}:${timestamp}`;
56
+ try {
57
+ const signature = await signMessage(message);
58
+ return setProfilePreference({
59
+ key,
60
+ preferredType,
61
+ signature,
62
+ signer: signerAddress,
63
+ timestamp,
64
+ });
65
+ }
66
+ catch (error) {
67
+ throw new Error(`Failed to set profile preference: ${error}`);
68
+ }
69
+ };
70
+ return { setPreference };
71
+ }
72
+ exports.default = useProfile;
@@ -363,7 +363,7 @@ export function AnySpendCustom({ isMainnet = true, loadOrder, mode = "modal", re
363
363
  const historyView = (_jsx("div", { className: cn("mx-auto flex w-full max-w-2xl flex-col items-center p-5", mode === "modal" && "bg-b3-react-background"), children: _jsx(OrderHistory, { mode: mode, onBack: () => {
364
364
  setActivePanel(PanelView.HISTORY);
365
365
  }, onSelectOrder: onSelectOrder }) }));
366
- const orderDetailsView = (_jsxs("div", { className: cn("mx-auto flex max-h-[90dvh] w-full flex-col items-center gap-4 overflow-y-auto p-5", mode === "modal" && "bg-b3-react-background"), children: [oat && (_jsxs(_Fragment, { children: [_jsx(OrderStatusDisplay, { order: oat.data.order }), _jsx(OrderDetails, { isMainnet: isMainnet, mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, onBack: () => {
366
+ const orderDetailsView = (_jsxs("div", { className: cn("mx-auto flex w-full flex-col items-center gap-4 p-5", mode === "modal" && "bg-b3-react-background"), children: [oat && (_jsxs(_Fragment, { children: [_jsx(OrderStatusDisplay, { order: oat.data.order }), _jsx(OrderDetails, { isMainnet: isMainnet, mode: mode, order: oat.data.order, depositTxs: oat.data.depositTxs, relayTx: oat.data.relayTx, executeTx: oat.data.executeTx, refundTxs: oat.data.refundTxs, onBack: () => {
367
367
  setOrderId(undefined);
368
368
  setActivePanel(PanelView.CONFIRM_ORDER);
369
369
  // Remove orderId from URL when canceling