@abstraxn/signer-react 3.3.10 → 4.0.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/CHANGELOG.md +33 -0
- package/dist/src/ConnectButton.css.d.ts +2 -0
- package/dist/src/ConnectButton.css.js +1 -0
- package/dist/src/ConnectButton.d.ts +0 -1
- package/dist/src/ConnectButton.js +7 -6
- package/dist/src/ExternalWalletButtons.css.d.ts +2 -0
- package/dist/src/ExternalWalletButtons.css.js +1 -0
- package/dist/src/ExternalWalletButtons.d.ts +4 -1
- package/dist/src/ExternalWalletButtons.js +6 -1
- package/dist/src/WalletModal.css +2 -0
- package/dist/src/WalletModal.css.d.ts +2 -0
- package/dist/src/WalletModal.css.js +1 -0
- package/dist/src/WalletModal.d.ts +2 -2
- package/dist/src/WalletModal.js +113 -59
- package/dist/src/components/AbstraxnLogo.d.ts +17 -0
- package/dist/src/components/AbstraxnLogo.js +29 -0
- package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js +406 -338
- package/dist/src/components/AbstraxnProvider/useAbstraxnProviderBase.d.ts +7 -0
- package/dist/src/components/AbstraxnProvider/useAbstraxnProviderBase.js +9 -0
- package/dist/src/components/AbstraxnProvider/useWalletInitialization.js +41 -6
- package/dist/src/components/OnboardingUI/OnboardingUI.css +99 -4
- package/dist/src/components/OnboardingUI/OnboardingUI.css.d.ts +2 -0
- package/dist/src/components/OnboardingUI/OnboardingUI.css.js +1 -0
- package/dist/src/components/OnboardingUI/OnboardingUIReact.d.ts +0 -1
- package/dist/src/components/OnboardingUI/OnboardingUIReact.js +46 -19
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.d.ts +24 -1
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +348 -160
- package/dist/src/components/OnboardingUI/components/Divider.d.ts +7 -0
- package/dist/src/components/OnboardingUI/components/Divider.js +9 -0
- package/dist/src/components/OnboardingUI/components/EmailForm.d.ts +0 -1
- package/dist/src/components/OnboardingUI/components/EmailForm.js +1 -2
- package/dist/src/components/OnboardingUI/components/MfaForm.d.ts +0 -1
- package/dist/src/components/OnboardingUI/components/MfaForm.js +2 -3
- package/dist/src/components/OnboardingUI/components/Modal.d.ts +0 -1
- package/dist/src/components/OnboardingUI/components/Modal.js +12 -4
- package/dist/src/components/OnboardingUI/components/OtpForm.d.ts +0 -1
- package/dist/src/components/OnboardingUI/components/OtpForm.js +2 -3
- package/dist/src/components/OnboardingUI/components/PasskeyButton.d.ts +0 -1
- package/dist/src/components/OnboardingUI/components/PasskeyButton.js +2 -2
- package/dist/src/components/OnboardingUI/components/SocialButtons.d.ts +0 -1
- package/dist/src/components/OnboardingUI/components/SocialButtons.js +3 -3
- package/dist/src/components/OnboardingUI/onboardingShadowContainer.d.ts +9 -0
- package/dist/src/components/OnboardingUI/onboardingShadowContainer.js +36 -0
- package/dist/src/components/ShadowHost/ShadowHost.d.ts +18 -0
- package/dist/src/components/ShadowHost/ShadowHost.js +123 -0
- package/dist/src/components/ShadowHost/ShadowHostContext.d.ts +10 -0
- package/dist/src/components/ShadowHost/ShadowHostContext.js +14 -0
- package/dist/src/components/ShadowHost/index.d.ts +2 -0
- package/dist/src/components/ShadowHost/index.js +3 -0
- package/dist/src/components/WalletModal/components/ChainSelector.css +9 -0
- package/dist/src/components/WalletModal/components/ChainSelector.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/ChainSelector.css.js +1 -0
- package/dist/src/components/WalletModal/components/ChainSelector.d.ts +0 -1
- package/dist/src/components/WalletModal/components/ChainSelector.js +78 -23
- package/dist/src/components/WalletModal/components/CodeInput.d.ts +12 -0
- package/dist/src/components/WalletModal/components/CodeInput.js +39 -0
- package/dist/src/components/WalletModal/components/ExportKeyModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/ExportKeyModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/ExportKeyModal.d.ts +0 -2
- package/dist/src/components/WalletModal/components/ExportKeyModal.js +2 -4
- package/dist/src/components/WalletModal/components/ExportWarningModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/ExportWarningModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/ExportWarningModal.d.ts +0 -2
- package/dist/src/components/WalletModal/components/ExportWarningModal.js +2 -4
- package/dist/src/components/WalletModal/components/ManageWalletModal.css +27 -1
- package/dist/src/components/WalletModal/components/ManageWalletModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/ManageWalletModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/ManageWalletModal.d.ts +0 -1
- package/dist/src/components/WalletModal/components/ManageWalletModal.js +66 -148
- package/dist/src/components/WalletModal/components/MfaVerifyModal.d.ts +15 -0
- package/dist/src/components/WalletModal/components/MfaVerifyModal.js +98 -0
- package/dist/src/components/WalletModal/components/PreviewTransactionModal.css +2 -12
- package/dist/src/components/WalletModal/components/PreviewTransactionModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/PreviewTransactionModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/PreviewTransactionModal.d.ts +0 -1
- package/dist/src/components/WalletModal/components/PreviewTransactionModal.js +0 -1
- package/dist/src/components/WalletModal/components/ReceiveModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/ReceiveModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/ReceiveModal.d.ts +0 -1
- package/dist/src/components/WalletModal/components/ReceiveModal.js +2 -2
- package/dist/src/components/WalletModal/components/SendModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/SendModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/SendModal.d.ts +5 -2
- package/dist/src/components/WalletModal/components/SendModal.js +25 -82
- package/dist/src/components/WalletModal/components/SignMfaModalHost.d.ts +1 -0
- package/dist/src/components/WalletModal/components/SignMfaModalHost.js +50 -0
- package/dist/src/components/WalletModal/components/SuccessModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/SuccessModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/SuccessModal.d.ts +0 -1
- package/dist/src/components/WalletModal/components/SuccessModal.js +0 -1
- package/dist/src/components/WalletModal/components/TokenSelectorModal.css.d.ts +2 -0
- package/dist/src/components/WalletModal/components/TokenSelectorModal.css.js +1 -0
- package/dist/src/components/WalletModal/components/TokenSelectorModal.d.ts +0 -1
- package/dist/src/components/WalletModal/components/TokenSelectorModal.js +0 -1
- package/dist/src/components/WalletModal/components/UserAvatar.js +2 -1
- package/dist/src/components/WalletModal/components/index.d.ts +3 -0
- package/dist/src/components/WalletModal/components/index.js +2 -0
- package/dist/src/components/WalletModal/hooks/useSendTransaction.js +18 -6
- package/dist/src/components/icons.d.ts +2 -0
- package/dist/src/components/icons.js +4 -0
- package/dist/src/hooks.d.ts +58 -3
- package/dist/src/hooks.js +172 -30
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/signMfaBridge.d.ts +7 -0
- package/dist/src/signMfaBridge.js +20 -0
- package/dist/src/types.d.ts +4 -0
- package/dist/src/utils/shadowFocus.d.ts +8 -0
- package/dist/src/utils/shadowFocus.js +15 -0
- package/dist/src/utils/shadowRegistry.d.ts +23 -0
- package/dist/src/utils/shadowRegistry.js +36 -0
- package/package.json +9 -4
|
@@ -4,11 +4,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
4
4
|
*/
|
|
5
5
|
import { useEffect, useRef, useState, useCallback } from "react";
|
|
6
6
|
import { createPortal } from "react-dom";
|
|
7
|
-
import { IoKeyOutline, IoCopyOutline, IoCheckmarkOutline, IoCloudDownloadOutline, IoChevronBack,
|
|
7
|
+
import { IoKeyOutline, IoCopyOutline, IoCheckmarkOutline, IoCloudDownloadOutline, IoChevronBack, CloseIcon, IoPhonePortraitOutline, SiWalletconnect, SiDiscord, SiX, GoogleIcon, FiUsers, FiLink, TfiEmail, BiShieldQuarter, } from "../../icons";
|
|
8
8
|
import { useAbstraxnWallet } from "../../../AbstraxnProvider";
|
|
9
9
|
import { useEnableMfa } from "../../../hooks";
|
|
10
|
-
import "./ManageWalletModal.css";
|
|
11
10
|
import { QRCodeSVG } from "qrcode.react";
|
|
11
|
+
import { useShadowHost } from "../../ShadowHost";
|
|
12
|
+
import { CodeInput } from "./CodeInput";
|
|
13
|
+
import { MfaVerifyModal } from "./MfaVerifyModal";
|
|
14
|
+
import { AbstraxnLogo } from "../../AbstraxnLogo";
|
|
12
15
|
function normalizeLinkedProvider(authProvider) {
|
|
13
16
|
return authProvider === "otp" ? "email" : authProvider;
|
|
14
17
|
}
|
|
@@ -18,7 +21,7 @@ function normalizeErrorMessage(message) {
|
|
|
18
21
|
function AuthMethodIcon({ provider }) {
|
|
19
22
|
const p = provider.toLowerCase();
|
|
20
23
|
if (p === "google")
|
|
21
|
-
return _jsx(
|
|
24
|
+
return _jsx(GoogleIcon, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-google" });
|
|
22
25
|
if (p === "discord")
|
|
23
26
|
return _jsx(SiDiscord, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-discord" });
|
|
24
27
|
if (p === "x" || p === "twitter")
|
|
@@ -31,7 +34,14 @@ function AuthMethodIcon({ provider }) {
|
|
|
31
34
|
}
|
|
32
35
|
export function ManageWalletModal({ ...props }) {
|
|
33
36
|
const { isOpen, onClose, isExternalWalletConnected, onExportPrivateKey, theme = "dark", userEmail, organizationName, } = props;
|
|
34
|
-
|
|
37
|
+
// Portal target: the enclosing WalletModal's shadow boundary container,
|
|
38
|
+
// so these nested overlays stay inside the isolation boundary instead of
|
|
39
|
+
// escaping to document.body. document.body fallback is purely defensive —
|
|
40
|
+
// this component is never rendered outside a WalletModal shadow boundary
|
|
41
|
+
// in practice.
|
|
42
|
+
const shadowHost = useShadowHost();
|
|
43
|
+
const portalTarget = shadowHost?.container ?? document.body;
|
|
44
|
+
const { getSupportedAuthMethods, getLinkedAuthMethods, linkAuthMethod, linkEmail, loginWithOTP, requestOtpForEmailLink, unlinkAuthMethod, whoami, mfaStatus, mfaStatusLoading, prefetchMfaStatus, verifySignMfa, disableMfaWithSignedPayload, } = useAbstraxnWallet();
|
|
35
45
|
const [showLinkedProfilesList, setShowLinkedProfilesList] = useState(false);
|
|
36
46
|
const [supportedMethods, setSupportedMethods] = useState([]);
|
|
37
47
|
const [linkedMethods, setLinkedMethods] = useState([]);
|
|
@@ -61,19 +71,21 @@ export function ManageWalletModal({ ...props }) {
|
|
|
61
71
|
const [showMfaDisableAuthModal, setShowMfaDisableAuthModal] = useState(false);
|
|
62
72
|
const [showMfaDisableConfirmModal, setShowMfaDisableConfirmModal] = useState(false);
|
|
63
73
|
const [showMfaStatusModal, setShowMfaStatusModal] = useState(false);
|
|
64
|
-
const [mfaDisableStep, setMfaDisableStep] = useState("otp");
|
|
65
|
-
const [mfaDisableCode, setMfaDisableCode] = useState("");
|
|
66
|
-
const [mfaDisableRecoveryCode, setMfaDisableRecoveryCode] = useState("");
|
|
67
74
|
const [mfaDisableLoading, setMfaDisableLoading] = useState(false);
|
|
68
75
|
const [mfaDisableError, setMfaDisableError] = useState(null);
|
|
69
|
-
const mfaDisableVerifyButtonRef = useRef(null);
|
|
70
76
|
const hasFetchedLinkedProfilesForOpenRef = useRef(false);
|
|
71
77
|
const linkedProfilesFetchPromiseRef = useRef(null);
|
|
78
|
+
const clearLinkUnlinkFeedback = useCallback(() => {
|
|
79
|
+
setLinkUnlinkError(null);
|
|
80
|
+
setLinkUnlinkSuccess(null);
|
|
81
|
+
}, []);
|
|
72
82
|
const showFeedback = useCallback((message, type = "success") => {
|
|
73
83
|
if (type === "error") {
|
|
84
|
+
setLinkUnlinkSuccess(null);
|
|
74
85
|
setLinkUnlinkError(message);
|
|
75
86
|
return;
|
|
76
87
|
}
|
|
88
|
+
setLinkUnlinkError(null);
|
|
77
89
|
setLinkUnlinkSuccess(message);
|
|
78
90
|
}, []);
|
|
79
91
|
const fetchLinkedProfilesData = useCallback(async () => {
|
|
@@ -115,21 +127,34 @@ export function ManageWalletModal({ ...props }) {
|
|
|
115
127
|
});
|
|
116
128
|
}, [getSupportedAuthMethods, getLinkedAuthMethods, isExternalWalletConnected, whoami]);
|
|
117
129
|
const handleOpenLinkedProfiles = useCallback(() => {
|
|
130
|
+
clearLinkUnlinkFeedback();
|
|
118
131
|
setShowLinkedProfilesList(true);
|
|
119
132
|
const hasLinkedProfilesData = supportedMethods.length > 0 || linkedMethods.length > 0;
|
|
120
133
|
if (!hasLinkedProfilesData && !linkedLoading) {
|
|
121
134
|
fetchLinkedProfilesData();
|
|
122
135
|
}
|
|
123
|
-
}, [
|
|
136
|
+
}, [
|
|
137
|
+
clearLinkUnlinkFeedback,
|
|
138
|
+
fetchLinkedProfilesData,
|
|
139
|
+
linkedLoading,
|
|
140
|
+
linkedMethods.length,
|
|
141
|
+
supportedMethods.length,
|
|
142
|
+
]);
|
|
143
|
+
const handleCloseLinkedProfiles = useCallback(() => {
|
|
144
|
+
clearLinkUnlinkFeedback();
|
|
145
|
+
setShowLinkedProfilesList(false);
|
|
146
|
+
}, [clearLinkUnlinkFeedback]);
|
|
124
147
|
const isProviderLinked = useCallback((provider) => {
|
|
125
148
|
return linkedMethods.some((m) => normalizeLinkedProvider(m.authProvider) === provider.toLowerCase());
|
|
126
149
|
}, [linkedMethods]);
|
|
127
150
|
const handleConnect = useCallback(async (provider) => {
|
|
151
|
+
clearLinkUnlinkFeedback();
|
|
128
152
|
if (provider.toLowerCase() === "email") {
|
|
129
153
|
setEmailLinkStep("email");
|
|
130
154
|
setEmailLinkEmail("");
|
|
131
155
|
setEmailLinkOtpId(null);
|
|
132
156
|
setEmailLinkOtpCode("");
|
|
157
|
+
setEmailLinkError(null);
|
|
133
158
|
return;
|
|
134
159
|
}
|
|
135
160
|
if (!linkAuthMethod)
|
|
@@ -146,12 +171,12 @@ export function ManageWalletModal({ ...props }) {
|
|
|
146
171
|
}
|
|
147
172
|
catch (err) {
|
|
148
173
|
const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to connect";
|
|
149
|
-
|
|
174
|
+
showFeedback(msg, "error");
|
|
150
175
|
}
|
|
151
176
|
finally {
|
|
152
177
|
setActionProvider(null);
|
|
153
178
|
}
|
|
154
|
-
}, [linkAuthMethod, fetchLinkedProfilesData, showFeedback]);
|
|
179
|
+
}, [clearLinkUnlinkFeedback, linkAuthMethod, fetchLinkedProfilesData, showFeedback]);
|
|
155
180
|
const handleSendOtpForLink = useCallback(async () => {
|
|
156
181
|
if (!emailLinkEmail.trim())
|
|
157
182
|
return;
|
|
@@ -171,7 +196,6 @@ export function ManageWalletModal({ ...props }) {
|
|
|
171
196
|
catch (err) {
|
|
172
197
|
const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to send OTP";
|
|
173
198
|
setEmailLinkError(msg);
|
|
174
|
-
showFeedback(msg, "error");
|
|
175
199
|
}
|
|
176
200
|
finally {
|
|
177
201
|
setActionProvider(null);
|
|
@@ -195,7 +219,6 @@ export function ManageWalletModal({ ...props }) {
|
|
|
195
219
|
catch (err) {
|
|
196
220
|
const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to resend";
|
|
197
221
|
setEmailLinkError(msg);
|
|
198
|
-
showFeedback(msg, "error");
|
|
199
222
|
}
|
|
200
223
|
finally {
|
|
201
224
|
setEmailLinkResending(false);
|
|
@@ -220,7 +243,6 @@ export function ManageWalletModal({ ...props }) {
|
|
|
220
243
|
catch (err) {
|
|
221
244
|
const msg = err instanceof Error ? normalizeErrorMessage(err.message) : "Failed to link email";
|
|
222
245
|
setEmailLinkError(msg);
|
|
223
|
-
showFeedback(msg, "error");
|
|
224
246
|
}
|
|
225
247
|
finally {
|
|
226
248
|
setActionProvider(null);
|
|
@@ -300,64 +322,38 @@ export function ManageWalletModal({ ...props }) {
|
|
|
300
322
|
const resetMfaDisableState = useCallback(() => {
|
|
301
323
|
setShowMfaDisableAuthModal(false);
|
|
302
324
|
setShowMfaDisableConfirmModal(false);
|
|
303
|
-
setMfaDisableStep("otp");
|
|
304
|
-
setMfaDisableCode("");
|
|
305
|
-
setMfaDisableRecoveryCode("");
|
|
306
325
|
setMfaDisableError(null);
|
|
307
326
|
setMfaDisableLoading(false);
|
|
308
327
|
}, []);
|
|
309
|
-
const
|
|
310
|
-
|
|
328
|
+
const handleMfaDisableVerify = useCallback(async (code) => {
|
|
329
|
+
// Must use verifySignMfa (/mfa/verify-sign): disable calls /sign/transaction,
|
|
330
|
+
// which requires sign step-up — login verifyMfa does not clear SIGN_MFA_REQUIRED.
|
|
331
|
+
if (!verifySignMfa)
|
|
311
332
|
return;
|
|
312
333
|
setMfaDisableLoading(true);
|
|
313
334
|
setMfaDisableError(null);
|
|
314
335
|
try {
|
|
315
|
-
await
|
|
336
|
+
await verifySignMfa(code);
|
|
316
337
|
setShowMfaDisableAuthModal(false);
|
|
317
338
|
setShowMfaDisableConfirmModal(true);
|
|
318
|
-
setMfaDisableCode("");
|
|
319
339
|
}
|
|
320
340
|
catch (err) {
|
|
321
|
-
setMfaDisableError(err instanceof Error
|
|
341
|
+
setMfaDisableError(err instanceof Error
|
|
342
|
+
? normalizeErrorMessage(err.message)
|
|
343
|
+
: "Invalid authentication code");
|
|
322
344
|
}
|
|
323
345
|
finally {
|
|
324
346
|
setMfaDisableLoading(false);
|
|
325
347
|
}
|
|
326
|
-
}, [
|
|
327
|
-
const handleMfaDisableVerifyRecoveryCode = useCallback(async () => {
|
|
328
|
-
if (!verifyMfa)
|
|
329
|
-
return;
|
|
330
|
-
const trimmed = mfaDisableRecoveryCode.trim().toUpperCase();
|
|
331
|
-
if (!/^[A-Z0-9]{8}$/.test(trimmed)) {
|
|
332
|
-
setMfaDisableError("Please enter a valid 8-character backup code");
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
setMfaDisableLoading(true);
|
|
336
|
-
setMfaDisableError(null);
|
|
337
|
-
try {
|
|
338
|
-
await verifyMfa(trimmed);
|
|
339
|
-
setShowMfaDisableAuthModal(false);
|
|
340
|
-
setShowMfaDisableConfirmModal(true);
|
|
341
|
-
setMfaDisableRecoveryCode("");
|
|
342
|
-
}
|
|
343
|
-
catch (err) {
|
|
344
|
-
setMfaDisableError(err instanceof Error ? normalizeErrorMessage(err.message) : "Invalid backup code");
|
|
345
|
-
}
|
|
346
|
-
finally {
|
|
347
|
-
setMfaDisableLoading(false);
|
|
348
|
-
}
|
|
349
|
-
}, [verifyMfa, mfaDisableRecoveryCode]);
|
|
348
|
+
}, [verifySignMfa]);
|
|
350
349
|
const openMfaDisableFlow = useCallback(() => {
|
|
351
|
-
if (!
|
|
350
|
+
if (!verifySignMfa || !disableMfaWithSignedPayload) {
|
|
352
351
|
return;
|
|
353
352
|
}
|
|
354
353
|
setShowMfaStatusModal(false);
|
|
355
|
-
setMfaDisableCode("");
|
|
356
|
-
setMfaDisableRecoveryCode("");
|
|
357
|
-
setMfaDisableStep("otp");
|
|
358
354
|
setMfaDisableError(null);
|
|
359
355
|
setShowMfaDisableAuthModal(true);
|
|
360
|
-
}, [
|
|
356
|
+
}, [verifySignMfa, disableMfaWithSignedPayload]);
|
|
361
357
|
const handleMfaDisableConfirm = useCallback(async () => {
|
|
362
358
|
if (!disableMfaWithSignedPayload)
|
|
363
359
|
return;
|
|
@@ -452,6 +448,7 @@ export function ManageWalletModal({ ...props }) {
|
|
|
452
448
|
const handleDisconnect = useCallback(async (provider) => {
|
|
453
449
|
if (!unlinkAuthMethod)
|
|
454
450
|
return;
|
|
451
|
+
clearLinkUnlinkFeedback();
|
|
455
452
|
setActionProvider(provider);
|
|
456
453
|
try {
|
|
457
454
|
await unlinkAuthMethod(provider);
|
|
@@ -460,7 +457,7 @@ export function ManageWalletModal({ ...props }) {
|
|
|
460
457
|
const message = lower === "passkey"
|
|
461
458
|
? "Passkey removed successfully!"
|
|
462
459
|
: "Provider unlinked successfully!";
|
|
463
|
-
|
|
460
|
+
showFeedback(message, "success");
|
|
464
461
|
await fetchLinkedProfilesData();
|
|
465
462
|
}
|
|
466
463
|
catch (err) {
|
|
@@ -469,7 +466,7 @@ export function ManageWalletModal({ ...props }) {
|
|
|
469
466
|
finally {
|
|
470
467
|
setActionProvider(null);
|
|
471
468
|
}
|
|
472
|
-
}, [unlinkAuthMethod, fetchLinkedProfilesData, showFeedback]);
|
|
469
|
+
}, [clearLinkUnlinkFeedback, unlinkAuthMethod, fetchLinkedProfilesData, showFeedback]);
|
|
473
470
|
useEffect(() => {
|
|
474
471
|
if (emailLinkStep !== "otp" || emailLinkResendCooldown <= 0)
|
|
475
472
|
return;
|
|
@@ -514,7 +511,7 @@ export function ManageWalletModal({ ...props }) {
|
|
|
514
511
|
}
|
|
515
512
|
setShowMfaSetupModal(false);
|
|
516
513
|
resetMfaSetupState();
|
|
517
|
-
}, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Two-Factor Authentication" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(
|
|
514
|
+
}, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Two-Factor Authentication" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsx("div", { className: "mfa-redesign-content", children: mfaSetupStep === "setup" ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mfa-info-box", children: [_jsx("div", { className: "mfa-info-icon", children: _jsx(IoPhonePortraitOutline, { size: 20 }) }), _jsx("p", { className: "mfa-info-text", children: "Open your authenticator app \u2014 Google Authenticator, Authy, or 1Password \u2014 and scan the QR code below." })] }), _jsxs("div", { className: "mfa-qr-container", children: [mfaQrCode ? (_jsx("div", { className: "mfa-qr-wrapper", children: _jsx(QRCodeSVG, { value: (() => {
|
|
518
515
|
const issuer = organizationName ?? "Abstraxn";
|
|
519
516
|
const label = userEmail ? `${issuer}:${userEmail}` : issuer;
|
|
520
517
|
return `otpauth://totp/${encodeURIComponent(label)}?secret=${mfaSecret}&issuer=${encodeURIComponent(issuer)}`;
|
|
@@ -522,41 +519,9 @@ export function ManageWalletModal({ ...props }) {
|
|
|
522
519
|
goToVerify();
|
|
523
520
|
setMfaSetupCode("");
|
|
524
521
|
setMfaRecoveryCode("");
|
|
525
|
-
}, disabled: mfaSetupLoading || !mfaSecret, children: "Continue" })] })) : mfaSetupStep === "verify" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), mfaSetupError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaSetupError })), _jsx(
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
const newCode = mfaSetupCode.split("");
|
|
529
|
-
newCode[index] = val;
|
|
530
|
-
const combined = newCode.join("").slice(0, 6);
|
|
531
|
-
setMfaSetupCode(combined);
|
|
532
|
-
if (combined.length === 6) {
|
|
533
|
-
window.setTimeout(() => {
|
|
534
|
-
mfaSetupVerifyButtonRef.current?.focus();
|
|
535
|
-
}, 0);
|
|
536
|
-
}
|
|
537
|
-
if (index < 5) {
|
|
538
|
-
const target = e.target;
|
|
539
|
-
const next = target.parentElement?.nextElementSibling?.querySelector("input");
|
|
540
|
-
next?.focus();
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
}, onKeyDown: (e) => {
|
|
544
|
-
if (e.key === "Backspace") {
|
|
545
|
-
const target = e.target;
|
|
546
|
-
if (!mfaSetupCode[index] && index > 0) {
|
|
547
|
-
const prev = target.parentElement?.previousElementSibling?.querySelector("input");
|
|
548
|
-
prev?.focus();
|
|
549
|
-
const newCode = mfaSetupCode.split("");
|
|
550
|
-
newCode[index - 1] = "";
|
|
551
|
-
setMfaSetupCode(newCode.join(""));
|
|
552
|
-
}
|
|
553
|
-
else {
|
|
554
|
-
const newCode = mfaSetupCode.split("");
|
|
555
|
-
newCode[index] = "";
|
|
556
|
-
setMfaSetupCode(newCode.join(""));
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}, className: "mfa-otp-input" }) }, index))) }), _jsx("p", { className: "mfa-refresh-text", children: "Code refreshes every 30 seconds" }), _jsx("button", { ref: mfaSetupVerifyButtonRef, type: "button", className: "mfa-verify-button", onClick: handleVerifyMfaSetup, disabled: mfaSetupLoading || mfaSetupCode.length !== 6, children: mfaSetupLoading ? "Verifying..." : "Verify & continue" }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", onClick: () => {
|
|
522
|
+
}, disabled: mfaSetupLoading || !mfaSecret, children: "Continue" })] })) : mfaSetupStep === "verify" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), mfaSetupError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaSetupError })), _jsx(CodeInput, { length: 6, value: mfaSetupCode, onChange: setMfaSetupCode, onComplete: () => window.setTimeout(() => {
|
|
523
|
+
mfaSetupVerifyButtonRef.current?.focus();
|
|
524
|
+
}, 0) }), _jsx("p", { className: "mfa-refresh-text", children: "Code refreshes every 30 seconds" }), _jsx("button", { ref: mfaSetupVerifyButtonRef, type: "button", className: "mfa-verify-button", onClick: handleVerifyMfaSetup, disabled: mfaSetupLoading || mfaSetupCode.length !== 6, children: mfaSetupLoading ? "Verifying..." : "Verify & continue" }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", onClick: () => {
|
|
560
525
|
goToRecovery();
|
|
561
526
|
setMfaRecoveryCode("");
|
|
562
527
|
}, children: "Use a recovery code" })] })] })) : (_jsxs("div", { className: "mfa-recovery-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 8 charater backup code" }) }), mfaSetupError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaSetupError })), _jsx("input", { type: "text", inputMode: "text", maxLength: 8, value: mfaRecoveryCode, onChange: (e) => {
|
|
@@ -571,68 +536,19 @@ export function ManageWalletModal({ ...props }) {
|
|
|
571
536
|
}, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => {
|
|
572
537
|
setShowMfaBackupModal(false);
|
|
573
538
|
reset();
|
|
574
|
-
}, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Backup Codes" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(
|
|
539
|
+
}, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Backup Codes" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsxs("div", { className: "mfa-info-box", children: [_jsx("div", { className: "mfa-info-icon", children: _jsx(IoKeyOutline, { size: 20 }) }), _jsx("p", { className: "mfa-info-text", children: "Backup codes can be used to access your account if you lose access to your primary authentication method. Store them securely as these codes will not be shown again." })] }), _jsx("div", { className: "wallet-modal-mfa-backup-heading", children: _jsx("span", { className: "wallet-modal-mfa-backup-heading-label", children: "Recovery Codes" }) }), _jsx("div", { className: "wallet-modal-mfa-backup-list", children: mfaBackupCodes.map((code, index) => (_jsx("div", { className: "wallet-modal-mfa-backup-code-wrapper", children: _jsx("code", { className: "wallet-modal-mfa-backup-code", children: code }) }, index))) }), _jsxs("div", { className: "wallet-modal-mfa-backup-actions", children: [_jsxs("button", { type: "button", className: `wallet-modal-mfa-backup-action-btn ${mfaBackupCodesCopied ? 'copied' : ''}`, onClick: handleCopyBackupCodes, disabled: !mfaBackupCodes.length, children: [mfaBackupCodesCopied ? _jsx(IoCheckmarkOutline, { size: 18 }) : _jsx(IoCopyOutline, { size: 18 }), mfaBackupCodesCopied ? "Copied" : "Copy All"] }), _jsxs("button", { type: "button", className: "wallet-modal-mfa-backup-action-btn", onClick: handleDownloadBackupCodes, disabled: !mfaBackupCodes.length, children: [_jsx(IoCloudDownloadOutline, { size: 18 }), "Download"] })] }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: () => {
|
|
575
540
|
setShowMfaBackupModal(false);
|
|
576
541
|
reset();
|
|
577
542
|
}, children: "I've saved these codes" })] })] }) }));
|
|
578
543
|
}
|
|
579
544
|
if (showMfaDisableAuthModal) {
|
|
580
|
-
return (_jsx(
|
|
581
|
-
if (mfaDisableStep === "recovery") {
|
|
582
|
-
setMfaDisableStep("otp");
|
|
583
|
-
setMfaDisableRecoveryCode("");
|
|
584
|
-
setMfaDisableError(null);
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
resetMfaDisableState();
|
|
588
|
-
}, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Verify to disable 2FA" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsx("div", { className: "mfa-info-box", children: _jsx("p", { className: "mfa-info-text", children: "Enter your authentication code to continue." }) }), mfaDisableStep === "otp" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsx("div", { className: "mfa-otp-grid", children: [0, 1, 2, 3, 4, 5].map((index) => (_jsx("div", { className: "mfa-otp-slot", children: _jsx("input", { type: "text", inputMode: "numeric", maxLength: 1, value: mfaDisableCode[index] || "", onChange: (e) => {
|
|
589
|
-
const val = e.target.value.replace(/\D/g, "");
|
|
590
|
-
if (val) {
|
|
591
|
-
const newCode = mfaDisableCode.split("");
|
|
592
|
-
newCode[index] = val;
|
|
593
|
-
const combined = newCode.join("").slice(0, 6);
|
|
594
|
-
setMfaDisableCode(combined);
|
|
595
|
-
if (combined.length === 6) {
|
|
596
|
-
window.setTimeout(() => {
|
|
597
|
-
mfaDisableVerifyButtonRef.current?.focus();
|
|
598
|
-
}, 0);
|
|
599
|
-
}
|
|
600
|
-
if (index < 5) {
|
|
601
|
-
const target = e.target;
|
|
602
|
-
const next = target.parentElement?.nextElementSibling?.querySelector("input");
|
|
603
|
-
next?.focus();
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}, onKeyDown: (e) => {
|
|
607
|
-
if (e.key === "Backspace") {
|
|
608
|
-
const target = e.target;
|
|
609
|
-
if (!mfaDisableCode[index] && index > 0) {
|
|
610
|
-
const prev = target.parentElement?.previousElementSibling?.querySelector("input");
|
|
611
|
-
prev?.focus();
|
|
612
|
-
const newCode = mfaDisableCode.split("");
|
|
613
|
-
newCode[index - 1] = "";
|
|
614
|
-
setMfaDisableCode(newCode.join(""));
|
|
615
|
-
}
|
|
616
|
-
else {
|
|
617
|
-
const newCode = mfaDisableCode.split("");
|
|
618
|
-
newCode[index] = "";
|
|
619
|
-
setMfaDisableCode(newCode.join(""));
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}, className: "mfa-otp-input" }) }, index))) }), _jsx("button", { ref: mfaDisableVerifyButtonRef, type: "button", className: "mfa-verify-button", onClick: handleMfaDisableVerifyCode, disabled: mfaDisableLoading || mfaDisableCode.length !== 6, children: mfaDisableLoading ? "Verifying..." : "Verify" }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", onClick: () => {
|
|
623
|
-
setMfaDisableStep("recovery");
|
|
624
|
-
setMfaDisableError(null);
|
|
625
|
-
setMfaDisableRecoveryCode("");
|
|
626
|
-
}, children: "Use a backup code" })] })] })) : (_jsxs("div", { className: "mfa-recovery-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 8 charater backup code" }) }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsx("input", { type: "text", inputMode: "text", maxLength: 8, value: mfaDisableRecoveryCode, onChange: (e) => {
|
|
627
|
-
const val = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 8);
|
|
628
|
-
setMfaDisableRecoveryCode(val);
|
|
629
|
-
}, className: "mfa-recovery-field" }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: handleMfaDisableVerifyRecoveryCode, disabled: mfaDisableLoading || mfaDisableRecoveryCode.trim().length !== 8, children: mfaDisableLoading ? "Verifying..." : "Verify" })] }))] })] }) }));
|
|
545
|
+
return (_jsx(MfaVerifyModal, { isOpen: true, theme: theme, title: "Verify to disable 2FA", description: "Enter your authentication code to continue.", loading: mfaDisableLoading, error: mfaDisableError, onSubmit: handleMfaDisableVerify, onCancel: resetMfaDisableState }));
|
|
630
546
|
}
|
|
631
547
|
if (showMfaStatusModal) {
|
|
632
|
-
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => setShowMfaStatusModal(false), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => setShowMfaStatusModal(false), "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "MFA" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(
|
|
548
|
+
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => setShowMfaStatusModal(false), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => setShowMfaStatusModal(false), "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "MFA" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsxs("div", { className: "mfa-info-box mfa-status-enabled-box", children: [_jsx("div", { className: "mfa-info-icon mfa-status-enabled-icon", children: _jsx(IoCheckmarkOutline, { size: 22 }) }), _jsxs("div", { className: "mfa-status-enabled-copy", children: [_jsx("p", { className: "mfa-status-enabled-title", children: "MFA is enabled" }), _jsx("p", { className: "mfa-info-text", children: "Your wallet is protected with an additional verification step." })] })] }), _jsx("button", { type: "button", className: "mfa-verify-button mfa-disable-primary-button", onClick: openMfaDisableFlow, children: "Disable MFA" })] })] }) }));
|
|
633
549
|
}
|
|
634
550
|
if (showLinkedProfilesList) {
|
|
635
|
-
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick:
|
|
551
|
+
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: handleCloseLinkedProfiles, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: () => emailLinkStep ? cancelEmailLink() : handleCloseLinkedProfiles(), "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: emailLinkStep ? "Link email" : "Auth Methods" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsx("div", { className: "wallet-modal-manage-content", children: emailLinkStep ? (_jsx("div", { className: "wallet-modal-email-link-flow", children: emailLinkStep === "email" ? (_jsxs("form", { className: "wallet-modal-email-link-form", onSubmit: (e) => {
|
|
636
552
|
e.preventDefault();
|
|
637
553
|
if (!actionProvider && emailLinkEmail.trim()) {
|
|
638
554
|
handleSendOtpForLink();
|
|
@@ -641,7 +557,7 @@ export function ManageWalletModal({ ...props }) {
|
|
|
641
557
|
emailLinkOtpInputsRef.current[index] = el;
|
|
642
558
|
}, type: "text", inputMode: "numeric", maxLength: 1, className: "mfa-otp-input", value: emailLinkOtpCode[index] || "", onChange: (e) => handleEmailLinkOtpChange(index, e.target.value), onKeyDown: (e) => handleEmailLinkOtpKeyDown(index, e), disabled: actionProvider === "email" || emailLinkResending }) }, index))) }), _jsx("button", { type: "button", className: "wallet-modal-email-link-button", onClick: handleLinkEmailSubmit, disabled: actionProvider === "email" ||
|
|
643
559
|
emailLinkResending ||
|
|
644
|
-
emailLinkOtpCode.trim().length !== 6, children: actionProvider === "email" ? "Linking..." : "Link email" }), _jsxs("p", { className: "wallet-modal-email-link-resend", children: ["Didn't receive the code?", " ", emailLinkResendCooldown > 0 ? (_jsxs("span", { className: "wallet-modal-email-link-resend-cooldown", children: ["Resend in ", emailLinkResendCooldown, "s"] })) : (_jsx("button", { type: "button", className: "wallet-modal-email-link-resend-button", onClick: handleResendOtpForLink, disabled: emailLinkResending || actionProvider === "email", children: emailLinkResending ? "Sending..." : "Resend code" }))] })] })) })) : (_jsxs("div", { className: "wallet-modal-linked-profiles-list", children: [linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-loading", children: "Loading..." })), linkedError && !linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-error", children: linkedError })), !linkedLoading && !linkedError && supportedMethods.length === 0 && (_jsx("div", { className: "wallet-modal-linked-profiles-empty", children: "No auth methods available." })), !linkedLoading &&
|
|
560
|
+
emailLinkOtpCode.trim().length !== 6, children: actionProvider === "email" ? "Linking..." : "Link email" }), _jsxs("p", { className: "wallet-modal-email-link-resend", children: ["Didn't receive the code?", " ", emailLinkResendCooldown > 0 ? (_jsxs("span", { className: "wallet-modal-email-link-resend-cooldown", children: ["Resend in ", emailLinkResendCooldown, "s"] })) : (_jsx("button", { type: "button", className: "wallet-modal-email-link-resend-button", onClick: handleResendOtpForLink, disabled: emailLinkResending || actionProvider === "email", children: emailLinkResending ? "Sending..." : "Resend code" }))] })] })) })) : (_jsxs("div", { className: "wallet-modal-linked-profiles-list", children: [linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-loading", children: "Loading..." })), linkedError && !linkedLoading && (_jsx("div", { className: "wallet-modal-linked-profiles-error", children: linkedError })), !linkedLoading && linkUnlinkSuccess && (_jsx("div", { className: "wallet-modal-linked-profiles-success", role: "status", children: linkUnlinkSuccess })), !linkedLoading && !linkedError && supportedMethods.length === 0 && (_jsx("div", { className: "wallet-modal-linked-profiles-empty", children: "No auth methods available." })), !linkedLoading &&
|
|
645
561
|
supportedMethods.map((method) => {
|
|
646
562
|
const linked = isProviderLinked(method.provider);
|
|
647
563
|
const busy = actionProvider === method.provider;
|
|
@@ -663,9 +579,10 @@ export function ManageWalletModal({ ...props }) {
|
|
|
663
579
|
? `Passkey ID: ${unlinkConfirm.id}`
|
|
664
580
|
: `Provider ID: ${unlinkConfirm.id}` }))] }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => handleDisconnect(unlinkConfirm.provider), disabled: actionProvider === unlinkConfirm.provider, children: unlinkConfirm.provider.toLowerCase() === "passkey"
|
|
665
581
|
? "Remove Passkey"
|
|
666
|
-
: "Remove Provider" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(
|
|
582
|
+
: "Remove Provider" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget), linkUnlinkError &&
|
|
583
|
+
createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => setLinkUnlinkError(null), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), role: "alertdialog", "aria-modal": "true", "aria-labelledby": "wallet-modal-auth-error-title", "aria-describedby": "wallet-modal-auth-error-message", children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { id: "wallet-modal-auth-error-title", className: "wallet-modal-unlink-confirm-title", children: "Error" }), _jsx("p", { id: "wallet-modal-auth-error-message", className: "wallet-modal-auth-error-message", children: linkUnlinkError }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => setLinkUnlinkError(null), children: "Ok" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setLinkUnlinkError(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget)] }) }));
|
|
667
584
|
}
|
|
668
|
-
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: onClose, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: onClose, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Manage Wallet" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(
|
|
585
|
+
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: onClose, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { className: "wallet-modal-back", onClick: onClose, "aria-label": "Back", children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: "Manage Wallet" }), _jsx("button", { className: "wallet-modal-close", onClick: onClose, "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }), _jsx("div", { className: "wallet-modal-manage-content", children: _jsxs("div", { className: "wallet-modal-manage-list", children: [!isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: handleOpenLinkedProfiles, type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(FiUsers, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "Auth Methods" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] })), !isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: () => {
|
|
669
586
|
if (mfaStatusLoading)
|
|
670
587
|
return;
|
|
671
588
|
if (!canEnableMfaFlow) {
|
|
@@ -677,7 +594,7 @@ export function ManageWalletModal({ ...props }) {
|
|
|
677
594
|
}
|
|
678
595
|
startMfaSetup();
|
|
679
596
|
}, type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(BiShieldQuarter, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "MFA" }), _jsx("span", { className: `wallet-modal-mfa-badge ${mfaStatus?.enabled ? "wallet-modal-mfa-badge-enabled" : "wallet-modal-mfa-badge-disabled"}`, "aria-hidden": "true", children: mfaStatus?.enabled ? "Enabled" : "Disabled" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] })), _jsxs("button", { className: "wallet-modal-manage-list-item", onClick: () => showFeedback("Coming soon", "success"), type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(SiWalletconnect, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "Connect an App" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] }), !isExternalWalletConnected && (_jsxs("button", { className: "wallet-modal-manage-list-item", onClick: onExportPrivateKey, type: "button", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(IoKeyOutline, { size: 20 }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: "Export Private Key" }), _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", className: "wallet-modal-manage-list-arrow", "aria-hidden": "true", children: _jsx("path", { d: "M6 12L10 8L6 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })] }))] }) }), showMfaDisableConfirmModal &&
|
|
680
|
-
createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => resetMfaDisableState(), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { className: "wallet-modal-unlink-confirm-title", children: "Disable two-factor authentication" }), _jsx("p", { className: "wallet-modal-unlink-confirm-subtitle", children: "You are about to disable two-factor authentication. Your account will be less secure. Do you want to continue?" }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsxs("div", { className: "wallet-modal-mfa-disable-actions", children: [_jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn wallet-modal-mfa-disable-cancel", onClick: () => resetMfaDisableState(), disabled: mfaDisableLoading, children: "Cancel" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => handleMfaDisableConfirm(), disabled: mfaDisableLoading, children: mfaDisableLoading ? "Disabling..." : "Confirm disable" })] }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => resetMfaDisableState(), "aria-label": "Close", children: _jsx(
|
|
597
|
+
createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => resetMfaDisableState(), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { className: "wallet-modal-unlink-confirm-title", children: "Disable two-factor authentication" }), _jsx("p", { className: "wallet-modal-unlink-confirm-subtitle", children: "You are about to disable two-factor authentication. Your account will be less secure. Do you want to continue?" }), mfaDisableError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: mfaDisableError })), _jsxs("div", { className: "wallet-modal-mfa-disable-actions", children: [_jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn wallet-modal-mfa-disable-cancel", onClick: () => resetMfaDisableState(), disabled: mfaDisableLoading, children: "Cancel" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => handleMfaDisableConfirm(), disabled: mfaDisableLoading, children: mfaDisableLoading ? "Disabling..." : "Confirm disable" })] }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => resetMfaDisableState(), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget), unlinkConfirm &&
|
|
681
598
|
createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => setUnlinkConfirm(null), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { className: "wallet-modal-unlink-confirm-title", children: unlinkConfirm.provider.toLowerCase() === "passkey"
|
|
682
599
|
? "Remove Passkey"
|
|
683
600
|
: "Remove OAuth Provider" }), _jsx("p", { className: "wallet-modal-unlink-confirm-subtitle", children: "This action is irreversible." }), _jsxs("div", { className: "wallet-modal-unlink-confirm-details", children: [_jsx("p", { className: "wallet-modal-unlink-confirm-details-line", children: unlinkConfirm.provider.toLowerCase() === "passkey"
|
|
@@ -691,8 +608,9 @@ export function ManageWalletModal({ ...props }) {
|
|
|
691
608
|
alignItems: "center",
|
|
692
609
|
gap: "6px",
|
|
693
610
|
verticalAlign: "middle",
|
|
694
|
-
}, children: [
|
|
611
|
+
}, children: [_jsx(AbstraxnLogo, { size: 18, gradientId: "abstraxn_logo_unlink_footer" }), _jsx("span", { style: {
|
|
695
612
|
color: theme === "dark" ? "#ffffff" : "#111827",
|
|
696
|
-
}, children: "abstraxn" })] })] }) }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(
|
|
613
|
+
}, children: "abstraxn" })] })] }) }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget), linkUnlinkError &&
|
|
614
|
+
createPortal(_jsx("div", { className: `wallet-modal-overlay wallet-modal-overlay-layer2 wallet-modal-theme-${theme}`, onClick: () => setLinkUnlinkError(null), children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-unlink-confirm-modal`, onClick: (e) => e.stopPropagation(), role: "alertdialog", "aria-modal": "true", "aria-labelledby": "wallet-modal-auth-error-title-main", "aria-describedby": "wallet-modal-auth-error-message-main", children: [_jsx("div", { className: "wallet-modal-unlink-confirm-icon", "aria-hidden": "true", children: _jsxs("svg", { width: "48", height: "48", viewBox: "0 0 24 24", fill: "none", children: [_jsx("circle", { cx: "12", cy: "12", r: "10", fill: "#ef4444" }), _jsx("path", { d: "M12 8v4M12 16h.01", stroke: "#ffffff", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })] }) }), _jsx("h3", { id: "wallet-modal-auth-error-title-main", className: "wallet-modal-unlink-confirm-title", children: "Error" }), _jsx("p", { id: "wallet-modal-auth-error-message-main", className: "wallet-modal-auth-error-message", children: linkUnlinkError }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-btn", onClick: () => setLinkUnlinkError(null), children: "Ok" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setLinkUnlinkError(null), "aria-label": "Close", children: _jsx(CloseIcon, { size: 24 }) })] }) }), portalTarget)] }) }));
|
|
697
615
|
}
|
|
698
616
|
//# sourceMappingURL=ManageWalletModal.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface MfaVerifyModalProps {
|
|
2
|
+
isOpen: boolean;
|
|
3
|
+
theme?: "light" | "dark";
|
|
4
|
+
title: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
submitLabel?: string;
|
|
7
|
+
loadingLabel?: string;
|
|
8
|
+
loading?: boolean;
|
|
9
|
+
error?: string | null;
|
|
10
|
+
/** When true, portals to document.body with its own ShadowHost (sign step-up). */
|
|
11
|
+
portal?: boolean;
|
|
12
|
+
onSubmit: (code: string) => void;
|
|
13
|
+
onCancel: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function MfaVerifyModal({ isOpen, theme, title, description, submitLabel, loadingLabel, loading, error, portal, onSubmit, onCancel, }: MfaVerifyModalProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Shared MFA verify UI (OTP + backup code) used by:
|
|
4
|
+
* - Manage Wallet → disable 2FA
|
|
5
|
+
* - Signing step-up (SIGN_MFA_REQUIRED) via SignMfaModalHost
|
|
6
|
+
*/
|
|
7
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { createPortal } from "react-dom";
|
|
9
|
+
import { CloseIcon, IoChevronBack } from "../../icons";
|
|
10
|
+
import { ShadowHost, ShadowHostContext } from "../../ShadowHost";
|
|
11
|
+
import { CodeInput } from "./CodeInput";
|
|
12
|
+
import walletModalCss from "../../../WalletModal.css.js";
|
|
13
|
+
import manageWalletModalCss from "./ManageWalletModal.css.js";
|
|
14
|
+
const MFA_VERIFY_PORTAL_CSS = [walletModalCss, manageWalletModalCss];
|
|
15
|
+
export function MfaVerifyModal({ isOpen, theme = "light", title, description = "Enter your authentication code to continue.", submitLabel = "Verify", loadingLabel = "Verifying...", loading = false, error = null, portal = false, onSubmit, onCancel, }) {
|
|
16
|
+
const [step, setStep] = useState("otp");
|
|
17
|
+
const [otpCode, setOtpCode] = useState("");
|
|
18
|
+
const [recoveryCode, setRecoveryCode] = useState("");
|
|
19
|
+
const [localError, setLocalError] = useState(null);
|
|
20
|
+
const submitRef = useRef(null);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!isOpen) {
|
|
23
|
+
setStep("otp");
|
|
24
|
+
setOtpCode("");
|
|
25
|
+
setRecoveryCode("");
|
|
26
|
+
setLocalError(null);
|
|
27
|
+
}
|
|
28
|
+
}, [isOpen]);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!isOpen)
|
|
31
|
+
return;
|
|
32
|
+
const onKey = (e) => {
|
|
33
|
+
if (e.key === "Escape" && !loading)
|
|
34
|
+
onCancel();
|
|
35
|
+
};
|
|
36
|
+
window.addEventListener("keydown", onKey);
|
|
37
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
38
|
+
}, [isOpen, loading, onCancel]);
|
|
39
|
+
const displayError = localError || error;
|
|
40
|
+
const canSubmit = useMemo(() => {
|
|
41
|
+
if (loading)
|
|
42
|
+
return false;
|
|
43
|
+
if (step === "otp")
|
|
44
|
+
return otpCode.length === 6;
|
|
45
|
+
return /^[A-Z0-9]{8}$/.test(recoveryCode.trim().toUpperCase());
|
|
46
|
+
}, [step, otpCode, recoveryCode, loading]);
|
|
47
|
+
const handleSubmit = useCallback(() => {
|
|
48
|
+
setLocalError(null);
|
|
49
|
+
if (step === "otp") {
|
|
50
|
+
if (otpCode.length !== 6) {
|
|
51
|
+
setLocalError("Please enter a 6-digit code");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
onSubmit(otpCode);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const trimmed = recoveryCode.trim().toUpperCase();
|
|
58
|
+
if (!/^[A-Z0-9]{8}$/.test(trimmed)) {
|
|
59
|
+
setLocalError("Please enter a valid 8-character backup code");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
onSubmit(trimmed);
|
|
63
|
+
}, [step, otpCode, recoveryCode, onSubmit]);
|
|
64
|
+
if (!isOpen || (portal && typeof document === "undefined"))
|
|
65
|
+
return null;
|
|
66
|
+
const content = (_jsx("div", { "data-abstraxn-sdk-root": portal ? true : undefined, className: `wallet-modal-overlay wallet-modal-theme-${theme}`, style: portal ? { zIndex: 10050 } : undefined, onClick: () => {
|
|
67
|
+
if (!loading)
|
|
68
|
+
onCancel();
|
|
69
|
+
}, children: _jsxs("div", { className: `wallet-modal-content wallet-modal-theme-${theme} wallet-modal-manage mfa-redesign-container`, onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "wallet-modal-receive-header", children: [_jsx("button", { type: "button", className: "wallet-modal-back", onClick: () => {
|
|
70
|
+
if (loading)
|
|
71
|
+
return;
|
|
72
|
+
if (step === "recovery") {
|
|
73
|
+
setStep("otp");
|
|
74
|
+
setRecoveryCode("");
|
|
75
|
+
setLocalError(null);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
onCancel();
|
|
79
|
+
}, "aria-label": "Back", disabled: loading, children: _jsx(IoChevronBack, { size: 20 }) }), _jsx("h2", { className: "wallet-modal-receive-title", children: title }), _jsx("button", { type: "button", className: "wallet-modal-close", onClick: () => {
|
|
80
|
+
if (!loading)
|
|
81
|
+
onCancel();
|
|
82
|
+
}, "aria-label": "Close", disabled: loading, children: _jsx(CloseIcon, { size: 24 }) })] }), _jsxs("div", { className: "mfa-redesign-content", children: [_jsx("div", { className: "mfa-info-box", children: _jsx("p", { className: "mfa-info-text", children: description }) }), step === "otp" ? (_jsxs("div", { className: "mfa-verification-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 6-digit verification code" }) }), displayError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: displayError })), _jsx(CodeInput, { length: 6, value: otpCode, onChange: setOtpCode, disabled: loading, onComplete: () => {
|
|
83
|
+
window.setTimeout(() => submitRef.current?.focus(), 0);
|
|
84
|
+
} }), _jsx("button", { ref: submitRef, type: "button", className: "mfa-verify-button", onClick: handleSubmit, disabled: !canSubmit, children: loading ? loadingLabel : submitLabel }), _jsxs("p", { className: "mfa-trouble-text", children: ["Having trouble?", " ", _jsx("button", { type: "button", className: "mfa-link-button", disabled: loading, onClick: () => {
|
|
85
|
+
setStep("recovery");
|
|
86
|
+
setLocalError(null);
|
|
87
|
+
setRecoveryCode("");
|
|
88
|
+
}, children: "Use a backup code" })] })] })) : (_jsxs("div", { className: "mfa-recovery-section", children: [_jsx("div", { className: "mfa-divider", children: _jsx("span", { children: "Enter 8 character backup code" }) }), displayError && (_jsx("p", { className: "mfa-setup-error", style: { marginBottom: 12 }, children: displayError })), _jsx("input", { type: "text", inputMode: "text", maxLength: 8, value: recoveryCode, disabled: loading, onChange: (e) => {
|
|
89
|
+
setRecoveryCode(e.target.value
|
|
90
|
+
.toUpperCase()
|
|
91
|
+
.replace(/[^A-Z0-9]/g, "")
|
|
92
|
+
.slice(0, 8));
|
|
93
|
+
}, className: "mfa-recovery-field", autoFocus: true }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: handleSubmit, disabled: !canSubmit, children: loading ? loadingLabel : submitLabel })] }))] })] }) }));
|
|
94
|
+
if (!portal)
|
|
95
|
+
return content;
|
|
96
|
+
return createPortal(_jsx(ShadowHostContext.Provider, { value: null, children: _jsx(ShadowHost, { cssTexts: MFA_VERIFY_PORTAL_CSS, children: content }) }), document.body);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=MfaVerifyModal.js.map
|