@casperid/react 1.0.1 → 1.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/_commonjsHelpers-DKOUU3wS.cjs +2 -0
- package/dist/_commonjsHelpers-DKOUU3wS.cjs.map +1 -0
- package/dist/_commonjsHelpers-DaMA6jEr.js +9 -0
- package/dist/_commonjsHelpers-DaMA6jEr.js.map +1 -0
- package/dist/camera_utils-BQaOSBPu.js +397 -0
- package/dist/camera_utils-BQaOSBPu.js.map +1 -0
- package/dist/camera_utils-wchtqrQn.cjs +2 -0
- package/dist/camera_utils-wchtqrQn.cjs.map +1 -0
- package/dist/face_mesh-DYMPc5Ce.js +4212 -0
- package/dist/face_mesh-DYMPc5Ce.js.map +1 -0
- package/dist/face_mesh-fEvyDoPt.cjs +19 -0
- package/dist/face_mesh-fEvyDoPt.cjs.map +1 -0
- package/dist/index.cjs +41 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1786 -1501
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +11 -11
- package/src/CasperIDModal.tsx +0 -777
- package/src/index.css +0 -217
- package/src/index.ts +0 -41
- package/src/screens/AuthSelection.tsx +0 -221
- package/src/screens/DocumentScan.tsx +0 -348
- package/src/screens/FaceScan.tsx +0 -368
- package/src/screens/IdentityVerified.tsx +0 -51
- package/src/screens/L1Setup.tsx +0 -335
- package/src/screens/Login.tsx +0 -186
- package/src/screens/MintingIdentity.tsx +0 -446
- package/src/screens/PasskeyAuth.tsx +0 -259
- package/src/screens/PasskeyRegister.tsx +0 -281
- package/src/screens/PermissionsRequest.tsx +0 -96
- package/src/screens/PinVerification.tsx +0 -321
- package/src/screens/ReviewData.tsx +0 -315
- package/src/screens/SecurityUpgrade.tsx +0 -83
- package/src/screens/VerifyIdentityChoice.tsx +0 -59
- package/src/shared/Footer.tsx +0 -13
- package/src/shared/GlassContainer.tsx +0 -17
- package/src/shared/Header.tsx +0 -62
- package/src/types.ts +0 -342
- package/src/utils/fetchWithTimeout.ts +0 -52
- package/src/utils/i18n.ts +0 -640
- package/src/utils/webauthn.ts +0 -261
|
@@ -1,446 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useState, useRef } from 'react';
|
|
2
|
-
import { motion } from 'framer-motion';
|
|
3
|
-
import { Shield, Network, AlertCircle, CheckCircle2, Wallet, Fingerprint } from 'lucide-react';
|
|
4
|
-
import { t } from '../utils/i18n';
|
|
5
|
-
|
|
6
|
-
type VerificationTier = 'layer_1' | 'layer_2' | 'layer_3';
|
|
7
|
-
|
|
8
|
-
interface MintingIdentityProps {
|
|
9
|
-
tier: VerificationTier;
|
|
10
|
-
sessionToken?: string;
|
|
11
|
-
requestId?: string; // Only needed for L2/L3 submission
|
|
12
|
-
onNext: (result?: { wallet?: string; didAddress?: string; credentialHash?: string }) => void;
|
|
13
|
-
onError?: (error: string) => void;
|
|
14
|
-
apiBaseUrl?: string;
|
|
15
|
-
previewMode?: boolean;
|
|
16
|
-
language?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
type MintingStatus = 'processing' | 'minting' | 'completed' | 'failed';
|
|
20
|
-
|
|
21
|
-
// Tier-specific status messages
|
|
22
|
-
const getStatusMessages = (tier: VerificationTier, language: string) => {
|
|
23
|
-
if (tier === 'layer_1') {
|
|
24
|
-
return {
|
|
25
|
-
processing: {
|
|
26
|
-
title: t('generating_wallet', language),
|
|
27
|
-
subtitle: t('wallet_subtitle', language)
|
|
28
|
-
},
|
|
29
|
-
minting: {
|
|
30
|
-
title: t('minting_did', language),
|
|
31
|
-
subtitle: t('did_subtitle', language)
|
|
32
|
-
},
|
|
33
|
-
completed: {
|
|
34
|
-
title: t('identity_created', language),
|
|
35
|
-
subtitle: t('identity_created_subtitle', language)
|
|
36
|
-
},
|
|
37
|
-
failed: {
|
|
38
|
-
title: t('setup_failed', language),
|
|
39
|
-
subtitle: t('setup_failed_subtitle', language)
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// L2/L3 messages
|
|
45
|
-
return {
|
|
46
|
-
processing: {
|
|
47
|
-
title: tier === 'layer_2' ? t('processing_liveness', language) : t('processing_documents', language),
|
|
48
|
-
subtitle: t('processing_subtitle', language)
|
|
49
|
-
},
|
|
50
|
-
minting: {
|
|
51
|
-
title: t('minting_identity', language),
|
|
52
|
-
subtitle: t('minting_subtitle', language)
|
|
53
|
-
},
|
|
54
|
-
completed: {
|
|
55
|
-
title: t('verification_submitted', language),
|
|
56
|
-
subtitle: t('verification_submitted_subtitle', language)
|
|
57
|
-
},
|
|
58
|
-
failed: {
|
|
59
|
-
title: t('verification_failed', language),
|
|
60
|
-
subtitle: t('verification_failed_subtitle', language)
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const MintingIdentity: React.FC<MintingIdentityProps> = ({
|
|
66
|
-
tier,
|
|
67
|
-
sessionToken,
|
|
68
|
-
requestId,
|
|
69
|
-
onNext,
|
|
70
|
-
onError,
|
|
71
|
-
apiBaseUrl = 'https://apis.casperid.com',
|
|
72
|
-
previewMode = false,
|
|
73
|
-
language = 'EN'
|
|
74
|
-
}) => {
|
|
75
|
-
const [status, setStatus] = useState<MintingStatus>('processing');
|
|
76
|
-
const [progress, setProgress] = useState(0);
|
|
77
|
-
const [error, setError] = useState('');
|
|
78
|
-
const [wallet, setWallet] = useState<string | null>(null);
|
|
79
|
-
const [didAddress, setDidAddress] = useState<string | null>(null);
|
|
80
|
-
const [credentialHash, setCredentialHash] = useState<string | null>(null);
|
|
81
|
-
const [humanId, setHumanId] = useState<string | null>(null);
|
|
82
|
-
|
|
83
|
-
// Prevent double execution in React StrictMode
|
|
84
|
-
const hasStartedRef = useRef(false);
|
|
85
|
-
|
|
86
|
-
const statusMessages = getStatusMessages(tier, language);
|
|
87
|
-
const currentMessage = statusMessages[status];
|
|
88
|
-
|
|
89
|
-
// Main setup effect
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
if (hasStartedRef.current) return;
|
|
92
|
-
hasStartedRef.current = true;
|
|
93
|
-
|
|
94
|
-
if (previewMode) {
|
|
95
|
-
runPreviewMode();
|
|
96
|
-
} else {
|
|
97
|
-
runSetup();
|
|
98
|
-
}
|
|
99
|
-
}, []);
|
|
100
|
-
|
|
101
|
-
// Preview mode simulation
|
|
102
|
-
const runPreviewMode = async () => {
|
|
103
|
-
setStatus('processing');
|
|
104
|
-
setProgress(20);
|
|
105
|
-
await sleep(1000);
|
|
106
|
-
setProgress(50);
|
|
107
|
-
await sleep(1000);
|
|
108
|
-
setStatus('minting');
|
|
109
|
-
setProgress(70);
|
|
110
|
-
await sleep(1000);
|
|
111
|
-
setProgress(100);
|
|
112
|
-
setStatus('completed');
|
|
113
|
-
|
|
114
|
-
if (tier === 'layer_1') {
|
|
115
|
-
setWallet('account-hash-abc123...');
|
|
116
|
-
setHumanId('casper-user-1234');
|
|
117
|
-
setDidAddress('did:casper:abc123...');
|
|
118
|
-
} else {
|
|
119
|
-
setCredentialHash('mock-credential-hash-xyz');
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
await sleep(1500);
|
|
123
|
-
onNext({
|
|
124
|
-
wallet: 'account-hash-abc123...',
|
|
125
|
-
didAddress: 'did:casper:abc123...',
|
|
126
|
-
credentialHash: 'mock-credential-hash-xyz'
|
|
127
|
-
});
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
// Real setup based on tier
|
|
131
|
-
const runSetup = async () => {
|
|
132
|
-
try {
|
|
133
|
-
if (tier === 'layer_1') {
|
|
134
|
-
await runL1Setup();
|
|
135
|
-
} else {
|
|
136
|
-
await runL2L3Setup();
|
|
137
|
-
}
|
|
138
|
-
} catch (err) {
|
|
139
|
-
const message = err instanceof Error ? err.message : 'Setup failed';
|
|
140
|
-
setError(message);
|
|
141
|
-
setStatus('failed');
|
|
142
|
-
onError?.(message);
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
// L1 Setup: Wallet + DID creation (synchronous)
|
|
147
|
-
const runL1Setup = async () => {
|
|
148
|
-
// Step 1: Generate wallet
|
|
149
|
-
setStatus('processing');
|
|
150
|
-
setProgress(10);
|
|
151
|
-
|
|
152
|
-
const walletResponse = await fetch(`${apiBaseUrl}/api/passkey/wallet/generate`, {
|
|
153
|
-
method: 'POST',
|
|
154
|
-
headers: {
|
|
155
|
-
'Content-Type': 'application/json',
|
|
156
|
-
'Authorization': `Bearer ${sessionToken}`
|
|
157
|
-
},
|
|
158
|
-
credentials: 'include'
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
if (!walletResponse.ok) {
|
|
162
|
-
const errorData = await walletResponse.json().catch(() => ({}));
|
|
163
|
-
throw new Error(errorData.error || 'Failed to generate wallet');
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const walletData = await walletResponse.json();
|
|
167
|
-
if (!walletData.success || !walletData.walletInfo?.walletAddress) {
|
|
168
|
-
throw new Error(walletData.error || 'Wallet generation failed');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
setWallet(walletData.walletInfo.walletAddress);
|
|
172
|
-
if (walletData.walletInfo.humanId) {
|
|
173
|
-
setHumanId(walletData.walletInfo.humanId);
|
|
174
|
-
}
|
|
175
|
-
setProgress(50);
|
|
176
|
-
|
|
177
|
-
// Step 2: Mint DID
|
|
178
|
-
setStatus('minting');
|
|
179
|
-
setProgress(60);
|
|
180
|
-
|
|
181
|
-
const didResponse = await fetch(`${apiBaseUrl}/api/passkey/did/mint`, {
|
|
182
|
-
method: 'POST',
|
|
183
|
-
headers: {
|
|
184
|
-
'Content-Type': 'application/json',
|
|
185
|
-
'Authorization': `Bearer ${sessionToken}`
|
|
186
|
-
},
|
|
187
|
-
credentials: 'include'
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
if (!didResponse.ok) {
|
|
191
|
-
const errorData = await didResponse.json().catch(() => ({}));
|
|
192
|
-
throw new Error(errorData.error || 'Failed to mint DID');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const didData = await didResponse.json();
|
|
196
|
-
if (!didData.success) {
|
|
197
|
-
throw new Error(didData.error || 'DID minting failed');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
setDidAddress(didData.did_address);
|
|
201
|
-
setCredentialHash(didData.transaction_hash);
|
|
202
|
-
setProgress(100);
|
|
203
|
-
setStatus('completed');
|
|
204
|
-
|
|
205
|
-
// Auto-proceed after showing success
|
|
206
|
-
await sleep(1500);
|
|
207
|
-
onNext({
|
|
208
|
-
wallet: walletData.walletInfo.walletAddress,
|
|
209
|
-
didAddress: didData.did_address,
|
|
210
|
-
credentialHash: didData.transaction_hash
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
// L2/L3 Setup: Submit verification (no polling)
|
|
215
|
-
const runL2L3Setup = async () => {
|
|
216
|
-
setStatus('processing');
|
|
217
|
-
setProgress(30);
|
|
218
|
-
|
|
219
|
-
// For L2/L3, we just confirm the submission was successful
|
|
220
|
-
// The actual verification happens in background, user tier upgrades when ready
|
|
221
|
-
await sleep(500);
|
|
222
|
-
setProgress(60);
|
|
223
|
-
|
|
224
|
-
setStatus('minting');
|
|
225
|
-
setProgress(80);
|
|
226
|
-
|
|
227
|
-
await sleep(500);
|
|
228
|
-
setProgress(100);
|
|
229
|
-
setStatus('completed');
|
|
230
|
-
|
|
231
|
-
// Auto-proceed after showing success
|
|
232
|
-
await sleep(1500);
|
|
233
|
-
onNext({ credentialHash: requestId });
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
|
237
|
-
|
|
238
|
-
const handleRetry = () => {
|
|
239
|
-
setStatus('processing');
|
|
240
|
-
setProgress(0);
|
|
241
|
-
setError('');
|
|
242
|
-
hasStartedRef.current = false;
|
|
243
|
-
|
|
244
|
-
if (previewMode) {
|
|
245
|
-
runPreviewMode();
|
|
246
|
-
} else {
|
|
247
|
-
runSetup();
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
// Get tier-specific icon
|
|
252
|
-
const getTierIcon = () => {
|
|
253
|
-
if (tier === 'layer_1') {
|
|
254
|
-
return status === 'minting' ? <Fingerprint className="text-brand w-4 h-4" /> : <Wallet className="text-brand w-4 h-4" />;
|
|
255
|
-
}
|
|
256
|
-
return <Shield className="text-brand w-4 h-4" />;
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
// Get status label for transaction status
|
|
260
|
-
const getStatusLabel = () => {
|
|
261
|
-
if (tier === 'layer_1') {
|
|
262
|
-
if (status === 'processing') return t('creating_wallet', language);
|
|
263
|
-
if (status === 'minting') return t('minting_did_chain', language);
|
|
264
|
-
if (status === 'completed') return t('identity_live', language);
|
|
265
|
-
} else {
|
|
266
|
-
if (status === 'processing') return t('validating_docs', language);
|
|
267
|
-
if (status === 'minting') return t('submitting_verification', language);
|
|
268
|
-
if (status === 'completed') return t('verification_queued', language);
|
|
269
|
-
}
|
|
270
|
-
return '';
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
return (
|
|
274
|
-
<motion.div
|
|
275
|
-
initial={{ opacity: 0 }}
|
|
276
|
-
animate={{ opacity: 1 }}
|
|
277
|
-
exit={{ opacity: 0 }}
|
|
278
|
-
className="flex-1 flex flex-col items-center justify-center px-8 text-center"
|
|
279
|
-
>
|
|
280
|
-
{/* Rotating card animation */}
|
|
281
|
-
<div className="relative w-64 h-64 flex items-center justify-center mb-12">
|
|
282
|
-
<div className="absolute inset-0 rounded-full border-4 border-dashed border-brand-20 animate-[spin_10s_linear_infinite]" />
|
|
283
|
-
<div className="absolute inset-4 rounded-full border-2 border-[#6DE8EC]/20 animate-[spin_6s_linear_infinite_reverse]" />
|
|
284
|
-
|
|
285
|
-
<motion.div
|
|
286
|
-
animate={status !== 'failed' ? { rotateY: [0, 180, 360], y: [-10, 10, -10] } : {}}
|
|
287
|
-
transition={{ duration: 6, repeat: Infinity, ease: 'easeInOut' }}
|
|
288
|
-
className={`relative w-40 h-56 backdrop-blur-xl border rounded-2xl flex flex-col p-4 ${status === 'completed'
|
|
289
|
-
? 'bg-green-500/10 border-green-500/30 shadow-[0_0_50px_-12px_rgba(34,197,94,0.5)]'
|
|
290
|
-
: status === 'failed'
|
|
291
|
-
? 'bg-red-500/10 border-red-500/30 shadow-[0_0_50px_-12px_rgba(239,68,68,0.5)]'
|
|
292
|
-
: 'bg-brand/10 border-brand-30 shadow-[0_0_50px_-12px_rgba(114,43,238,0.5)]'
|
|
293
|
-
}`}
|
|
294
|
-
>
|
|
295
|
-
<div className="flex justify-between items-start mb-6">
|
|
296
|
-
<div className={`w-8 h-8 rounded flex items-center justify-center ${status === 'completed'
|
|
297
|
-
? 'bg-green-500/30'
|
|
298
|
-
: status === 'failed'
|
|
299
|
-
? 'bg-red-500/30'
|
|
300
|
-
: 'bg-brand/30'
|
|
301
|
-
}`}>
|
|
302
|
-
{status === 'completed' ? (
|
|
303
|
-
<CheckCircle2 className="text-green-500 w-4 h-4" />
|
|
304
|
-
) : status === 'failed' ? (
|
|
305
|
-
<AlertCircle className="text-red-500 w-4 h-4" />
|
|
306
|
-
) : (
|
|
307
|
-
getTierIcon()
|
|
308
|
-
)}
|
|
309
|
-
</div>
|
|
310
|
-
<div className={`w-6 h-1 rounded-full ${status === 'completed'
|
|
311
|
-
? 'bg-green-500/40'
|
|
312
|
-
: status === 'failed'
|
|
313
|
-
? 'bg-red-500/40'
|
|
314
|
-
: 'bg-brand/40'
|
|
315
|
-
}`} />
|
|
316
|
-
</div>
|
|
317
|
-
<div className="space-y-3 mb-auto">
|
|
318
|
-
<div className={`h-2 w-3/4 rounded-full ${status === 'completed'
|
|
319
|
-
? 'bg-green-500/20'
|
|
320
|
-
: status === 'failed'
|
|
321
|
-
? 'bg-red-500/20'
|
|
322
|
-
: 'bg-brand/20'
|
|
323
|
-
}`} />
|
|
324
|
-
<div className={`h-2 w-1/2 rounded-full ${status === 'completed'
|
|
325
|
-
? 'bg-green-500/20'
|
|
326
|
-
: status === 'failed'
|
|
327
|
-
? 'bg-red-500/20'
|
|
328
|
-
: 'bg-brand/20'
|
|
329
|
-
}`} />
|
|
330
|
-
</div>
|
|
331
|
-
<div className="flex items-center gap-2 mt-4">
|
|
332
|
-
<div className={`size-6 rounded-full overflow-hidden border border-white/10 ${status === 'completed'
|
|
333
|
-
? 'bg-gradient-to-tr from-green-500 to-[#6DE8EC]'
|
|
334
|
-
: status === 'failed'
|
|
335
|
-
? 'bg-gradient-to-tr from-red-500 to-orange-500'
|
|
336
|
-
: 'bg-gradient-to-tr from-brand to-[#6DE8EC]'
|
|
337
|
-
}`} />
|
|
338
|
-
<div className="flex flex-col items-start max-w-[80px]">
|
|
339
|
-
{humanId ? (
|
|
340
|
-
<motion.span
|
|
341
|
-
initial={{ opacity: 0 }}
|
|
342
|
-
animate={{ opacity: 1 }}
|
|
343
|
-
className="text-[10px] font-bold text-white/90 truncate w-full text-left"
|
|
344
|
-
>
|
|
345
|
-
{humanId}
|
|
346
|
-
</motion.span>
|
|
347
|
-
) : (
|
|
348
|
-
<div className="h-1.5 w-12 bg-white/20 rounded-full mb-1" />
|
|
349
|
-
)}
|
|
350
|
-
<div className="h-1 w-8 bg-white/10 rounded-full" />
|
|
351
|
-
</div>
|
|
352
|
-
</div>
|
|
353
|
-
{status !== 'failed' && status !== 'completed' && (
|
|
354
|
-
<motion.div
|
|
355
|
-
animate={{ top: ['0%', '100%', '0%'] }}
|
|
356
|
-
transition={{ duration: 2, repeat: Infinity }}
|
|
357
|
-
className="absolute inset-0 bg-gradient-to-b from-transparent via-brand-10 to-transparent h-1/2 w-full"
|
|
358
|
-
/>
|
|
359
|
-
)}
|
|
360
|
-
</motion.div>
|
|
361
|
-
</div>
|
|
362
|
-
|
|
363
|
-
<div className="space-y-4">
|
|
364
|
-
<h2 className={`text-2xl font-bold bg-clip-text ${status === 'completed'
|
|
365
|
-
? 'text-green-500'
|
|
366
|
-
: status === 'failed'
|
|
367
|
-
? 'text-red-500'
|
|
368
|
-
: 'dark:bg-gradient-to-r dark:from-slate-100 dark:to-slate-400 bg-slate-900 dark:text-transparent text-slate-900'
|
|
369
|
-
}`}>
|
|
370
|
-
{currentMessage.title}
|
|
371
|
-
</h2>
|
|
372
|
-
<p className="dark:text-slate-400 text-slate-500 text-sm leading-relaxed max-w-[280px] mx-auto">
|
|
373
|
-
{currentMessage.subtitle}
|
|
374
|
-
</p>
|
|
375
|
-
</div>
|
|
376
|
-
|
|
377
|
-
{/* Error with retry button */}
|
|
378
|
-
{status === 'failed' && (
|
|
379
|
-
<div className="mt-6 space-y-3">
|
|
380
|
-
<p className="text-red-500 text-sm">{error}</p>
|
|
381
|
-
<button
|
|
382
|
-
onClick={handleRetry}
|
|
383
|
-
className="px-6 py-3 bg-brand text-white rounded-2xl font-bold"
|
|
384
|
-
>
|
|
385
|
-
{t('try_again', language)}
|
|
386
|
-
</button>
|
|
387
|
-
</div>
|
|
388
|
-
)}
|
|
389
|
-
|
|
390
|
-
{/* Wallet/DID display for L1 */}
|
|
391
|
-
{tier === 'layer_1' && wallet && status === 'completed' && (
|
|
392
|
-
<div className="mt-6 p-3 dark:bg-white/5 bg-black/5 rounded-xl border dark:border-white/10 border-black/5">
|
|
393
|
-
<p className="text-[10px] text-muted mb-1">{t('your_wallet', language)}</p>
|
|
394
|
-
<p className="text-xs font-mono text-main break-all">
|
|
395
|
-
{wallet.slice(0, 20)}...{wallet.slice(-10)}
|
|
396
|
-
</p>
|
|
397
|
-
</div>
|
|
398
|
-
)}
|
|
399
|
-
|
|
400
|
-
{/* Credential hash display for L2/L3 */}
|
|
401
|
-
{tier !== 'layer_1' && credentialHash && status === 'completed' && (
|
|
402
|
-
<div className="mt-6 p-3 dark:bg-white/5 bg-black/5 rounded-xl border dark:border-white/10 border-black/5">
|
|
403
|
-
<p className="text-[10px] text-muted mb-1">{t('verification_id', language)}</p>
|
|
404
|
-
<p className="text-xs font-mono text-main break-all">
|
|
405
|
-
{credentialHash.slice(0, 20)}...
|
|
406
|
-
</p>
|
|
407
|
-
</div>
|
|
408
|
-
)}
|
|
409
|
-
|
|
410
|
-
{/* Transaction status (only show when not failed) */}
|
|
411
|
-
{status !== 'failed' && (
|
|
412
|
-
<div className="w-full mt-12 p-6 dark:bg-brand/5 bg-brand/5 border-t dark:border-white/5 border-black/5">
|
|
413
|
-
<div className="flex justify-between items-center mb-3">
|
|
414
|
-
<span className="text-xs font-medium text-brand uppercase tracking-widest">
|
|
415
|
-
{tier === 'layer_1' ? t('setup_status', language) : t('transaction_status', language)}
|
|
416
|
-
</span>
|
|
417
|
-
<span className={`text-xs font-bold ${status === 'completed' ? 'text-green-500' : 'text-[#6DE8EC]'
|
|
418
|
-
}`}>
|
|
419
|
-
{t('complete_percent', language).replace('{percent}', progress.toString())}
|
|
420
|
-
</span>
|
|
421
|
-
</div>
|
|
422
|
-
<div className="w-full h-1.5 dark:bg-brand/10 bg-brand/10 rounded-full overflow-hidden mb-4">
|
|
423
|
-
<motion.div
|
|
424
|
-
initial={{ width: '0%' }}
|
|
425
|
-
animate={{ width: `${progress}%` }}
|
|
426
|
-
transition={{ duration: 0.5 }}
|
|
427
|
-
className={`h-full rounded-full ${status === 'completed'
|
|
428
|
-
? 'bg-gradient-to-r from-green-500 to-[#6DE8EC]'
|
|
429
|
-
: 'bg-gradient-to-r from-brand to-[#6DE8EC]'
|
|
430
|
-
} shadow-[0_0_10px_rgba(114,43,238,0.5)]`}
|
|
431
|
-
/>
|
|
432
|
-
</div>
|
|
433
|
-
<div className="flex items-center gap-3 px-3 py-2 dark:bg-brand/10 bg-brand/10 rounded-xl border dark:border-brand-10 border-brand-5">
|
|
434
|
-
<Network className={`w-4 h-4 ${status === 'completed' ? 'text-green-500' : 'text-brand'
|
|
435
|
-
}`} />
|
|
436
|
-
<p className="text-[10px] dark:text-slate-300 text-slate-600 font-medium">
|
|
437
|
-
{getStatusLabel()}
|
|
438
|
-
</p>
|
|
439
|
-
</div>
|
|
440
|
-
</div>
|
|
441
|
-
)}
|
|
442
|
-
</motion.div>
|
|
443
|
-
);
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
export default MintingIdentity;
|