@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.
- package/dist/index.d.mts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +156 -106
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +139 -88
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.d.mts +62 -52
- package/dist/react/index.d.ts +62 -52
- package/dist/react/index.js +901 -227
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +884 -203
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/styles.css +1 -168
- package/package.json +33 -10
- package/dist/react/components/PaymentButton.tsx +0 -119
- package/dist/react/components/WalletConnect.tsx +0 -152
- package/dist/react/hooks/usePayment.ts +0 -109
- package/dist/react/hooks/usePaymentInfo.ts +0 -94
- package/dist/react/hooks/useWallet.ts +0 -174
- package/dist/react/hooks/useWalletStore.ts +0 -61
- package/dist/react/index.ts +0 -42
- package/dist/react/store/walletStore.ts +0 -181
- package/dist/react/styles/inline-styles.ts +0 -227
package/dist/react/styles.css
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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": "
|
|
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
|
-
"
|
|
48
|
-
"@solana/web3.js": "^1.95.0",
|
|
57
|
+
"@ant-design/icons": "^5.0.0",
|
|
49
58
|
"@solana/spl-token": "^0.4.0",
|
|
50
|
-
"
|
|
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
|
-
|