@mantle-rwa/react 0.1.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.
- package/dist/cjs/components/InvestorDashboard/index.js +156 -0
- package/dist/cjs/components/InvestorDashboard/index.js.map +1 -0
- package/dist/cjs/components/KYCFlow/index.js +231 -0
- package/dist/cjs/components/KYCFlow/index.js.map +1 -0
- package/dist/cjs/components/TokenMintForm/index.js +286 -0
- package/dist/cjs/components/TokenMintForm/index.js.map +1 -0
- package/dist/cjs/components/YieldCalculator/index.js +245 -0
- package/dist/cjs/components/YieldCalculator/index.js.map +1 -0
- package/dist/cjs/components/index.js +15 -0
- package/dist/cjs/components/index.js.map +1 -0
- package/dist/cjs/hooks/index.js +9 -0
- package/dist/cjs/hooks/index.js.map +1 -0
- package/dist/cjs/hooks/useRWA.js +54 -0
- package/dist/cjs/hooks/useRWA.js.map +1 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/types/index.js +10 -0
- package/dist/cjs/types/index.js.map +1 -0
- package/dist/esm/components/InvestorDashboard/index.js +153 -0
- package/dist/esm/components/InvestorDashboard/index.js.map +1 -0
- package/dist/esm/components/KYCFlow/index.js +228 -0
- package/dist/esm/components/KYCFlow/index.js.map +1 -0
- package/dist/esm/components/TokenMintForm/index.js +279 -0
- package/dist/esm/components/TokenMintForm/index.js.map +1 -0
- package/dist/esm/components/YieldCalculator/index.js +236 -0
- package/dist/esm/components/YieldCalculator/index.js.map +1 -0
- package/dist/esm/components/index.js +8 -0
- package/dist/esm/components/index.js.map +1 -0
- package/dist/esm/hooks/index.js +5 -0
- package/dist/esm/hooks/index.js.map +1 -0
- package/dist/esm/hooks/useRWA.js +51 -0
- package/dist/esm/hooks/useRWA.js.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types/index.js +6 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/types/components/InvestorDashboard/index.d.ts +25 -0
- package/dist/types/components/InvestorDashboard/index.d.ts.map +1 -0
- package/dist/types/components/KYCFlow/index.d.ts +25 -0
- package/dist/types/components/KYCFlow/index.d.ts.map +1 -0
- package/dist/types/components/TokenMintForm/index.d.ts +60 -0
- package/dist/types/components/TokenMintForm/index.d.ts.map +1 -0
- package/dist/types/components/YieldCalculator/index.d.ts +59 -0
- package/dist/types/components/YieldCalculator/index.d.ts.map +1 -0
- package/dist/types/components/index.d.ts +8 -0
- package/dist/types/components/index.d.ts.map +1 -0
- package/dist/types/hooks/index.d.ts +5 -0
- package/dist/types/hooks/index.d.ts.map +1 -0
- package/dist/types/hooks/useRWA.d.ts +22 -0
- package/dist/types/hooks/useRWA.d.ts.map +1 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +177 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/package.json +66 -0
- package/src/components/InvestorDashboard/index.tsx +359 -0
- package/src/components/KYCFlow/index.tsx +434 -0
- package/src/components/TokenMintForm/index.tsx +590 -0
- package/src/components/YieldCalculator/index.tsx +541 -0
- package/src/components/index.ts +8 -0
- package/src/hooks/index.ts +5 -0
- package/src/hooks/useRWA.ts +70 -0
- package/src/index.ts +32 -0
- package/src/styles/index.css +197 -0
- package/src/types/index.ts +193 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KYCFlow Component
|
|
3
|
+
* Multi-step KYC verification flow with provider integration
|
|
4
|
+
*
|
|
5
|
+
* @see Requirements 10.1, 10.2, 10.3, 10.4, 10.5
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
|
9
|
+
import type { KYCFlowProps, KYCResult, KYCRequiredField } from '../../types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Verification step status
|
|
13
|
+
*/
|
|
14
|
+
type StepStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Verification step definition
|
|
18
|
+
*/
|
|
19
|
+
interface VerificationStep {
|
|
20
|
+
id: KYCRequiredField;
|
|
21
|
+
label: string;
|
|
22
|
+
description: string;
|
|
23
|
+
status: StepStatus;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Provider configuration
|
|
28
|
+
*/
|
|
29
|
+
interface ProviderConfig {
|
|
30
|
+
name: string;
|
|
31
|
+
displayName: string;
|
|
32
|
+
logo: string;
|
|
33
|
+
description: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const PROVIDER_CONFIGS: Record<string, ProviderConfig> = {
|
|
37
|
+
persona: {
|
|
38
|
+
name: 'persona',
|
|
39
|
+
displayName: 'Persona',
|
|
40
|
+
logo: '🔐',
|
|
41
|
+
description: 'Identity verification powered by Persona',
|
|
42
|
+
},
|
|
43
|
+
synaps: {
|
|
44
|
+
name: 'synaps',
|
|
45
|
+
displayName: 'Synaps',
|
|
46
|
+
logo: '🛡️',
|
|
47
|
+
description: 'KYC verification powered by Synaps',
|
|
48
|
+
},
|
|
49
|
+
jumio: {
|
|
50
|
+
name: 'jumio',
|
|
51
|
+
displayName: 'Jumio',
|
|
52
|
+
logo: '✓',
|
|
53
|
+
description: 'Identity verification powered by Jumio',
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const FIELD_LABELS: Record<KYCRequiredField, { label: string; description: string }> = {
|
|
58
|
+
identity: {
|
|
59
|
+
label: 'Identity Verification',
|
|
60
|
+
description: 'Verify your identity with a government-issued ID',
|
|
61
|
+
},
|
|
62
|
+
accreditation: {
|
|
63
|
+
label: 'Accreditation Status',
|
|
64
|
+
description: 'Confirm your investor accreditation status',
|
|
65
|
+
},
|
|
66
|
+
address: {
|
|
67
|
+
label: 'Address Verification',
|
|
68
|
+
description: 'Verify your residential address',
|
|
69
|
+
},
|
|
70
|
+
tax: {
|
|
71
|
+
label: 'Tax Information',
|
|
72
|
+
description: 'Provide tax identification information',
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* KYCFlow component for investor verification
|
|
78
|
+
* Supports Persona, Synaps, and Jumio providers
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```tsx
|
|
82
|
+
* <KYCFlow
|
|
83
|
+
* provider="persona"
|
|
84
|
+
* requiredFields={['identity', 'accreditation']}
|
|
85
|
+
* onComplete={(result) => console.log('KYC complete:', result)}
|
|
86
|
+
* theme="light"
|
|
87
|
+
* />
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export function KYCFlow({
|
|
91
|
+
provider,
|
|
92
|
+
onComplete,
|
|
93
|
+
onError,
|
|
94
|
+
requiredFields,
|
|
95
|
+
theme = 'light',
|
|
96
|
+
customStyles,
|
|
97
|
+
registryAddress,
|
|
98
|
+
autoUpdateRegistry = false,
|
|
99
|
+
}: KYCFlowProps): React.ReactElement {
|
|
100
|
+
const [currentStepIndex, setCurrentStepIndex] = useState(0);
|
|
101
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
102
|
+
const [error, setError] = useState<string | null>(null);
|
|
103
|
+
const [sessionId, setSessionId] = useState<string | null>(null);
|
|
104
|
+
const [verificationStarted, setVerificationStarted] = useState(false);
|
|
105
|
+
|
|
106
|
+
const isDark = theme === 'dark';
|
|
107
|
+
const providerConfig = PROVIDER_CONFIGS[provider];
|
|
108
|
+
|
|
109
|
+
// Initialize steps based on required fields
|
|
110
|
+
const [steps, setSteps] = useState<VerificationStep[]>(() =>
|
|
111
|
+
requiredFields.map((field) => ({
|
|
112
|
+
id: field,
|
|
113
|
+
label: FIELD_LABELS[field].label,
|
|
114
|
+
description: FIELD_LABELS[field].description,
|
|
115
|
+
status: 'pending' as StepStatus,
|
|
116
|
+
}))
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Reset steps when requiredFields change
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
setSteps(
|
|
122
|
+
requiredFields.map((field) => ({
|
|
123
|
+
id: field,
|
|
124
|
+
label: FIELD_LABELS[field].label,
|
|
125
|
+
description: FIELD_LABELS[field].description,
|
|
126
|
+
status: 'pending' as StepStatus,
|
|
127
|
+
}))
|
|
128
|
+
);
|
|
129
|
+
setCurrentStepIndex(0);
|
|
130
|
+
setVerificationStarted(false);
|
|
131
|
+
setSessionId(null);
|
|
132
|
+
setError(null);
|
|
133
|
+
}, [requiredFields]);
|
|
134
|
+
|
|
135
|
+
const currentStep = steps[currentStepIndex];
|
|
136
|
+
const isLastStep = currentStepIndex === steps.length - 1;
|
|
137
|
+
const allStepsCompleted = steps.every((step) => step.status === 'completed');
|
|
138
|
+
|
|
139
|
+
// Update step status
|
|
140
|
+
const updateStepStatus = useCallback((stepIndex: number, status: StepStatus) => {
|
|
141
|
+
setSteps((prev) =>
|
|
142
|
+
prev.map((step, idx) => (idx === stepIndex ? { ...step, status } : step))
|
|
143
|
+
);
|
|
144
|
+
}, []);
|
|
145
|
+
|
|
146
|
+
// Start verification flow
|
|
147
|
+
const handleStartVerification = useCallback(async () => {
|
|
148
|
+
setIsLoading(true);
|
|
149
|
+
setError(null);
|
|
150
|
+
setVerificationStarted(true);
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// Generate session ID for this verification flow
|
|
154
|
+
const newSessionId = `${provider}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
155
|
+
setSessionId(newSessionId);
|
|
156
|
+
|
|
157
|
+
// Mark first step as in progress
|
|
158
|
+
updateStepStatus(0, 'in_progress');
|
|
159
|
+
|
|
160
|
+
// Simulate provider initialization
|
|
161
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
162
|
+
} catch (err) {
|
|
163
|
+
const errorMessage = err instanceof Error ? err.message : 'Failed to start verification';
|
|
164
|
+
setError(errorMessage);
|
|
165
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
166
|
+
setVerificationStarted(false);
|
|
167
|
+
} finally {
|
|
168
|
+
setIsLoading(false);
|
|
169
|
+
}
|
|
170
|
+
}, [provider, onError, updateStepStatus]);
|
|
171
|
+
|
|
172
|
+
// Complete current step and move to next
|
|
173
|
+
const handleCompleteStep = useCallback(async () => {
|
|
174
|
+
setIsLoading(true);
|
|
175
|
+
setError(null);
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
// Simulate step completion
|
|
179
|
+
await new Promise((resolve) => setTimeout(resolve, 800));
|
|
180
|
+
|
|
181
|
+
// Mark current step as completed
|
|
182
|
+
updateStepStatus(currentStepIndex, 'completed');
|
|
183
|
+
|
|
184
|
+
if (!isLastStep) {
|
|
185
|
+
// Move to next step
|
|
186
|
+
const nextIndex = currentStepIndex + 1;
|
|
187
|
+
setCurrentStepIndex(nextIndex);
|
|
188
|
+
updateStepStatus(nextIndex, 'in_progress');
|
|
189
|
+
}
|
|
190
|
+
} catch (err) {
|
|
191
|
+
const errorMessage = err instanceof Error ? err.message : 'Step verification failed';
|
|
192
|
+
setError(errorMessage);
|
|
193
|
+
updateStepStatus(currentStepIndex, 'failed');
|
|
194
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
195
|
+
} finally {
|
|
196
|
+
setIsLoading(false);
|
|
197
|
+
}
|
|
198
|
+
}, [currentStepIndex, isLastStep, onError, updateStepStatus]);
|
|
199
|
+
|
|
200
|
+
// Complete entire verification flow
|
|
201
|
+
const handleCompleteVerification = useCallback(async () => {
|
|
202
|
+
setIsLoading(true);
|
|
203
|
+
setError(null);
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
// Complete the last step first
|
|
207
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
208
|
+
updateStepStatus(currentStepIndex, 'completed');
|
|
209
|
+
|
|
210
|
+
// Determine tier based on accreditation field
|
|
211
|
+
const hasAccreditation = requiredFields.includes('accreditation');
|
|
212
|
+
const tier = hasAccreditation ? 2 : 1; // Accredited (2) or Retail (1)
|
|
213
|
+
|
|
214
|
+
// Generate identity hash
|
|
215
|
+
const identityHash = '0x' + Array.from({ length: 64 }, () =>
|
|
216
|
+
Math.floor(Math.random() * 16).toString(16)
|
|
217
|
+
).join('');
|
|
218
|
+
|
|
219
|
+
const result: KYCResult = {
|
|
220
|
+
verified: true,
|
|
221
|
+
tier,
|
|
222
|
+
identityHash,
|
|
223
|
+
sessionId: sessionId || `${provider}-${Date.now()}`,
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// Auto-update registry if configured
|
|
227
|
+
if (autoUpdateRegistry && registryAddress) {
|
|
228
|
+
// In production, this would call the SDK to update the on-chain registry
|
|
229
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
onComplete(result);
|
|
233
|
+
} catch (err) {
|
|
234
|
+
const errorMessage = err instanceof Error ? err.message : 'Verification completion failed';
|
|
235
|
+
setError(errorMessage);
|
|
236
|
+
updateStepStatus(currentStepIndex, 'failed');
|
|
237
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
238
|
+
} finally {
|
|
239
|
+
setIsLoading(false);
|
|
240
|
+
}
|
|
241
|
+
}, [
|
|
242
|
+
currentStepIndex,
|
|
243
|
+
requiredFields,
|
|
244
|
+
sessionId,
|
|
245
|
+
provider,
|
|
246
|
+
autoUpdateRegistry,
|
|
247
|
+
registryAddress,
|
|
248
|
+
onComplete,
|
|
249
|
+
onError,
|
|
250
|
+
updateStepStatus,
|
|
251
|
+
]);
|
|
252
|
+
|
|
253
|
+
// Retry failed step
|
|
254
|
+
const handleRetry = useCallback(() => {
|
|
255
|
+
setError(null);
|
|
256
|
+
updateStepStatus(currentStepIndex, 'in_progress');
|
|
257
|
+
}, [currentStepIndex, updateStepStatus]);
|
|
258
|
+
|
|
259
|
+
// Style classes
|
|
260
|
+
const containerClass = useMemo(
|
|
261
|
+
() => customStyles?.container ?? `rwa-kyc-flow ${isDark ? 'dark' : ''}`,
|
|
262
|
+
[customStyles?.container, isDark]
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
const headerClass = useMemo(
|
|
266
|
+
() => customStyles?.header ?? 'rwa-kyc-header',
|
|
267
|
+
[customStyles?.header]
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
const buttonClass = useMemo(
|
|
271
|
+
() => customStyles?.button ?? 'rwa-button-primary',
|
|
272
|
+
[customStyles?.button]
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
// Render step indicator
|
|
276
|
+
const renderStepIndicator = () => (
|
|
277
|
+
<div className="rwa-kyc-steps" role="list" aria-label="Verification steps">
|
|
278
|
+
{steps.map((step, index) => (
|
|
279
|
+
<div
|
|
280
|
+
key={step.id}
|
|
281
|
+
className={`rwa-kyc-step ${step.status}`}
|
|
282
|
+
role="listitem"
|
|
283
|
+
aria-current={index === currentStepIndex ? 'step' : undefined}
|
|
284
|
+
>
|
|
285
|
+
<div className="rwa-kyc-step-indicator">
|
|
286
|
+
{step.status === 'completed' ? (
|
|
287
|
+
<span aria-hidden="true">✓</span>
|
|
288
|
+
) : step.status === 'failed' ? (
|
|
289
|
+
<span aria-hidden="true">✗</span>
|
|
290
|
+
) : (
|
|
291
|
+
<span aria-hidden="true">{index + 1}</span>
|
|
292
|
+
)}
|
|
293
|
+
</div>
|
|
294
|
+
<div className="rwa-kyc-step-content">
|
|
295
|
+
<span className="rwa-kyc-step-label">{step.label}</span>
|
|
296
|
+
{index === currentStepIndex && verificationStarted && (
|
|
297
|
+
<span className="rwa-kyc-step-description">{step.description}</span>
|
|
298
|
+
)}
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
))}
|
|
302
|
+
</div>
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
// Render provider info
|
|
306
|
+
const renderProviderInfo = () => (
|
|
307
|
+
<div className="rwa-kyc-provider" data-testid="kyc-provider-info">
|
|
308
|
+
<span className="rwa-kyc-provider-logo" aria-hidden="true">
|
|
309
|
+
{providerConfig.logo}
|
|
310
|
+
</span>
|
|
311
|
+
<div className="rwa-kyc-provider-details">
|
|
312
|
+
<span className="rwa-kyc-provider-name">{providerConfig.displayName}</span>
|
|
313
|
+
<span className="rwa-kyc-provider-description">{providerConfig.description}</span>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// Render action buttons
|
|
319
|
+
const renderActions = () => {
|
|
320
|
+
if (!verificationStarted) {
|
|
321
|
+
return (
|
|
322
|
+
<button
|
|
323
|
+
type="button"
|
|
324
|
+
className={buttonClass}
|
|
325
|
+
onClick={handleStartVerification}
|
|
326
|
+
disabled={isLoading}
|
|
327
|
+
aria-busy={isLoading}
|
|
328
|
+
data-testid="start-verification-btn"
|
|
329
|
+
>
|
|
330
|
+
{isLoading ? 'Starting...' : 'Start Verification'}
|
|
331
|
+
</button>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (currentStep?.status === 'failed') {
|
|
336
|
+
return (
|
|
337
|
+
<button
|
|
338
|
+
type="button"
|
|
339
|
+
className={buttonClass}
|
|
340
|
+
onClick={handleRetry}
|
|
341
|
+
disabled={isLoading}
|
|
342
|
+
data-testid="retry-btn"
|
|
343
|
+
>
|
|
344
|
+
Retry Step
|
|
345
|
+
</button>
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (allStepsCompleted) {
|
|
350
|
+
return (
|
|
351
|
+
<div className="rwa-kyc-success" role="status">
|
|
352
|
+
<span className="rwa-kyc-success-icon" aria-hidden="true">✓</span>
|
|
353
|
+
<span>Verification Complete</span>
|
|
354
|
+
</div>
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (isLastStep) {
|
|
359
|
+
return (
|
|
360
|
+
<button
|
|
361
|
+
type="button"
|
|
362
|
+
className={buttonClass}
|
|
363
|
+
onClick={handleCompleteVerification}
|
|
364
|
+
disabled={isLoading}
|
|
365
|
+
aria-busy={isLoading}
|
|
366
|
+
data-testid="complete-verification-btn"
|
|
367
|
+
>
|
|
368
|
+
{isLoading ? 'Completing...' : 'Complete Verification'}
|
|
369
|
+
</button>
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return (
|
|
374
|
+
<button
|
|
375
|
+
type="button"
|
|
376
|
+
className={buttonClass}
|
|
377
|
+
onClick={handleCompleteStep}
|
|
378
|
+
disabled={isLoading}
|
|
379
|
+
aria-busy={isLoading}
|
|
380
|
+
data-testid="next-step-btn"
|
|
381
|
+
>
|
|
382
|
+
{isLoading ? 'Verifying...' : 'Continue'}
|
|
383
|
+
</button>
|
|
384
|
+
);
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
return (
|
|
388
|
+
<div
|
|
389
|
+
className={containerClass}
|
|
390
|
+
data-testid="kyc-flow"
|
|
391
|
+
data-provider={provider}
|
|
392
|
+
data-theme={theme}
|
|
393
|
+
role="form"
|
|
394
|
+
aria-label="KYC Verification Flow"
|
|
395
|
+
>
|
|
396
|
+
<h2 className={headerClass}>
|
|
397
|
+
{allStepsCompleted
|
|
398
|
+
? 'Verification Complete'
|
|
399
|
+
: verificationStarted
|
|
400
|
+
? `Step ${currentStepIndex + 1} of ${steps.length}: ${currentStep?.label}`
|
|
401
|
+
: 'Identity Verification'}
|
|
402
|
+
</h2>
|
|
403
|
+
|
|
404
|
+
{error && (
|
|
405
|
+
<div
|
|
406
|
+
className="rwa-kyc-error"
|
|
407
|
+
role="alert"
|
|
408
|
+
aria-live="polite"
|
|
409
|
+
data-testid="kyc-error"
|
|
410
|
+
>
|
|
411
|
+
<span className="rwa-kyc-error-icon" aria-hidden="true">⚠</span>
|
|
412
|
+
<span>{error}</span>
|
|
413
|
+
</div>
|
|
414
|
+
)}
|
|
415
|
+
|
|
416
|
+
{renderProviderInfo()}
|
|
417
|
+
{renderStepIndicator()}
|
|
418
|
+
|
|
419
|
+
<div className="rwa-kyc-actions">
|
|
420
|
+
{renderActions()}
|
|
421
|
+
</div>
|
|
422
|
+
|
|
423
|
+
{sessionId && (
|
|
424
|
+
<div className="rwa-kyc-session" data-testid="session-info">
|
|
425
|
+
<span className="text-xs text-gray-500 dark:text-gray-400">
|
|
426
|
+
Session: {sessionId.slice(0, 20)}...
|
|
427
|
+
</span>
|
|
428
|
+
</div>
|
|
429
|
+
)}
|
|
430
|
+
</div>
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export default KYCFlow;
|