@diviswap/sdk 1.7.6

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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +510 -0
  3. package/bin/create-diviswap-app.js +25 -0
  4. package/bin/diviswap-sdk.js +4 -0
  5. package/dist/cli/index.js +1888 -0
  6. package/dist/cli/templates/nextjs-app/actions.ts.hbs +259 -0
  7. package/dist/cli/templates/nextjs-app/api-hooks.ts.hbs +439 -0
  8. package/dist/cli/templates/nextjs-app/api-route.ts.hbs +502 -0
  9. package/dist/cli/templates/nextjs-app/auth-context.tsx.hbs +59 -0
  10. package/dist/cli/templates/nextjs-app/client.ts.hbs +116 -0
  11. package/dist/cli/templates/nextjs-app/dashboard-hooks.ts.hbs +180 -0
  12. package/dist/cli/templates/nextjs-app/example-page.tsx.hbs +276 -0
  13. package/dist/cli/templates/nextjs-app/hooks.ts.hbs +252 -0
  14. package/dist/cli/templates/nextjs-app/kyc-hooks.ts.hbs +87 -0
  15. package/dist/cli/templates/nextjs-app/kyc-wizard.css.hbs +433 -0
  16. package/dist/cli/templates/nextjs-app/kyc-wizard.tsx.hbs +711 -0
  17. package/dist/cli/templates/nextjs-app/layout-wrapper.tsx.hbs +13 -0
  18. package/dist/cli/templates/nextjs-app/layout.tsx.hbs +13 -0
  19. package/dist/cli/templates/nextjs-app/middleware.ts.hbs +49 -0
  20. package/dist/cli/templates/nextjs-app/provider-wrapper.tsx.hbs +8 -0
  21. package/dist/cli/templates/nextjs-app/provider.tsx.hbs +408 -0
  22. package/dist/cli/templates/nextjs-app/setup-provider.tsx.hbs +25 -0
  23. package/dist/cli/templates/nextjs-app/types.ts.hbs +159 -0
  24. package/dist/cli/templates/react/api-client-wrapper.ts.hbs +89 -0
  25. package/dist/cli/templates/react/example.tsx.hbs +69 -0
  26. package/dist/cli/templates/react/tanstack-hooks.ts.hbs +185 -0
  27. package/dist/cli/templates/webhooks/nextjs.hbs +98 -0
  28. package/dist/index.d.mts +91 -0
  29. package/dist/index.d.ts +91 -0
  30. package/dist/index.js +2339 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/index.mjs +2313 -0
  33. package/dist/index.mjs.map +1 -0
  34. package/dist/react/index.d.mts +192 -0
  35. package/dist/react/index.d.ts +192 -0
  36. package/dist/react/index.js +1083 -0
  37. package/dist/react/index.js.map +1 -0
  38. package/dist/react/index.mjs +1064 -0
  39. package/dist/react/index.mjs.map +1 -0
  40. package/dist/wallet-BEGvzNtB.d.mts +1614 -0
  41. package/dist/wallet-BEGvzNtB.d.ts +1614 -0
  42. package/package.json +102 -0
  43. package/src/cli/templates/index.ts +65 -0
  44. package/src/cli/templates/nextjs-app/actions.ts.hbs +259 -0
  45. package/src/cli/templates/nextjs-app/api-hooks.ts.hbs +439 -0
  46. package/src/cli/templates/nextjs-app/api-route.ts.hbs +502 -0
  47. package/src/cli/templates/nextjs-app/auth-context.tsx.hbs +59 -0
  48. package/src/cli/templates/nextjs-app/client.ts.hbs +116 -0
  49. package/src/cli/templates/nextjs-app/dashboard-hooks.ts.hbs +180 -0
  50. package/src/cli/templates/nextjs-app/example-page.tsx.hbs +276 -0
  51. package/src/cli/templates/nextjs-app/hooks.ts.hbs +252 -0
  52. package/src/cli/templates/nextjs-app/kyc-hooks.ts.hbs +87 -0
  53. package/src/cli/templates/nextjs-app/kyc-wizard.css.hbs +433 -0
  54. package/src/cli/templates/nextjs-app/kyc-wizard.tsx.hbs +711 -0
  55. package/src/cli/templates/nextjs-app/layout-wrapper.tsx.hbs +13 -0
  56. package/src/cli/templates/nextjs-app/layout.tsx.hbs +13 -0
  57. package/src/cli/templates/nextjs-app/middleware.ts.hbs +49 -0
  58. package/src/cli/templates/nextjs-app/provider-wrapper.tsx.hbs +8 -0
  59. package/src/cli/templates/nextjs-app/provider.tsx.hbs +408 -0
  60. package/src/cli/templates/nextjs-app/setup-provider.tsx.hbs +25 -0
  61. package/src/cli/templates/nextjs-app/types.ts.hbs +159 -0
  62. package/src/cli/templates/react/api-client-wrapper.ts.hbs +89 -0
  63. package/src/cli/templates/react/example.tsx.hbs +69 -0
  64. package/src/cli/templates/react/tanstack-hooks.ts.hbs +185 -0
  65. package/src/cli/templates/shared/client.ts +78 -0
  66. package/src/cli/templates/webhooks/nextjs.hbs +98 -0
@@ -0,0 +1,180 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import { use{{prefix}}Auth } from '~/context/diviswap-auth-context';
5
+
6
+ export function use{{prefix}}Dashboard() {
7
+ const { customerId, customerEmail, isAuthenticated } = use{{prefix}}Auth();
8
+
9
+ // API functions that include customer context
10
+ const getTransactions = async (params?: any) => {
11
+ if (!isAuthenticated || !customerId) return [];
12
+ const queryParams = new URLSearchParams({
13
+ resource: 'transactions',
14
+ customerId,
15
+ customerEmail,
16
+ ...params
17
+ });
18
+ const response = await fetch(`/api/diviswap?${queryParams}`);
19
+ if (!response.ok) throw new Error('Failed to fetch transactions');
20
+ return response.json();
21
+ };
22
+
23
+ const getPayees = async () => {
24
+ if (!isAuthenticated || !customerId) return [];
25
+ const response = await fetch(`/api/diviswap?resource=payees&customerId=${customerId}&customerEmail=${customerEmail}`);
26
+ if (!response.ok) throw new Error('Failed to fetch payees');
27
+ return response.json();
28
+ };
29
+
30
+ const getAddresses = async (params?: { chain_id?: number; is_default?: boolean }) => {
31
+ if (!isAuthenticated || !customerId) return [];
32
+ const queryParams = new URLSearchParams({
33
+ resource: 'addresses',
34
+ customerId,
35
+ customerEmail,
36
+ ...(params?.chain_id && { chain_id: params.chain_id.toString() }),
37
+ ...(params?.is_default !== undefined && { is_default: params.is_default.toString() })
38
+ });
39
+ const response = await fetch(`/api/diviswap?${queryParams}`);
40
+ if (!response.ok) throw new Error('Failed to fetch addresses');
41
+ return response.json();
42
+ };
43
+
44
+ const createAddress = async (data: { chain_id: number; address: string; is_default?: boolean }) => {
45
+ if (!isAuthenticated || !customerId) throw new Error('Not authenticated');
46
+ const response = await fetch('/api/diviswap', {
47
+ method: 'POST',
48
+ headers: { 'Content-Type': 'application/json' },
49
+ body: JSON.stringify({
50
+ action: 'createAddress',
51
+ customerId,
52
+ customerEmail,
53
+ ...data
54
+ })
55
+ });
56
+ if (!response.ok) throw new Error('Failed to create address');
57
+ return response.json();
58
+ };
59
+
60
+ const setDefaultAddress = async (data: { chain_id: number; address: string }) => {
61
+ if (!isAuthenticated || !customerId) throw new Error('Not authenticated');
62
+ const response = await fetch('/api/diviswap', {
63
+ method: 'POST',
64
+ headers: { 'Content-Type': 'application/json' },
65
+ body: JSON.stringify({
66
+ action: 'setDefaultAddress',
67
+ customerId,
68
+ customerEmail,
69
+ ...data
70
+ })
71
+ });
72
+ if (!response.ok) throw new Error('Failed to set default address');
73
+ return response.json();
74
+ };
75
+
76
+ const deleteAddress = async (data: { chain_id: number; address: string }) => {
77
+ if (!isAuthenticated || !customerId) throw new Error('Not authenticated');
78
+ const response = await fetch('/api/diviswap', {
79
+ method: 'POST',
80
+ headers: { 'Content-Type': 'application/json' },
81
+ body: JSON.stringify({
82
+ action: 'deleteAddress',
83
+ customerId,
84
+ customerEmail,
85
+ ...data
86
+ })
87
+ });
88
+ if (!response.ok) throw new Error('Failed to delete address');
89
+ return response.json();
90
+ };
91
+
92
+ const [loading, setLoading] = useState(true);
93
+ const [transactions, setTransactions] = useState<any[]>([]);
94
+ const [payees, setPayees] = useState<any[]>([]);
95
+ const [addresses, setAddresses] = useState<any[]>([]);
96
+
97
+ const [stats, setStats] = useState({
98
+ totalVolume: 0,
99
+ pendingTransactions: 0,
100
+ completedTransactions: 0,
101
+ failedTransactions: 0,
102
+ });
103
+
104
+ const [chartData, setChartData] = useState<any[]>([]);
105
+
106
+ useEffect(() => {
107
+ loadDashboardData();
108
+ }, []);
109
+
110
+ const loadDashboardData = async () => {
111
+ try {
112
+ setLoading(true);
113
+ const [txData, payeeData, addressData] = await Promise.all([
114
+ getTransactions({ limit: 50 }),
115
+ getPayees(),
116
+ getAddresses()
117
+ ]);
118
+
119
+ setTransactions(txData || []);
120
+ setPayees(payeeData || []);
121
+ setAddresses(addressData || []);
122
+
123
+ // Calculate stats
124
+ if (txData && txData.length > 0) {
125
+ const totalVolume = txData.reduce((sum: number, tx: any) => sum + (tx.amount || 0), 0);
126
+ const pendingTransactions = txData.filter((tx: any) => tx.status === 'pending').length;
127
+ const completedTransactions = txData.filter((tx: any) => tx.status === 'completed').length;
128
+ const failedTransactions = txData.filter((tx: any) => tx.status === 'failed').length;
129
+
130
+ setStats({
131
+ totalVolume,
132
+ pendingTransactions,
133
+ completedTransactions,
134
+ failedTransactions,
135
+ });
136
+
137
+ // Prepare chart data (last 7 days)
138
+ const last7Days = Array.from({ length: 7 }, (_, i) => {
139
+ const date = new Date();
140
+ date.setDate(date.getDate() - (6 - i));
141
+ return date.toISOString().split('T')[0];
142
+ });
143
+
144
+ const dailyVolumes = last7Days.map(date => {
145
+ const dayTransactions = txData.filter((tx: any) =>
146
+ tx.createdAt && new Date(tx.createdAt).toISOString().split('T')[0] === date
147
+ );
148
+ const volume = dayTransactions.reduce((sum: number, tx: any) => sum + (tx.amount || 0), 0);
149
+
150
+ return {
151
+ date: new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }),
152
+ volume: volume / 100, // Convert cents to dollars
153
+ transactions: dayTransactions.length,
154
+ };
155
+ });
156
+
157
+ setChartData(dailyVolumes);
158
+ }
159
+ } catch (error) {
160
+ console.error('Error loading dashboard data:', error);
161
+ } finally {
162
+ setLoading(false);
163
+ }
164
+ };
165
+
166
+ return {
167
+ stats,
168
+ chartData,
169
+ transactions: transactions.slice(0, 5), // Recent 5 transactions
170
+ payees,
171
+ addresses,
172
+ loading,
173
+ refresh: loadDashboardData,
174
+ // Address management functions
175
+ getAddresses,
176
+ createAddress,
177
+ setDefaultAddress,
178
+ deleteAddress,
179
+ };
180
+ }
@@ -0,0 +1,276 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { LiberexKYC, LiberexKYCModal } from '@/components/diviswap-kyc-wizard';
5
+ import '@/components/diviswap-kyc-wizard.css';
6
+
7
+ export default function DiviswapDemo() {
8
+ // Demo state
9
+ const [currentDemo, setCurrentDemo] = useState<'kyc-inline' | 'kyc-modal' | 'features'>('kyc-inline');
10
+ const [showKYCModal, setShowKYCModal] = useState(false);
11
+ const [kycResults, setKycResults] = useState<any[]>([]);
12
+ const [showSuccess, setShowSuccess] = useState(false);
13
+
14
+ const handleKYCSuccess = (result: any) => {
15
+ setKycResults(prev => [...prev, { ...result, timestamp: new Date().toISOString() }]);
16
+ setShowSuccess(true);
17
+
18
+ // Auto-hide success message after 3 seconds
19
+ setTimeout(() => setShowSuccess(false), 3000);
20
+ };
21
+
22
+ const handleKYCError = (error: Error) => {
23
+ alert(`KYC Error: ${error.message}`);
24
+ };
25
+
26
+ return (
27
+ <div className="min-h-screen bg-gray-50">
28
+ {/* Header */}
29
+ <div className="bg-white shadow">
30
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
31
+ <div className="flex justify-between items-center py-6">
32
+ <h1 className="text-2xl font-bold text-gray-900">Diviswap KYC Wizard Demo</h1>
33
+ <div className="text-sm text-gray-600">
34
+ Ready-to-use KYC component
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </div>
39
+
40
+ {/* Success Banner */}
41
+ {showSuccess && (
42
+ <div className="bg-green-50 border border-green-200 rounded-md p-4 mx-4 mt-4">
43
+ <div className="flex">
44
+ <div className="flex-shrink-0">
45
+ <svg className="h-5 w-5 text-green-400" fill="currentColor" viewBox="0 0 20 20">
46
+ <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
47
+ </svg>
48
+ </div>
49
+ <div className="ml-3">
50
+ <p className="text-sm font-medium text-green-800">
51
+ KYC completed successfully! Check the console for full details.
52
+ </p>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ )}
57
+
58
+ {/* Demo Navigation */}
59
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
60
+ <div className="flex space-x-1 mb-8">
61
+ <button
62
+ onClick={() => setCurrentDemo('kyc-inline')}
63
+ className={`flex-1 py-3 px-6 text-sm font-medium rounded-lg transition-colors ${
64
+ currentDemo === 'kyc-inline'
65
+ ? 'bg-indigo-100 text-indigo-700 border-2 border-indigo-200'
66
+ : 'text-gray-500 hover:text-gray-700 border-2 border-transparent'
67
+ }`}
68
+ >
69
+ 📝 Inline KYC Wizard
70
+ </button>
71
+ <button
72
+ onClick={() => setCurrentDemo('kyc-modal')}
73
+ className={`flex-1 py-3 px-6 text-sm font-medium rounded-lg transition-colors ${
74
+ currentDemo === 'kyc-modal'
75
+ ? 'bg-indigo-100 text-indigo-700 border-2 border-indigo-200'
76
+ : 'text-gray-500 hover:text-gray-700 border-2 border-transparent'
77
+ }`}
78
+ >
79
+ 🚀 Modal KYC Wizard
80
+ </button>
81
+ <button
82
+ onClick={() => setCurrentDemo('features')}
83
+ className={`flex-1 py-3 px-6 text-sm font-medium rounded-lg transition-colors ${
84
+ currentDemo === 'features'
85
+ ? 'bg-indigo-100 text-indigo-700 border-2 border-indigo-200'
86
+ : 'text-gray-500 hover:text-gray-700 border-2 border-transparent'
87
+ }`}
88
+ >
89
+ ✨ Features & Themes
90
+ </button>
91
+ </div>
92
+
93
+ {/* Inline KYC Demo */}
94
+ {currentDemo === 'kyc-inline' && (
95
+ <div className="space-y-6">
96
+ <div className="text-center">
97
+ <h2 className="text-xl font-semibold text-gray-900 mb-2">Inline KYC Wizard</h2>
98
+ <p className="text-gray-600 max-w-2xl mx-auto">
99
+ This is the KYC wizard component embedded directly in your page. Perfect for dedicated verification pages or onboarding flows.
100
+ </p>
101
+ </div>
102
+
103
+ <div className="max-w-4xl mx-auto">
104
+ <LiberexKYC
105
+ onSuccess={handleKYCSuccess}
106
+ onError={handleKYCError}
107
+ theme="light"
108
+ className="mx-auto"
109
+ />
110
+ </div>
111
+ </div>
112
+ )}
113
+
114
+ {/* Modal KYC Demo */}
115
+ {currentDemo === 'kyc-modal' && (
116
+ <div className="space-y-6">
117
+ <div className="text-center">
118
+ <h2 className="text-xl font-semibold text-gray-900 mb-2">Modal KYC Wizard</h2>
119
+ <p className="text-gray-600 max-w-2xl mx-auto mb-8">
120
+ Use the KYC wizard as a modal overlay. Perfect for prompting users to complete verification without leaving their current page.
121
+ </p>
122
+
123
+ <button
124
+ onClick={() => setShowKYCModal(true)}
125
+ className="inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
126
+ >
127
+ 🚀 Launch KYC Modal
128
+ </button>
129
+ </div>
130
+
131
+ <div className="bg-white rounded-lg p-8 text-center">
132
+ <h3 className="text-lg font-medium text-gray-900 mb-4">Integration Code</h3>
133
+ <div className="bg-gray-50 rounded-md p-4 text-left">
134
+ <pre className="text-sm text-gray-800 overflow-x-auto">
135
+ {`import { LiberexKYCModal } from '@/components/diviswap-kyc-wizard';
136
+
137
+ function MyComponent() {
138
+ const [showKYC, setShowKYC] = useState(false);
139
+
140
+ return (
141
+ <>
142
+ <button onClick={() => setShowKYC(true)}>
143
+ Complete Verification
144
+ </button>
145
+
146
+ <LiberexKYCModal
147
+ isOpen={showKYC}
148
+ onClose={() => setShowKYC(false)}
149
+ onSuccess={(result) => {
150
+ console.log('KYC completed!', result);
151
+ setShowKYC(false);
152
+ }}
153
+ />
154
+ </>
155
+ );
156
+ }`}
157
+ </pre>
158
+ </div>
159
+ </div>
160
+ </div>
161
+ )}
162
+
163
+ {/* Features Demo */}
164
+ {currentDemo === 'features' && (
165
+ <div className="space-y-8">
166
+ <div className="text-center">
167
+ <h2 className="text-xl font-semibold text-gray-900 mb-2">Features & Customization</h2>
168
+ <p className="text-gray-600 max-w-2xl mx-auto">
169
+ The KYC wizard supports themes, step customization, and various integration patterns.
170
+ </p>
171
+ </div>
172
+
173
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
174
+ {/* Features List */}
175
+ <div className="bg-white rounded-lg p-6 shadow">
176
+ <h3 className="text-lg font-medium text-gray-900 mb-4">✨ Key Features</h3>
177
+ <ul className="space-y-3 text-sm">
178
+ <li className="flex items-start">
179
+ <span className="flex-shrink-0 h-1.5 w-1.5 rounded-full bg-indigo-500 mt-2 mr-3"></span>
180
+ <span><strong>Multi-step wizard:</strong> Intro → Personal → ID → Address → Review → Success</span>
181
+ </li>
182
+ <li className="flex items-start">
183
+ <span className="flex-shrink-0 h-1.5 w-1.5 rounded-full bg-indigo-500 mt-2 mr-3"></span>
184
+ <span><strong>Full validation:</strong> Real-time form validation with helpful error messages</span>
185
+ </li>
186
+ <li className="flex items-start">
187
+ <span className="flex-shrink-0 h-1.5 w-1.5 rounded-full bg-indigo-500 mt-2 mr-3"></span>
188
+ <span><strong>Responsive design:</strong> Mobile-optimized with desktop support</span>
189
+ </li>
190
+ <li className="flex items-start">
191
+ <span className="flex-shrink-0 h-1.5 w-1.5 rounded-full bg-indigo-500 mt-2 mr-3"></span>
192
+ <span><strong>Theme support:</strong> Light/dark themes plus custom colors</span>
193
+ </li>
194
+ <li className="flex items-start">
195
+ <span className="flex-shrink-0 h-1.5 w-1.5 rounded-full bg-indigo-500 mt-2 mr-3"></span>
196
+ <span><strong>Progress tracking:</strong> Visual progress indicator throughout</span>
197
+ </li>
198
+ <li className="flex items-start">
199
+ <span className="flex-shrink-0 h-1.5 w-1.5 rounded-full bg-indigo-500 mt-2 mr-3"></span>
200
+ <span><strong>API integration:</strong> Works with your existing API routes</span>
201
+ </li>
202
+ </ul>
203
+ </div>
204
+
205
+ {/* Theme Examples */}
206
+ <div className="bg-white rounded-lg p-6 shadow">
207
+ <h3 className="text-lg font-medium text-gray-900 mb-4">🎨 Theme Options</h3>
208
+ <div className="space-y-4">
209
+ <div className="flex items-center space-x-3">
210
+ <div className="w-4 h-4 bg-white border-2 border-gray-300 rounded"></div>
211
+ <span className="text-sm">Light theme (default)</span>
212
+ </div>
213
+ <div className="flex items-center space-x-3">
214
+ <div className="w-4 h-4 bg-gray-800 rounded"></div>
215
+ <span className="text-sm">Dark theme</span>
216
+ </div>
217
+ <div className="flex items-center space-x-3">
218
+ <div className="w-4 h-4 bg-gradient-to-r from-purple-500 to-pink-500 rounded"></div>
219
+ <span className="text-sm">Custom colors</span>
220
+ </div>
221
+ </div>
222
+
223
+ <div className="mt-6 bg-gray-50 rounded p-3">
224
+ <p className="text-xs text-gray-600 mb-2">Custom theme example:</p>
225
+ <pre className="text-xs text-gray-800 overflow-x-auto">
226
+ {`<LiberexKYC
227
+ theme={{
228
+ primaryColor: '#8B5CF6',
229
+ backgroundColor: '#F8FAFC',
230
+ textColor: '#1E293B'
231
+ }}
232
+ />`}
233
+ </pre>
234
+ </div>
235
+ </div>
236
+ </div>
237
+
238
+ {/* Results Section */}
239
+ {kycResults.length > 0 && (
240
+ <div className="bg-white rounded-lg p-6 shadow">
241
+ <h3 className="text-lg font-medium text-gray-900 mb-4">📊 Recent Submissions</h3>
242
+ <div className="space-y-3">
243
+ {kycResults.slice(-3).map((result, index) => (
244
+ <div key={index} className="flex items-center justify-between p-3 bg-green-50 rounded-md">
245
+ <div>
246
+ <p className="text-sm font-medium text-green-800">KYC Submission #{kycResults.length - index}</p>
247
+ <p className="text-xs text-green-600">{new Date(result.timestamp).toLocaleString()}</p>
248
+ </div>
249
+ <div className="text-green-700">
250
+ <svg className="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
251
+ <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
252
+ </svg>
253
+ </div>
254
+ </div>
255
+ ))}
256
+ </div>
257
+ </div>
258
+ )}
259
+ </div>
260
+ )}
261
+ </div>
262
+
263
+ {/* KYC Modal */}
264
+ <LiberexKYCModal
265
+ isOpen={showKYCModal}
266
+ onClose={() => setShowKYCModal(false)}
267
+ onSuccess={(result) => {
268
+ handleKYCSuccess(result);
269
+ setShowKYCModal(false);
270
+ }}
271
+ onError={handleKYCError}
272
+ theme="light"
273
+ />
274
+ </div>
275
+ );
276
+ }