@voyage_ai/v402-web-ts 0.1.1 → 0.1.3

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.
@@ -1,168 +1 @@
1
- /**
2
- * x402 React Components - Default Styles
3
- *
4
- * ⚠️ DEPRECATED: This CSS file is no longer needed!
5
- *
6
- * All styles are now inline within the components.
7
- * You can safely remove any imports of this file:
8
- * - import '@voyage_ai/v402-web-ts/react/styles.css' ❌
9
- * - import '@voyage_ai/v402-web-ts/styles.css' ❌
10
- *
11
- * Just use the components directly - styles are built-in! ✅
12
- */
13
-
14
- .x402-wallet-connect {
15
- width: 100%;
16
- max-width: 500px;
17
- margin: 0 auto;
18
- }
19
-
20
- .x402-wallet-section,
21
- .x402-wallet-info {
22
- padding: 2rem;
23
- border: 1px solid #e0e0e0;
24
- border-radius: 8px;
25
- background: #ffffff;
26
- }
27
-
28
- .x402-section-title {
29
- margin: 0 0 1.5rem 0;
30
- font-size: 1.5rem;
31
- font-weight: 600;
32
- text-align: center;
33
- }
34
-
35
- .x402-wallet-buttons {
36
- display: flex;
37
- flex-direction: column;
38
- gap: 1rem;
39
- }
40
-
41
- .x402-wallet-option {
42
- display: flex;
43
- flex-direction: column;
44
- gap: 0.5rem;
45
- }
46
-
47
- .x402-connect-button,
48
- .x402-disconnect-button,
49
- .x402-pay-button {
50
- padding: 0.75rem 1.5rem;
51
- font-size: 1rem;
52
- font-weight: 500;
53
- border: none;
54
- border-radius: 6px;
55
- cursor: pointer;
56
- transition: all 0.2s;
57
- }
58
-
59
- .x402-connect-button {
60
- background: #0070f3;
61
- color: white;
62
- }
63
-
64
- .x402-connect-button:hover:not(:disabled) {
65
- background: #0051cc;
66
- }
67
-
68
- .x402-connect-button:disabled {
69
- background: #ccc;
70
- cursor: not-allowed;
71
- }
72
-
73
- .x402-disconnect-button {
74
- background: #ff4444;
75
- color: white;
76
- }
77
-
78
- .x402-disconnect-button:hover {
79
- background: #cc0000;
80
- }
81
-
82
- .x402-pay-button {
83
- background: #00d084;
84
- color: white;
85
- width: 100%;
86
- }
87
-
88
- .x402-pay-button:hover:not(:disabled) {
89
- background: #00a869;
90
- }
91
-
92
- .x402-pay-button:disabled {
93
- background: #ccc;
94
- cursor: not-allowed;
95
- }
96
-
97
- .x402-install-link {
98
- display: inline-block;
99
- padding: 0.5rem;
100
- font-size: 0.875rem;
101
- color: #0070f3;
102
- text-decoration: none;
103
- text-align: center;
104
- }
105
-
106
- .x402-install-link:hover {
107
- text-decoration: underline;
108
- }
109
-
110
- .x402-wallet-address {
111
- display: flex;
112
- flex-direction: column;
113
- gap: 0.5rem;
114
- margin-bottom: 1rem;
115
- }
116
-
117
- .x402-wallet-label {
118
- font-size: 0.875rem;
119
- color: #666;
120
- }
121
-
122
- .x402-address {
123
- font-family: monospace;
124
- font-size: 1rem;
125
- font-weight: 500;
126
- }
127
-
128
- .x402-wallet-actions {
129
- margin: 1rem 0;
130
- }
131
-
132
- .x402-hint {
133
- margin-top: 1rem;
134
- font-size: 0.875rem;
135
- color: #666;
136
- text-align: center;
137
- }
138
-
139
- .x402-error {
140
- margin-top: 1rem;
141
- padding: 0.75rem;
142
- background: #ffe0e0;
143
- color: #cc0000;
144
- border-radius: 4px;
145
- font-size: 0.875rem;
146
- }
147
-
148
- /* Dark mode support */
149
- @media (prefers-color-scheme: dark) {
150
- .x402-wallet-section,
151
- .x402-wallet-info {
152
- background: #1a1a1a;
153
- border-color: #333;
154
- }
155
-
156
- .x402-section-title {
157
- color: #fff;
158
- }
159
-
160
- .x402-wallet-label {
161
- color: #aaa;
162
- }
163
-
164
- .x402-hint {
165
- color: #aaa;
166
- }
167
- }
168
-
1
+ *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-screen{height:100vh}.w-10{width:2.5rem}.w-12{width:3rem}.w-16{width:4rem}.min-w-0{min-width:0}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.overflow-hidden{overflow:hidden}.break-all{word-break:break-all}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.bg-black{background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black,.bg-gray-50{--tw-bg-opacity:1}.bg-gray-50{background-color:rgb(249 250 251/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.text-center{text-align:center}.text-sm{font-size:.875rem;line-height:1.25rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.text-blue-600{color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-blue-600,.text-white{--tw-text-opacity:1}.text-white{color:rgb(255 255 255/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.opacity-40{opacity:.4}.outline{outline-style:solid}.blur-xl{--tw-blur:blur(24px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.hover\:text-blue-700:hover{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}
package/package.json CHANGED
@@ -1,28 +1,38 @@
1
1
  {
2
2
  "name": "@voyage_ai/v402-web-ts",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "v402pay platform frontend SDK for seamless Web3 payment integration with Solana and Ethereum support",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
+ "types": "./dist/index.d.ts",
10
11
  "import": "./dist/index.mjs",
11
- "require": "./dist/index.js",
12
- "types": "./dist/index.d.ts"
12
+ "require": "./dist/index.js"
13
13
  },
14
14
  "./react": {
15
+ "types": "./dist/react/index.d.ts",
16
+ "style": "./dist/react/styles.css",
15
17
  "import": "./dist/react/index.mjs",
16
- "require": "./dist/react/index.js",
17
- "types": "./dist/react/index.d.ts"
18
- }
18
+ "require": "./dist/react/index.js"
19
+ },
20
+ "./react/styles.css": "./dist/react/styles.css"
19
21
  },
22
+ "sideEffects": [
23
+ "*.css",
24
+ "dist/react/styles.css",
25
+ "dist/react/index.js",
26
+ "dist/react/index.mjs"
27
+ ],
20
28
  "files": [
21
29
  "dist",
22
30
  "README.md"
23
31
  ],
24
32
  "scripts": {
25
- "build": "tsup",
33
+ "build:css": "tailwindcss -i ./src/react/styles.css -o ./dist/react/styles.css --minify",
34
+ "build:js": "tsup",
35
+ "build": "npm run build:js && npm run build:css",
26
36
  "dev": "tsup --watch",
27
37
  "type-check": "tsc --noEmit",
28
38
  "prepublishOnly": "npm run build",
@@ -44,14 +54,22 @@
44
54
  "author": "",
45
55
  "license": "MIT",
46
56
  "peerDependencies": {
47
- "react": ">=18.0.0",
48
- "@solana/web3.js": "^1.95.0",
57
+ "@ant-design/icons": "^5.0.0",
49
58
  "@solana/spl-token": "^0.4.0",
50
- "ethers": "^6.0.0"
59
+ "@solana/web3.js": "^1.95.0",
60
+ "antd": "^5.0.0",
61
+ "ethers": "^6.0.0",
62
+ "react": ">=18.0.0"
51
63
  },
52
64
  "peerDependenciesMeta": {
53
65
  "react": {
54
66
  "optional": true
67
+ },
68
+ "antd": {
69
+ "optional": true
70
+ },
71
+ "@ant-design/icons": {
72
+ "optional": true
55
73
  }
56
74
  },
57
75
  "dependencies": {
@@ -59,8 +77,13 @@
59
77
  "zod": "^3.22.0"
60
78
  },
61
79
  "devDependencies": {
80
+ "@ant-design/icons": "^5.0.0",
62
81
  "@types/node": "^20.0.0",
63
82
  "@types/react": "^18.0.0",
83
+ "antd": "^5.0.0",
84
+ "autoprefixer": "^10.4.22",
85
+ "postcss": "^8.5.6",
86
+ "tailwindcss": "^3.4.18",
64
87
  "tsup": "^8.0.0",
65
88
  "typescript": "^5.0.0"
66
89
  }
@@ -1,119 +0,0 @@
1
- /**
2
- * PaymentButton Component
3
- *
4
- * Pre-built payment button component with inline styles
5
- * Note: This is a simple wrapper. For complex payment flows,
6
- * use the SDK directly with usePayment hook for full control.
7
- */
8
-
9
- 'use client';
10
-
11
- import React, {useState} from 'react';
12
- import {useWallet} from '../hooks/useWalletStore';
13
- import {usePayment} from '../hooks/usePayment';
14
- import {handlePayment} from '../../utils';
15
- import {getErrorStyle, getPayButtonStyle} from '../styles/inline-styles';
16
-
17
- export interface PaymentButtonProps {
18
- endpoint: string;
19
- className?: string;
20
- disabled?: boolean;
21
- onSuccess?: (result: any) => void;
22
- onError?: (error: string) => void;
23
- onStart?: () => void;
24
- onFinish?: () => void;
25
- children?: React.ReactNode;
26
- }
27
-
28
- /**
29
- * Simple pre-built payment button
30
- *
31
- * For complex payment flows, use the SDK directly:
32
- *
33
- * @example
34
- * ```tsx
35
- * import { useWallet, usePayment } from '../react';
36
- * import { handleSvmPayment } from '@/app/sdk';
37
- *
38
- * function CustomPayment() {
39
- * const { networkType } = useWallet();
40
- * const { isProcessing, setIsProcessing, setResult, setError } = usePayment();
41
- *
42
- * const handlePay = async () => {
43
- * setIsProcessing(true);
44
- * try {
45
- * // Your custom logic before payment
46
- * const response = await handleSvmPayment(...);
47
- * const data = await response.json();
48
- *
49
- * // Your custom logic after payment
50
- * setResult(data);
51
- * } catch (err) {
52
- * setError(err.message);
53
- * } finally {
54
- * setIsProcessing(false);
55
- * }
56
- * };
57
- * }
58
- * ```
59
- */
60
- export function PaymentButton({
61
- endpoint,
62
- className = '',
63
- disabled = false,
64
- onSuccess,
65
- onError,
66
- onStart,
67
- onFinish,
68
- children = 'Pay Now',
69
- }: PaymentButtonProps) {
70
- const {networkType} = useWallet();
71
- const {isProcessing, setIsProcessing, setResult, setError, error} = usePayment();
72
- const [isHovered, setIsHovered] = useState(false);
73
-
74
- const handleClick = async () => {
75
- if (!networkType) {
76
- const errorMsg = 'Please connect wallet first';
77
- setError(errorMsg);
78
- onError?.(errorMsg);
79
- return;
80
- }
81
-
82
- try {
83
- onStart?.();
84
- setIsProcessing(true);
85
- setError(null);
86
-
87
- const result = await handlePayment(endpoint, networkType);
88
-
89
- setResult(result);
90
- onSuccess?.(result);
91
- } catch (err: any) {
92
- const errorMsg = err.message || 'Payment failed';
93
- setError(errorMsg);
94
- onError?.(errorMsg);
95
- } finally {
96
- setIsProcessing(false);
97
- onFinish?.();
98
- }
99
- };
100
-
101
- const isDisabled = disabled || isProcessing || !networkType;
102
-
103
- return (
104
- <>
105
- <button
106
- style={getPayButtonStyle(isDisabled, isHovered)}
107
- className={className}
108
- onClick={handleClick}
109
- disabled={isDisabled}
110
- onMouseEnter={() => setIsHovered(true)}
111
- onMouseLeave={() => setIsHovered(false)}
112
- >
113
- {isProcessing ? 'Processing...' : children}
114
- </button>
115
- {error && <p style={getErrorStyle()}>{error}</p>}
116
- </>
117
- );
118
- }
119
-
@@ -1,152 +0,0 @@
1
- /**
2
- * WalletConnect Component
3
- *
4
- * Pre-built wallet connection UI component with inline styles
5
- */
6
-
7
- 'use client';
8
-
9
- import React, {useState} from 'react';
10
- import {NetworkType} from '../../types';
11
- import {formatAddress, getNetworkDisplayName, getWalletInstallUrl, isWalletInstalled,} from '../../utils';
12
- import {useWallet} from '../hooks/useWalletStore';
13
- import {
14
- buttonsContainerStyle,
15
- containerStyle,
16
- getAddressStyle,
17
- getConnectButtonStyle,
18
- getDisconnectButtonStyle,
19
- getErrorStyle,
20
- getHintStyle,
21
- getInstallLinkStyle,
22
- getLabelStyle,
23
- getSectionStyle,
24
- getTitleStyle,
25
- walletActionsStyle,
26
- walletAddressStyle,
27
- walletOptionStyle,
28
- } from '../styles/inline-styles';
29
-
30
- export interface WalletConnectProps {
31
- supportedNetworks?: NetworkType[];
32
- className?: string;
33
- onConnect?: (address: string, networkType: NetworkType) => void;
34
- onDisconnect?: () => void;
35
- }
36
-
37
- /**
38
- * Pre-built wallet connection component
39
- *
40
- * @example
41
- * ```tsx
42
- * import { WalletConnect } from '../react';
43
- *
44
- * function App() {
45
- * return (
46
- * <WalletConnect
47
- * supportedNetworks={[NetworkType.SOLANA, NetworkType.EVM]}
48
- * onConnect={(address, network) => console.log('Connected:', address)}
49
- * />
50
- * );
51
- * }
52
- * ```
53
- */
54
- export function WalletConnect({
55
- supportedNetworks = [NetworkType.SOLANA, NetworkType.EVM],
56
- className = '',
57
- onConnect,
58
- onDisconnect,
59
- }: WalletConnectProps) {
60
- const {address, networkType, isConnecting, error, connect, disconnect} = useWallet();
61
- const [hoveredButton, setHoveredButton] = useState<string | null>(null);
62
- const [hoveredLink, setHoveredLink] = useState<string | null>(null);
63
-
64
- const handleConnect = async (network: NetworkType) => {
65
- try {
66
- await connect(network);
67
- // Note: address state won't be updated yet due to async setState
68
- // The parent component will re-render when address updates
69
- } catch (err) {
70
- // Error is already set in hook
71
- }
72
- };
73
-
74
- const handleDisconnect = () => {
75
- disconnect();
76
- onDisconnect?.();
77
- };
78
-
79
- return (
80
- <div style={{ ...containerStyle, ...(className ? {} : {}) }} className={className}>
81
- {!address ? (
82
- <div style={getSectionStyle()}>
83
- <h3 style={getTitleStyle()}>Connect Wallet</h3>
84
-
85
- {supportedNetworks.length === 0 ? (
86
- <p style={getHintStyle()}>No payment required</p>
87
- ) : (
88
- <div style={buttonsContainerStyle}>
89
- {supportedNetworks.map((network) => {
90
- const installed = isWalletInstalled(network);
91
- return (
92
- <div key={network} style={walletOptionStyle}>
93
- <button
94
- style={getConnectButtonStyle(isConnecting || !installed, hoveredButton === network)}
95
- onClick={() => handleConnect(network)}
96
- disabled={isConnecting || !installed}
97
- onMouseEnter={() => setHoveredButton(network)}
98
- onMouseLeave={() => setHoveredButton(null)}
99
- >
100
- {isConnecting ? 'Connecting...' : getNetworkDisplayName(network)}
101
- </button>
102
- {!installed && (
103
- <a
104
- href={getWalletInstallUrl(network)}
105
- target="_blank"
106
- rel="noopener noreferrer"
107
- style={getInstallLinkStyle(hoveredLink === network)}
108
- onMouseEnter={() => setHoveredLink(network)}
109
- onMouseLeave={() => setHoveredLink(null)}
110
- >
111
- Install Wallet
112
- </a>
113
- )}
114
- </div>
115
- );
116
- })}
117
- </div>
118
- )}
119
-
120
- {error && <p style={getErrorStyle()}>{error}</p>}
121
-
122
- <p style={getHintStyle()}>
123
- To switch accounts, please change it in your wallet extension
124
- </p>
125
- </div>
126
- ) : (
127
- <div style={getSectionStyle()}>
128
- <div style={walletAddressStyle}>
129
- <span style={getLabelStyle()}>
130
- Connected {networkType && `(${getNetworkDisplayName(networkType)})`}
131
- </span>
132
- <span style={getAddressStyle()}>{formatAddress(address)}</span>
133
- </div>
134
- <div style={walletActionsStyle}>
135
- <button
136
- style={getDisconnectButtonStyle(hoveredButton === 'disconnect')}
137
- onClick={handleDisconnect}
138
- onMouseEnter={() => setHoveredButton('disconnect')}
139
- onMouseLeave={() => setHoveredButton(null)}
140
- >
141
- Disconnect
142
- </button>
143
- </div>
144
- <p style={getHintStyle()}>
145
- Switch account in your wallet to change address
146
- </p>
147
- </div>
148
- )}
149
- </div>
150
- );
151
- }
152
-
@@ -1,109 +0,0 @@
1
- /**
2
- * usePayment Hook
3
- *
4
- * React hook for payment state management
5
- * Provides state only - you control the payment flow
6
- */
7
-
8
- import {useCallback, useState} from 'react';
9
-
10
- export interface UsePaymentReturn {
11
- // State
12
- isProcessing: boolean;
13
- result: any;
14
- error: string | null;
15
-
16
- // State setters
17
- setIsProcessing: (value: boolean) => void;
18
- setResult: (value: any) => void;
19
- setError: (value: string | null) => void;
20
-
21
- // Helpers
22
- clearResult: () => void;
23
- clearError: () => void;
24
- reset: () => void;
25
- }
26
-
27
- /**
28
- * Hook for managing payment state
29
- *
30
- * This hook only manages state - you control the payment logic.
31
- * Use SDK's handleSvmPayment/handleEvmPayment directly for full control.
32
- *
33
- * @example
34
- * ```tsx
35
- * import { usePayment, useWallet } from '../react';
36
- * import { handleSvmPayment } from '@/app/sdk';
37
- *
38
- * function PaymentButton() {
39
- * const { networkType } = useWallet();
40
- * const { isProcessing, setIsProcessing, result, setResult, error, setError } = usePayment();
41
- *
42
- * const handlePay = async () => {
43
- * if (!networkType) return;
44
- *
45
- * setIsProcessing(true);
46
- * setError(null);
47
- *
48
- * try {
49
- * const response = await handleSvmPayment('/api/endpoint', {
50
- * wallet: window.solana,
51
- * network: 'solana-devnet',
52
- * });
53
- *
54
- * const data = await response.json();
55
- * setResult(data);
56
- *
57
- * // Your custom logic here
58
- * console.log('Payment success!');
59
- * } catch (err: any) {
60
- * setError(err.message);
61
- * } finally {
62
- * setIsProcessing(false);
63
- * }
64
- * };
65
- *
66
- * return (
67
- * <div>
68
- * <button onClick={handlePay} disabled={isProcessing}>
69
- * {isProcessing ? 'Processing...' : 'Pay'}
70
- * </button>
71
- * {error && <p>Error: {error}</p>}
72
- * {result && <pre>{JSON.stringify(result, null, 2)}</pre>}
73
- * </div>
74
- * );
75
- * }
76
- * ```
77
- */
78
- export function usePayment(): UsePaymentReturn {
79
- const [isProcessing, setIsProcessing] = useState(false);
80
- const [result, setResult] = useState<any>(null);
81
- const [error, setError] = useState<string | null>(null);
82
-
83
- const clearResult = useCallback(() => {
84
- setResult(null);
85
- }, []);
86
-
87
- const clearError = useCallback(() => {
88
- setError(null);
89
- }, []);
90
-
91
- const reset = useCallback(() => {
92
- setIsProcessing(false);
93
- setResult(null);
94
- setError(null);
95
- }, []);
96
-
97
- return {
98
- isProcessing,
99
- result,
100
- error,
101
- setIsProcessing,
102
- setResult,
103
- setError,
104
- clearResult,
105
- clearError,
106
- reset,
107
- };
108
- }
109
-