@abstraxn/signer-react 2.1.5 → 2.2.1
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 +21 -0
- package/dist/src/ExternalWalletButtons.js +8 -3
- package/dist/src/ExternalWalletButtons.js.map +1 -1
- package/dist/src/WalletModal.css +0 -1
- package/dist/src/WalletModal.js +10 -4
- package/dist/src/WalletModal.js.map +1 -1
- package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js +557 -81
- package/dist/src/components/AbstraxnProvider/AbstraxnProviderInner.js.map +1 -1
- package/dist/src/components/AbstraxnProvider/useOAuthCallbacks.d.ts +2 -1
- package/dist/src/components/AbstraxnProvider/useOAuthCallbacks.js +72 -8
- package/dist/src/components/AbstraxnProvider/useOAuthCallbacks.js.map +1 -1
- package/dist/src/components/AbstraxnProvider/useWalletInitialization.js +16 -11
- package/dist/src/components/AbstraxnProvider/useWalletInitialization.js.map +1 -1
- package/dist/src/components/AbstraxnProvider/utils.d.ts +5 -0
- package/dist/src/components/AbstraxnProvider/utils.js +9 -0
- package/dist/src/components/AbstraxnProvider/utils.js.map +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUI.css +186 -6
- package/dist/src/components/OnboardingUI/OnboardingUIReact.js +18 -4
- package/dist/src/components/OnboardingUI/OnboardingUIReact.js.map +1 -1
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.d.ts +21 -0
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js +528 -20
- package/dist/src/components/OnboardingUI/OnboardingUIWeb.js.map +1 -1
- package/dist/src/components/OnboardingUI/components/EmailForm.js +2 -1
- package/dist/src/components/OnboardingUI/components/EmailForm.js.map +1 -1
- package/dist/src/components/OnboardingUI/components/MfaForm.d.ts +17 -0
- package/dist/src/components/OnboardingUI/components/MfaForm.js +81 -0
- package/dist/src/components/OnboardingUI/components/MfaForm.js.map +1 -0
- package/dist/src/components/OnboardingUI/components/index.d.ts +2 -0
- package/dist/src/components/OnboardingUI/components/index.js +1 -0
- package/dist/src/components/OnboardingUI/components/index.js.map +1 -1
- package/dist/src/components/OnboardingUI/hooks/useAuthMethods.js +3 -0
- package/dist/src/components/OnboardingUI/hooks/useAuthMethods.js.map +1 -1
- package/dist/src/components/OnboardingUI/hooks/useOnboarding.d.ts +4 -1
- package/dist/src/components/OnboardingUI/hooks/useOnboarding.js +65 -2
- package/dist/src/components/OnboardingUI/hooks/useOnboarding.js.map +1 -1
- package/dist/src/components/WalletModal/components/ManageWalletModal.css +1443 -2
- package/dist/src/components/WalletModal/components/ManageWalletModal.js +737 -23
- package/dist/src/components/WalletModal/components/ManageWalletModal.js.map +1 -1
- package/dist/src/components/WalletModal/components/ReceiveModal.css +0 -1
- package/dist/src/components/WalletModal/hooks/useSendTransaction.js +67 -12
- package/dist/src/components/WalletModal/hooks/useSendTransaction.js.map +1 -1
- package/dist/src/types.d.ts +17 -0
- package/dist/src/wagmiConfig.js +1 -0
- package/dist/src/wagmiConfig.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
|
@@ -1,36 +1,750 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Manage Wallet Modal Component
|
|
4
4
|
*/
|
|
5
5
|
import { useEffect, useRef, useState, useCallback } from "react";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { createPortal } from "react-dom";
|
|
7
|
+
import { IoKeyOutline, IoCopyOutline, IoCheckmarkOutline, IoCloudDownloadOutline, IoChevronBack, IoClose, IoPhonePortraitOutline } from "react-icons/io5";
|
|
8
|
+
import { SiWalletconnect, SiDiscord, SiX } from "react-icons/si";
|
|
9
|
+
import { FcGoogle } from "react-icons/fc";
|
|
10
|
+
import { FiUsers, FiLink } from "react-icons/fi";
|
|
11
|
+
import { TfiEmail } from "react-icons/tfi";
|
|
12
|
+
import { BiShieldQuarter } from "react-icons/bi";
|
|
13
|
+
import { useAbstraxnWallet } from "../../../AbstraxnProvider";
|
|
9
14
|
import "./ManageWalletModal.css";
|
|
15
|
+
import { QRCodeSVG } from "qrcode.react";
|
|
16
|
+
function normalizeLinkedProvider(authProvider) {
|
|
17
|
+
return authProvider === "otp" ? "email" : authProvider;
|
|
18
|
+
}
|
|
19
|
+
function AuthMethodIcon({ provider }) {
|
|
20
|
+
const p = provider.toLowerCase();
|
|
21
|
+
if (p === "google")
|
|
22
|
+
return _jsx(FcGoogle, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-google" });
|
|
23
|
+
if (p === "discord")
|
|
24
|
+
return _jsx(SiDiscord, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-discord" });
|
|
25
|
+
if (p === "x" || p === "twitter")
|
|
26
|
+
return _jsx(SiX, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-x" });
|
|
27
|
+
if (p === "email")
|
|
28
|
+
return _jsx(TfiEmail, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-email" });
|
|
29
|
+
if (p === "passkey")
|
|
30
|
+
return _jsx(IoKeyOutline, { size: 20, className: "wallet-modal-provider-icon wallet-modal-provider-icon-passkey" });
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
10
33
|
export function ManageWalletModal({ ...props }) {
|
|
11
|
-
const { isOpen, onClose, isExternalWalletConnected, onExportPrivateKey, theme = "dark", } = props;
|
|
12
|
-
const
|
|
13
|
-
const [
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
const { isOpen, onClose, isExternalWalletConnected, onExportPrivateKey, theme = "dark", userEmail, organizationName, } = props;
|
|
35
|
+
const { getSupportedAuthMethods, getLinkedAuthMethods, linkAuthMethod, linkEmail, loginWithOTP, requestOtpForEmailLink, unlinkAuthMethod, whoami, getMfaStatus, enableMfa, verifySetupMfa, verifyMfa, disableMfaWithSignedPayload, } = useAbstraxnWallet();
|
|
36
|
+
const [showLinkedProfilesList, setShowLinkedProfilesList] = useState(false);
|
|
37
|
+
const [supportedMethods, setSupportedMethods] = useState([]);
|
|
38
|
+
const [linkedMethods, setLinkedMethods] = useState([]);
|
|
39
|
+
const [linkedLoading, setLinkedLoading] = useState(false);
|
|
40
|
+
const [linkedError, setLinkedError] = useState(null);
|
|
41
|
+
const [actionProvider, setActionProvider] = useState(null);
|
|
42
|
+
const [unlinkConfirm, setUnlinkConfirm] = useState(null);
|
|
43
|
+
const [linkUnlinkSuccess, setLinkUnlinkSuccess] = useState(null);
|
|
44
|
+
const [linkUnlinkError, setLinkUnlinkError] = useState(null);
|
|
45
|
+
const [emailLinkStep, setEmailLinkStep] = useState(null);
|
|
46
|
+
const [emailLinkEmail, setEmailLinkEmail] = useState("");
|
|
47
|
+
const [emailLinkOtpId, setEmailLinkOtpId] = useState(null);
|
|
48
|
+
const [emailLinkOtpCode, setEmailLinkOtpCode] = useState("");
|
|
49
|
+
const [emailLinkError, setEmailLinkError] = useState(null);
|
|
50
|
+
const [emailLinkResending, setEmailLinkResending] = useState(false);
|
|
51
|
+
const [emailLinkResendCooldown, setEmailLinkResendCooldown] = useState(0);
|
|
52
|
+
const emailLinkOtpInputsRef = useRef([]);
|
|
53
|
+
// MFA state
|
|
54
|
+
const [mfaStatus, setMfaStatus] = useState(null);
|
|
55
|
+
const [mfaLoading, setMfaLoading] = useState(false);
|
|
56
|
+
const [mfaError, setMfaError] = useState(null);
|
|
57
|
+
// MFA setup flow state (QR + secret + TOTP + backup codes)
|
|
58
|
+
const [showMfaSetupModal, setShowMfaSetupModal] = useState(false);
|
|
59
|
+
const [mfaSetupStep, setMfaSetupStep] = useState("setup");
|
|
60
|
+
const [mfaQrCode, setMfaQrCode] = useState(null);
|
|
61
|
+
const [mfaSecret, setMfaSecret] = useState(null);
|
|
62
|
+
const [mfaSetupCode, setMfaSetupCode] = useState("");
|
|
63
|
+
const [mfaRecoveryCode, setMfaRecoveryCode] = useState("");
|
|
64
|
+
const [mfaSetupLoading, setMfaSetupLoading] = useState(false);
|
|
65
|
+
const [mfaSetupError, setMfaSetupError] = useState(null);
|
|
66
|
+
const [mfaBackupCodes, setMfaBackupCodes] = useState([]);
|
|
67
|
+
const [showMfaBackupModal, setShowMfaBackupModal] = useState(false);
|
|
68
|
+
const [mfaSecretCopied, setMfaSecretCopied] = useState(false);
|
|
69
|
+
const [mfaBackupCodesCopied, setMfaBackupCodesCopied] = useState(false);
|
|
70
|
+
const mfaSetupVerifyButtonRef = useRef(null);
|
|
71
|
+
// MFA disable flow state (auth code modal -> confirm disable modal)
|
|
72
|
+
const [showMfaDisableAuthModal, setShowMfaDisableAuthModal] = useState(false);
|
|
73
|
+
const [showMfaDisableConfirmModal, setShowMfaDisableConfirmModal] = useState(false);
|
|
74
|
+
const [showMfaStatusModal, setShowMfaStatusModal] = useState(false);
|
|
75
|
+
const [mfaDisableStep, setMfaDisableStep] = useState("otp");
|
|
76
|
+
const [mfaDisableCode, setMfaDisableCode] = useState("");
|
|
77
|
+
const [mfaDisableRecoveryCode, setMfaDisableRecoveryCode] = useState("");
|
|
78
|
+
const [mfaDisableLoading, setMfaDisableLoading] = useState(false);
|
|
79
|
+
const [mfaDisableError, setMfaDisableError] = useState(null);
|
|
80
|
+
const mfaDisableVerifyButtonRef = useRef(null);
|
|
81
|
+
const showFeedback = useCallback((message, type = "success") => {
|
|
82
|
+
if (type === "error") {
|
|
83
|
+
setLinkUnlinkError(message);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
setLinkUnlinkSuccess(message);
|
|
23
87
|
}, []);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
88
|
+
const fetchLinkedProfilesData = useCallback(async () => {
|
|
89
|
+
if (!getSupportedAuthMethods || !getLinkedAuthMethods || isExternalWalletConnected)
|
|
90
|
+
return;
|
|
91
|
+
setLinkedLoading(true);
|
|
92
|
+
setLinkedError(null);
|
|
93
|
+
try {
|
|
94
|
+
const [supportedRes, linkedRes] = await Promise.all([
|
|
95
|
+
getSupportedAuthMethods(),
|
|
96
|
+
getLinkedAuthMethods(),
|
|
97
|
+
]);
|
|
98
|
+
const loginProvider = whoami?.loginProvider?.toLowerCase();
|
|
99
|
+
const supported = supportedRes.supportedMethods ?? [];
|
|
100
|
+
const filteredSupported = loginProvider != null && loginProvider !== ""
|
|
101
|
+
? supported.filter((method) => method.provider.toLowerCase() !== loginProvider)
|
|
102
|
+
: supported;
|
|
103
|
+
setSupportedMethods(filteredSupported);
|
|
104
|
+
setLinkedMethods(linkedRes.linkedMethods ?? []);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
const msg = err instanceof Error ? err.message : "Failed to load auth methods";
|
|
108
|
+
setLinkedError(msg);
|
|
109
|
+
setSupportedMethods([]);
|
|
110
|
+
setLinkedMethods([]);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
setLinkedLoading(false);
|
|
114
|
+
}
|
|
115
|
+
}, [getSupportedAuthMethods, getLinkedAuthMethods, isExternalWalletConnected, whoami]);
|
|
116
|
+
const handleOpenLinkedProfiles = useCallback(() => {
|
|
117
|
+
setShowLinkedProfilesList(true);
|
|
118
|
+
fetchLinkedProfilesData();
|
|
119
|
+
}, [fetchLinkedProfilesData]);
|
|
120
|
+
const isProviderLinked = useCallback((provider) => {
|
|
121
|
+
return linkedMethods.some((m) => normalizeLinkedProvider(m.authProvider) === provider.toLowerCase());
|
|
122
|
+
}, [linkedMethods]);
|
|
123
|
+
const handleConnect = useCallback(async (provider) => {
|
|
124
|
+
if (provider.toLowerCase() === "email") {
|
|
125
|
+
setEmailLinkStep("email");
|
|
126
|
+
setEmailLinkEmail("");
|
|
127
|
+
setEmailLinkOtpId(null);
|
|
128
|
+
setEmailLinkOtpCode("");
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (!linkAuthMethod)
|
|
132
|
+
return;
|
|
133
|
+
setActionProvider(provider);
|
|
134
|
+
try {
|
|
135
|
+
await linkAuthMethod(provider);
|
|
136
|
+
const lower = provider.toLowerCase();
|
|
137
|
+
const message = lower === "passkey"
|
|
138
|
+
? "Successfully added passkey!"
|
|
139
|
+
: "Connected successfully";
|
|
140
|
+
showFeedback(message, "success");
|
|
141
|
+
await fetchLinkedProfilesData();
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
const msg = err instanceof Error ? err.message : "Failed to connect";
|
|
145
|
+
setLinkUnlinkError(msg);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
setActionProvider(null);
|
|
149
|
+
}
|
|
150
|
+
}, [linkAuthMethod, fetchLinkedProfilesData, showFeedback]);
|
|
151
|
+
const handleSendOtpForLink = useCallback(async () => {
|
|
152
|
+
if (!emailLinkEmail.trim())
|
|
153
|
+
return;
|
|
154
|
+
const sendOtp = requestOtpForEmailLink ?? loginWithOTP;
|
|
155
|
+
if (!sendOtp)
|
|
156
|
+
return;
|
|
157
|
+
setEmailLinkError(null);
|
|
158
|
+
setActionProvider("email");
|
|
159
|
+
try {
|
|
160
|
+
const { otpId } = await sendOtp(emailLinkEmail.trim());
|
|
161
|
+
setEmailLinkOtpId(otpId);
|
|
162
|
+
setEmailLinkStep("otp");
|
|
163
|
+
setEmailLinkOtpCode("");
|
|
164
|
+
setEmailLinkResendCooldown(60);
|
|
165
|
+
showFeedback("Check your email for the code", "success");
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
const msg = err instanceof Error ? err.message : "Failed to send OTP";
|
|
169
|
+
setEmailLinkError(msg);
|
|
170
|
+
showFeedback(msg, "error");
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
setActionProvider(null);
|
|
174
|
+
}
|
|
175
|
+
}, [requestOtpForEmailLink, loginWithOTP, emailLinkEmail, showFeedback]);
|
|
176
|
+
const handleResendOtpForLink = useCallback(async () => {
|
|
177
|
+
if (!emailLinkEmail.trim() || emailLinkResendCooldown > 0)
|
|
178
|
+
return;
|
|
179
|
+
const sendOtp = requestOtpForEmailLink ?? loginWithOTP;
|
|
180
|
+
if (!sendOtp)
|
|
181
|
+
return;
|
|
182
|
+
setEmailLinkResending(true);
|
|
183
|
+
setEmailLinkError(null);
|
|
184
|
+
try {
|
|
185
|
+
const { otpId } = await sendOtp(emailLinkEmail.trim());
|
|
186
|
+
setEmailLinkOtpId(otpId);
|
|
187
|
+
setEmailLinkOtpCode("");
|
|
188
|
+
setEmailLinkResendCooldown(60);
|
|
189
|
+
showFeedback("Code resent", "success");
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
const msg = err instanceof Error ? err.message : "Failed to resend";
|
|
193
|
+
setEmailLinkError(msg);
|
|
194
|
+
showFeedback(msg, "error");
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
setEmailLinkResending(false);
|
|
198
|
+
}
|
|
199
|
+
}, [requestOtpForEmailLink, loginWithOTP, emailLinkEmail, emailLinkResendCooldown, showFeedback]);
|
|
200
|
+
const handleLinkEmailSubmit = useCallback(async () => {
|
|
201
|
+
if (!linkEmail || !emailLinkOtpId || !emailLinkOtpCode.trim())
|
|
202
|
+
return;
|
|
203
|
+
setEmailLinkError(null);
|
|
204
|
+
setActionProvider("email");
|
|
205
|
+
try {
|
|
206
|
+
await linkEmail(emailLinkOtpId, emailLinkOtpCode.trim());
|
|
207
|
+
const message = "Email linked successfully";
|
|
208
|
+
showFeedback(message, "success");
|
|
209
|
+
setEmailLinkStep(null);
|
|
210
|
+
setEmailLinkEmail("");
|
|
211
|
+
setEmailLinkOtpId(null);
|
|
212
|
+
setEmailLinkOtpCode("");
|
|
213
|
+
setEmailLinkError(null);
|
|
214
|
+
await fetchLinkedProfilesData();
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
const msg = err instanceof Error ? err.message : "Failed to link email";
|
|
218
|
+
setEmailLinkError(msg);
|
|
219
|
+
showFeedback(msg, "error");
|
|
220
|
+
}
|
|
221
|
+
finally {
|
|
222
|
+
setActionProvider(null);
|
|
223
|
+
}
|
|
224
|
+
}, [linkEmail, emailLinkOtpId, emailLinkOtpCode, fetchLinkedProfilesData, showFeedback]);
|
|
225
|
+
const cancelEmailLink = useCallback(() => {
|
|
226
|
+
setEmailLinkStep(null);
|
|
227
|
+
setEmailLinkEmail("");
|
|
228
|
+
setEmailLinkOtpId(null);
|
|
229
|
+
setEmailLinkOtpCode("");
|
|
230
|
+
setEmailLinkError(null);
|
|
231
|
+
setEmailLinkResending(false);
|
|
232
|
+
setEmailLinkResendCooldown(0);
|
|
233
|
+
}, []);
|
|
234
|
+
const handleEmailLinkOtpChange = useCallback((index, value) => {
|
|
235
|
+
if (value && !/^\d$/.test(value))
|
|
236
|
+
return;
|
|
237
|
+
const digits = (emailLinkOtpCode || "").split("").slice(0, 6);
|
|
238
|
+
while (digits.length < 6)
|
|
239
|
+
digits.push("");
|
|
240
|
+
const next = digits.map((d, i) => (i === index ? value : d)).join("");
|
|
241
|
+
const cleaned = next.replace(/\s/g, "").slice(0, 6);
|
|
242
|
+
setEmailLinkOtpCode(cleaned);
|
|
243
|
+
if (value && index < 5) {
|
|
244
|
+
const nextInput = emailLinkOtpInputsRef.current[index + 1];
|
|
245
|
+
nextInput?.focus();
|
|
246
|
+
}
|
|
247
|
+
}, [emailLinkOtpCode]);
|
|
248
|
+
const handleEmailLinkOtpKeyDown = useCallback(async (index, e) => {
|
|
249
|
+
const digits = (emailLinkOtpCode || "").split("").slice(0, 6);
|
|
250
|
+
// Backspace navigation
|
|
251
|
+
if (e.key === "Backspace" && !digits[index] && index > 0) {
|
|
252
|
+
emailLinkOtpInputsRef.current[index - 1]?.focus();
|
|
253
|
+
}
|
|
254
|
+
// Paste via keyboard shortcut
|
|
255
|
+
if (e.key === "v" && (e.ctrlKey || e.metaKey)) {
|
|
256
|
+
e.preventDefault();
|
|
257
|
+
try {
|
|
258
|
+
const text = await navigator.clipboard.readText();
|
|
259
|
+
const pasted = text.replace(/\D/g, "").slice(0, 6);
|
|
260
|
+
if (!pasted)
|
|
261
|
+
return;
|
|
262
|
+
setEmailLinkOtpCode(pasted);
|
|
263
|
+
if (pasted.length === 6) {
|
|
264
|
+
emailLinkOtpInputsRef.current[5]?.focus();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
// ignore clipboard errors
|
|
29
269
|
}
|
|
30
|
-
}
|
|
270
|
+
}
|
|
271
|
+
}, [emailLinkOtpCode]);
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
if (emailLinkOtpCode.trim().length === 6 &&
|
|
274
|
+
actionProvider !== "email" &&
|
|
275
|
+
!emailLinkResending &&
|
|
276
|
+
!emailLinkError) {
|
|
277
|
+
handleLinkEmailSubmit();
|
|
278
|
+
}
|
|
279
|
+
}, [emailLinkOtpCode, actionProvider, emailLinkResending, emailLinkError, handleLinkEmailSubmit]);
|
|
280
|
+
const refreshMfaStatus = useCallback(async () => {
|
|
281
|
+
if (!getMfaStatus)
|
|
282
|
+
return;
|
|
283
|
+
setMfaLoading(true);
|
|
284
|
+
setMfaError(null);
|
|
285
|
+
try {
|
|
286
|
+
const status = await getMfaStatus();
|
|
287
|
+
setMfaStatus(status);
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
const msg = err instanceof Error ? err.message : "Failed to load MFA status";
|
|
291
|
+
setMfaError(msg);
|
|
292
|
+
}
|
|
293
|
+
finally {
|
|
294
|
+
setMfaLoading(false);
|
|
295
|
+
}
|
|
296
|
+
}, [getMfaStatus]);
|
|
297
|
+
const resetMfaSetupState = useCallback(() => {
|
|
298
|
+
setMfaSetupStep("setup");
|
|
299
|
+
setMfaQrCode(null);
|
|
300
|
+
setMfaSecret(null);
|
|
301
|
+
setMfaSetupCode("");
|
|
302
|
+
setMfaRecoveryCode("");
|
|
303
|
+
setMfaSetupError(null);
|
|
304
|
+
setMfaSetupLoading(false);
|
|
305
|
+
setMfaBackupCodes([]);
|
|
31
306
|
}, []);
|
|
307
|
+
const resetMfaDisableState = useCallback(() => {
|
|
308
|
+
setShowMfaDisableAuthModal(false);
|
|
309
|
+
setShowMfaDisableConfirmModal(false);
|
|
310
|
+
setMfaDisableStep("otp");
|
|
311
|
+
setMfaDisableCode("");
|
|
312
|
+
setMfaDisableRecoveryCode("");
|
|
313
|
+
setMfaDisableError(null);
|
|
314
|
+
setMfaDisableLoading(false);
|
|
315
|
+
}, []);
|
|
316
|
+
const handleMfaDisableVerifyCode = useCallback(async () => {
|
|
317
|
+
if (!verifyMfa || mfaDisableCode.trim().length !== 6)
|
|
318
|
+
return;
|
|
319
|
+
setMfaDisableLoading(true);
|
|
320
|
+
setMfaDisableError(null);
|
|
321
|
+
try {
|
|
322
|
+
await verifyMfa(mfaDisableCode.trim());
|
|
323
|
+
setShowMfaDisableAuthModal(false);
|
|
324
|
+
setShowMfaDisableConfirmModal(true);
|
|
325
|
+
setMfaDisableCode("");
|
|
326
|
+
}
|
|
327
|
+
catch (err) {
|
|
328
|
+
setMfaDisableError(err instanceof Error ? err.message : "Invalid authentication code");
|
|
329
|
+
}
|
|
330
|
+
finally {
|
|
331
|
+
setMfaDisableLoading(false);
|
|
332
|
+
}
|
|
333
|
+
}, [verifyMfa, mfaDisableCode]);
|
|
334
|
+
const handleMfaDisableVerifyRecoveryCode = useCallback(async () => {
|
|
335
|
+
if (!verifyMfa)
|
|
336
|
+
return;
|
|
337
|
+
const trimmed = mfaDisableRecoveryCode.trim().toUpperCase();
|
|
338
|
+
if (!/^[A-Z0-9]{8}$/.test(trimmed)) {
|
|
339
|
+
setMfaDisableError("Please enter a valid 8-character backup code");
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
setMfaDisableLoading(true);
|
|
343
|
+
setMfaDisableError(null);
|
|
344
|
+
try {
|
|
345
|
+
await verifyMfa(trimmed);
|
|
346
|
+
setShowMfaDisableAuthModal(false);
|
|
347
|
+
setShowMfaDisableConfirmModal(true);
|
|
348
|
+
setMfaDisableRecoveryCode("");
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
setMfaDisableError(err instanceof Error ? err.message : "Invalid backup code");
|
|
352
|
+
}
|
|
353
|
+
finally {
|
|
354
|
+
setMfaDisableLoading(false);
|
|
355
|
+
}
|
|
356
|
+
}, [verifyMfa, mfaDisableRecoveryCode]);
|
|
357
|
+
const openMfaDisableFlow = useCallback(() => {
|
|
358
|
+
if (!verifyMfa || !disableMfaWithSignedPayload) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
setShowMfaStatusModal(false);
|
|
362
|
+
setMfaDisableCode("");
|
|
363
|
+
setMfaDisableRecoveryCode("");
|
|
364
|
+
setMfaDisableStep("otp");
|
|
365
|
+
setMfaDisableError(null);
|
|
366
|
+
setShowMfaDisableAuthModal(true);
|
|
367
|
+
}, [verifyMfa, disableMfaWithSignedPayload]);
|
|
368
|
+
const handleMfaDisableConfirm = useCallback(async () => {
|
|
369
|
+
if (!disableMfaWithSignedPayload)
|
|
370
|
+
return;
|
|
371
|
+
setMfaDisableLoading(true);
|
|
372
|
+
setMfaDisableError(null);
|
|
373
|
+
try {
|
|
374
|
+
await disableMfaWithSignedPayload();
|
|
375
|
+
await refreshMfaStatus();
|
|
376
|
+
resetMfaDisableState();
|
|
377
|
+
showFeedback("2FA disabled successfully", "success");
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
const msg = err instanceof Error ? err.message : "Failed to disable 2FA";
|
|
381
|
+
setMfaDisableError(msg);
|
|
382
|
+
}
|
|
383
|
+
finally {
|
|
384
|
+
setMfaDisableLoading(false);
|
|
385
|
+
}
|
|
386
|
+
}, [disableMfaWithSignedPayload, refreshMfaStatus, resetMfaDisableState, showFeedback]);
|
|
387
|
+
const startMfaSetup = useCallback(async () => {
|
|
388
|
+
if (!enableMfa)
|
|
389
|
+
return;
|
|
390
|
+
resetMfaSetupState();
|
|
391
|
+
setShowMfaSetupModal(true);
|
|
392
|
+
setMfaSetupLoading(true);
|
|
393
|
+
try {
|
|
394
|
+
const result = await enableMfa();
|
|
395
|
+
setMfaQrCode(result.qrCode);
|
|
396
|
+
setMfaSecret(result.secret);
|
|
397
|
+
}
|
|
398
|
+
catch (err) {
|
|
399
|
+
const msg = err instanceof Error ? err.message : "Failed to enable MFA";
|
|
400
|
+
setMfaSetupError(msg);
|
|
401
|
+
setShowMfaSetupModal(false);
|
|
402
|
+
}
|
|
403
|
+
finally {
|
|
404
|
+
setMfaSetupLoading(false);
|
|
405
|
+
}
|
|
406
|
+
}, [enableMfa, resetMfaSetupState]);
|
|
407
|
+
const handleVerifyMfaSetup = useCallback(async () => {
|
|
408
|
+
if (!verifySetupMfa)
|
|
409
|
+
return;
|
|
410
|
+
const trimmed = mfaSetupCode.trim();
|
|
411
|
+
if (trimmed.length !== 6) {
|
|
412
|
+
setMfaSetupError("Please enter a 6-digit code");
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
setMfaSetupLoading(true);
|
|
416
|
+
setMfaSetupError(null);
|
|
417
|
+
try {
|
|
418
|
+
const result = await verifySetupMfa(trimmed);
|
|
419
|
+
setMfaBackupCodes(result.backupCodes || []);
|
|
420
|
+
setShowMfaSetupModal(false);
|
|
421
|
+
setShowMfaBackupModal(true);
|
|
422
|
+
await refreshMfaStatus();
|
|
423
|
+
showFeedback("MFA enabled successfully.", "success");
|
|
424
|
+
}
|
|
425
|
+
catch (err) {
|
|
426
|
+
const msg = err instanceof Error ? err.message : "Invalid TOTP code";
|
|
427
|
+
setMfaSetupError(msg);
|
|
428
|
+
}
|
|
429
|
+
finally {
|
|
430
|
+
setMfaSetupLoading(false);
|
|
431
|
+
}
|
|
432
|
+
}, [verifySetupMfa, mfaSetupCode, refreshMfaStatus, showFeedback]);
|
|
433
|
+
const handleVerifyRecoveryCode = useCallback(async () => {
|
|
434
|
+
if (!verifyMfa)
|
|
435
|
+
return;
|
|
436
|
+
const trimmed = mfaRecoveryCode.trim().toUpperCase();
|
|
437
|
+
if (!/^[A-Z0-9]{8}$/.test(trimmed)) {
|
|
438
|
+
setMfaSetupError("Please enter a valid 8-character recovery code");
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
setMfaSetupLoading(true);
|
|
442
|
+
setMfaSetupError(null);
|
|
443
|
+
try {
|
|
444
|
+
await verifyMfa(trimmed);
|
|
445
|
+
setMfaSetupStep("verify");
|
|
446
|
+
setMfaRecoveryCode("");
|
|
447
|
+
}
|
|
448
|
+
catch (err) {
|
|
449
|
+
const msg = err instanceof Error ? err.message : "Invalid recovery code";
|
|
450
|
+
setMfaSetupError(msg);
|
|
451
|
+
}
|
|
452
|
+
finally {
|
|
453
|
+
setMfaSetupLoading(false);
|
|
454
|
+
}
|
|
455
|
+
}, [verifyMfa, mfaRecoveryCode]);
|
|
456
|
+
const handleCopyMfaSecret = useCallback(() => {
|
|
457
|
+
if (!mfaSecret)
|
|
458
|
+
return;
|
|
459
|
+
try {
|
|
460
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
461
|
+
navigator.clipboard.writeText(mfaSecret);
|
|
462
|
+
setMfaSecretCopied(true);
|
|
463
|
+
setTimeout(() => setMfaSecretCopied(false), 2000);
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
throw new Error("Clipboard not available");
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
catch {
|
|
470
|
+
window.alert("Copy failed. Please copy the secret manually.");
|
|
471
|
+
}
|
|
472
|
+
}, [mfaSecret]);
|
|
473
|
+
const handleCopyBackupCodes = useCallback(() => {
|
|
474
|
+
if (!mfaBackupCodes.length)
|
|
475
|
+
return;
|
|
476
|
+
const text = mfaBackupCodes.join("\n");
|
|
477
|
+
try {
|
|
478
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
479
|
+
navigator.clipboard.writeText(text);
|
|
480
|
+
setMfaBackupCodesCopied(true);
|
|
481
|
+
setTimeout(() => setMfaBackupCodesCopied(false), 2000);
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
throw new Error("Clipboard not available");
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
window.alert("Copy failed. Please copy the codes manually.");
|
|
489
|
+
}
|
|
490
|
+
}, [mfaBackupCodes]);
|
|
491
|
+
const handleDownloadBackupCodes = useCallback(() => {
|
|
492
|
+
if (!mfaBackupCodes.length)
|
|
493
|
+
return;
|
|
494
|
+
const header = "Abstraxn MFA Backup Codes\n\n“You have 10 backup codes. Each can be used once.”\n\n";
|
|
495
|
+
const body = mfaBackupCodes.join("\n");
|
|
496
|
+
const blob = new Blob([header + body], { type: "text/plain" });
|
|
497
|
+
const url = URL.createObjectURL(blob);
|
|
498
|
+
const a = document.createElement("a");
|
|
499
|
+
a.href = url;
|
|
500
|
+
a.download = "abstraxn-mfa-backup-codes.txt";
|
|
501
|
+
document.body.appendChild(a);
|
|
502
|
+
a.click();
|
|
503
|
+
document.body.removeChild(a);
|
|
504
|
+
URL.revokeObjectURL(url);
|
|
505
|
+
}, [mfaBackupCodes]);
|
|
506
|
+
const handleDisconnect = useCallback(async (provider) => {
|
|
507
|
+
if (!unlinkAuthMethod)
|
|
508
|
+
return;
|
|
509
|
+
setActionProvider(provider);
|
|
510
|
+
try {
|
|
511
|
+
await unlinkAuthMethod(provider);
|
|
512
|
+
setUnlinkConfirm(null);
|
|
513
|
+
const lower = provider.toLowerCase();
|
|
514
|
+
const message = lower === "passkey"
|
|
515
|
+
? "Passkey removed successfully!"
|
|
516
|
+
: "Provider unlinked successfully!";
|
|
517
|
+
setLinkUnlinkSuccess(message);
|
|
518
|
+
await fetchLinkedProfilesData();
|
|
519
|
+
}
|
|
520
|
+
catch (err) {
|
|
521
|
+
showFeedback(err instanceof Error ? err.message : "Failed to disconnect", "error");
|
|
522
|
+
}
|
|
523
|
+
finally {
|
|
524
|
+
setActionProvider(null);
|
|
525
|
+
}
|
|
526
|
+
}, [unlinkAuthMethod, fetchLinkedProfilesData, showFeedback]);
|
|
527
|
+
useEffect(() => {
|
|
528
|
+
if (emailLinkStep !== "otp" || emailLinkResendCooldown <= 0)
|
|
529
|
+
return;
|
|
530
|
+
const id = setInterval(() => {
|
|
531
|
+
setEmailLinkResendCooldown((c) => {
|
|
532
|
+
if (c <= 1) {
|
|
533
|
+
clearInterval(id);
|
|
534
|
+
return 0;
|
|
535
|
+
}
|
|
536
|
+
return c - 1;
|
|
537
|
+
});
|
|
538
|
+
}, 1000);
|
|
539
|
+
return () => clearInterval(id);
|
|
540
|
+
}, [emailLinkStep, emailLinkResendCooldown]);
|
|
541
|
+
useEffect(() => {
|
|
542
|
+
if (!isOpen || isExternalWalletConnected)
|
|
543
|
+
return;
|
|
544
|
+
refreshMfaStatus();
|
|
545
|
+
}, [isOpen, isExternalWalletConnected, refreshMfaStatus]);
|
|
546
|
+
useEffect(() => {
|
|
547
|
+
if (isOpen)
|
|
548
|
+
return;
|
|
549
|
+
setShowMfaStatusModal(false);
|
|
550
|
+
}, [isOpen]);
|
|
32
551
|
if (!isOpen)
|
|
33
552
|
return null;
|
|
34
|
-
|
|
553
|
+
if (showMfaSetupModal) {
|
|
554
|
+
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => {
|
|
555
|
+
setShowMfaSetupModal(false);
|
|
556
|
+
resetMfaSetupState();
|
|
557
|
+
}, 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: () => {
|
|
558
|
+
if (mfaSetupStep === "verify" || mfaSetupStep === "recovery") {
|
|
559
|
+
setMfaSetupStep("setup");
|
|
560
|
+
setMfaSetupCode("");
|
|
561
|
+
setMfaRecoveryCode("");
|
|
562
|
+
setMfaSetupError(null);
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
setShowMfaSetupModal(false);
|
|
566
|
+
resetMfaSetupState();
|
|
567
|
+
}, "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(IoClose, { 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: (() => {
|
|
568
|
+
const issuer = organizationName ?? "Abstraxn";
|
|
569
|
+
const label = userEmail ? `${issuer}:${userEmail}` : issuer;
|
|
570
|
+
return `otpauth://totp/${encodeURIComponent(label)}?secret=${mfaSecret}&issuer=${encodeURIComponent(issuer)}`;
|
|
571
|
+
})(), size: 160, level: "L", includeMargin: false }) })) : (_jsx("div", { className: "mfa-qr-placeholder", children: mfaSetupLoading ? "Generating QR..." : "QR Code" })), mfaSecret && (_jsxs("div", { className: "mfa-secret-display", children: [_jsx(IoKeyOutline, { size: 16, className: "mfa-secret-key-icon" }), _jsx("code", { className: "mfa-secret-code", children: mfaSecret }), _jsx("button", { type: "button", className: `mfa-secret-copy ${mfaSecretCopied ? "copied" : ""}`, onClick: handleCopyMfaSecret, children: mfaSecretCopied ? _jsx(IoCheckmarkOutline, { size: 18 }) : _jsx(IoCopyOutline, { size: 18 }) })] }))] }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: () => {
|
|
572
|
+
setMfaSetupStep("verify");
|
|
573
|
+
setMfaSetupCode("");
|
|
574
|
+
setMfaRecoveryCode("");
|
|
575
|
+
setMfaSetupError(null);
|
|
576
|
+
}, 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("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: mfaSetupCode[index] || "", onChange: (e) => {
|
|
577
|
+
const val = e.target.value.replace(/\D/g, "");
|
|
578
|
+
if (val) {
|
|
579
|
+
const newCode = mfaSetupCode.split("");
|
|
580
|
+
newCode[index] = val;
|
|
581
|
+
const combined = newCode.join("").slice(0, 6);
|
|
582
|
+
setMfaSetupCode(combined);
|
|
583
|
+
if (combined.length === 6) {
|
|
584
|
+
window.setTimeout(() => {
|
|
585
|
+
mfaSetupVerifyButtonRef.current?.focus();
|
|
586
|
+
}, 0);
|
|
587
|
+
}
|
|
588
|
+
if (index < 5) {
|
|
589
|
+
const target = e.target;
|
|
590
|
+
const next = target.parentElement?.nextElementSibling?.querySelector("input");
|
|
591
|
+
next?.focus();
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}, onKeyDown: (e) => {
|
|
595
|
+
if (e.key === "Backspace") {
|
|
596
|
+
const target = e.target;
|
|
597
|
+
if (!mfaSetupCode[index] && index > 0) {
|
|
598
|
+
const prev = target.parentElement?.previousElementSibling?.querySelector("input");
|
|
599
|
+
prev?.focus();
|
|
600
|
+
const newCode = mfaSetupCode.split("");
|
|
601
|
+
newCode[index - 1] = "";
|
|
602
|
+
setMfaSetupCode(newCode.join(""));
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
const newCode = mfaSetupCode.split("");
|
|
606
|
+
newCode[index] = "";
|
|
607
|
+
setMfaSetupCode(newCode.join(""));
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}, 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: () => {
|
|
611
|
+
setMfaSetupStep("recovery");
|
|
612
|
+
setMfaSetupError(null);
|
|
613
|
+
setMfaRecoveryCode("");
|
|
614
|
+
}, 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) => {
|
|
615
|
+
const val = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 8);
|
|
616
|
+
setMfaRecoveryCode(val);
|
|
617
|
+
}, className: "mfa-recovery-field" }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: handleVerifyRecoveryCode, disabled: mfaSetupLoading || mfaRecoveryCode.trim().length !== 8, children: mfaSetupLoading ? "Verifying..." : "Verify" })] })) })] }) }));
|
|
618
|
+
}
|
|
619
|
+
if (showMfaBackupModal) {
|
|
620
|
+
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => {
|
|
621
|
+
setShowMfaBackupModal(false);
|
|
622
|
+
setMfaBackupCodes([]);
|
|
623
|
+
}, 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: () => {
|
|
624
|
+
setShowMfaBackupModal(false);
|
|
625
|
+
setMfaBackupCodes([]);
|
|
626
|
+
}, "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(IoClose, { 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: () => {
|
|
627
|
+
setShowMfaBackupModal(false);
|
|
628
|
+
setMfaBackupCodes([]);
|
|
629
|
+
}, children: "I've saved these codes" })] })] }) }));
|
|
630
|
+
}
|
|
631
|
+
if (showMfaDisableAuthModal) {
|
|
632
|
+
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: resetMfaDisableState, 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: () => {
|
|
633
|
+
if (mfaDisableStep === "recovery") {
|
|
634
|
+
setMfaDisableStep("otp");
|
|
635
|
+
setMfaDisableRecoveryCode("");
|
|
636
|
+
setMfaDisableError(null);
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
resetMfaDisableState();
|
|
640
|
+
}, "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) => {
|
|
641
|
+
const val = e.target.value.replace(/\D/g, "");
|
|
642
|
+
if (val) {
|
|
643
|
+
const newCode = mfaDisableCode.split("");
|
|
644
|
+
newCode[index] = val;
|
|
645
|
+
const combined = newCode.join("").slice(0, 6);
|
|
646
|
+
setMfaDisableCode(combined);
|
|
647
|
+
if (combined.length === 6) {
|
|
648
|
+
window.setTimeout(() => {
|
|
649
|
+
mfaDisableVerifyButtonRef.current?.focus();
|
|
650
|
+
}, 0);
|
|
651
|
+
}
|
|
652
|
+
if (index < 5) {
|
|
653
|
+
const target = e.target;
|
|
654
|
+
const next = target.parentElement?.nextElementSibling?.querySelector("input");
|
|
655
|
+
next?.focus();
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}, onKeyDown: (e) => {
|
|
659
|
+
if (e.key === "Backspace") {
|
|
660
|
+
const target = e.target;
|
|
661
|
+
if (!mfaDisableCode[index] && index > 0) {
|
|
662
|
+
const prev = target.parentElement?.previousElementSibling?.querySelector("input");
|
|
663
|
+
prev?.focus();
|
|
664
|
+
const newCode = mfaDisableCode.split("");
|
|
665
|
+
newCode[index - 1] = "";
|
|
666
|
+
setMfaDisableCode(newCode.join(""));
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
const newCode = mfaDisableCode.split("");
|
|
670
|
+
newCode[index] = "";
|
|
671
|
+
setMfaDisableCode(newCode.join(""));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}, 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: () => {
|
|
675
|
+
setMfaDisableStep("recovery");
|
|
676
|
+
setMfaDisableError(null);
|
|
677
|
+
setMfaDisableRecoveryCode("");
|
|
678
|
+
}, 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) => {
|
|
679
|
+
const val = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, "").slice(0, 8);
|
|
680
|
+
setMfaDisableRecoveryCode(val);
|
|
681
|
+
}, className: "mfa-recovery-field" }), _jsx("button", { type: "button", className: "mfa-verify-button", onClick: handleMfaDisableVerifyRecoveryCode, disabled: mfaDisableLoading || mfaDisableRecoveryCode.trim().length !== 8, children: mfaDisableLoading ? "Verifying..." : "Verify" })] }))] })] }) }));
|
|
682
|
+
}
|
|
683
|
+
if (showMfaStatusModal) {
|
|
684
|
+
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(IoClose, { 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" })] })] }) }));
|
|
685
|
+
}
|
|
686
|
+
if (showLinkedProfilesList) {
|
|
687
|
+
return (_jsx("div", { className: `wallet-modal-overlay wallet-modal-theme-${theme}`, onClick: () => setShowLinkedProfilesList(false), 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() : setShowLinkedProfilesList(false), "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(IoClose, { 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) => {
|
|
688
|
+
e.preventDefault();
|
|
689
|
+
if (!actionProvider && emailLinkEmail.trim()) {
|
|
690
|
+
handleSendOtpForLink();
|
|
691
|
+
}
|
|
692
|
+
}, children: [_jsx("div", { className: "wallet-modal-email-link-icon", children: _jsx(TfiEmail, { size: 22 }) }), _jsx("h3", { className: "wallet-modal-email-link-title", children: "Add an email" }), _jsx("p", { className: "wallet-modal-email-link-subtitle", children: "Add an email so you can sign in or recover access securely." }), _jsx("label", { className: "wallet-modal-email-link-label", htmlFor: "wallet-modal-link-email", children: "Email" }), _jsx("input", { id: "wallet-modal-link-email", type: "email", className: "wallet-modal-email-link-input", placeholder: "Enter email to link", value: emailLinkEmail, onChange: (e) => setEmailLinkEmail(e.target.value), disabled: actionProvider === "email", autoComplete: "email" }), emailLinkError && (_jsx("p", { className: "wallet-modal-email-link-error", children: emailLinkError })), _jsx("button", { type: "submit", className: "wallet-modal-email-link-button", disabled: actionProvider === "email" || !emailLinkEmail.trim(), children: actionProvider === "email" ? "Sending..." : "Send code" })] })) : (_jsxs("div", { className: "wallet-modal-email-link-otp", children: [_jsx("div", { className: "wallet-modal-email-link-icon", children: _jsx(TfiEmail, { size: 22 }) }), _jsx("h3", { className: "wallet-modal-email-link-title", children: "Enter verification code" }), _jsx("p", { className: "wallet-modal-email-link-subtitle", children: "We sent a 6-digit code to" }), _jsx("p", { className: "wallet-modal-email-link-email", children: emailLinkEmail }), emailLinkError && (_jsx("p", { className: "wallet-modal-email-link-error", children: emailLinkError })), _jsx("div", { className: "mfa-otp-grid", children: [0, 1, 2, 3, 4, 5].map((index) => (_jsx("div", { className: "mfa-otp-slot", children: _jsx("input", { ref: (el) => {
|
|
693
|
+
emailLinkOtpInputsRef.current[index] = el;
|
|
694
|
+
}, 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" ||
|
|
695
|
+
emailLinkResending ||
|
|
696
|
+
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 &&
|
|
697
|
+
supportedMethods.map((method) => {
|
|
698
|
+
const linked = isProviderLinked(method.provider);
|
|
699
|
+
const busy = actionProvider === method.provider;
|
|
700
|
+
return (_jsxs("div", { className: "wallet-modal-linked-profiles-row", children: [_jsx("div", { className: "wallet-modal-manage-list-icon", "aria-hidden": "true", children: _jsx(AuthMethodIcon, { provider: method.provider }) }), _jsx("span", { className: "wallet-modal-manage-list-label", children: method.displayName }), _jsx("div", { className: "wallet-modal-linked-profiles-action", children: linked ? (_jsx("button", { type: "button", className: "wallet-modal-linked-disconnect", onClick: () => {
|
|
701
|
+
const linkedMethod = linkedMethods.find((m) => normalizeLinkedProvider(m.authProvider) ===
|
|
702
|
+
method.provider.toLowerCase());
|
|
703
|
+
setUnlinkConfirm({
|
|
704
|
+
provider: method.provider,
|
|
705
|
+
displayName: method.displayName,
|
|
706
|
+
id: linkedMethod?.id ?? null,
|
|
707
|
+
});
|
|
708
|
+
}, disabled: busy, "aria-label": `Unlink ${method.displayName}`, children: _jsx(FiLink, { size: 18, "aria-hidden": "true" }) })) : (_jsx("button", { type: "button", className: "wallet-modal-linked-connect", onClick: () => handleConnect(method.provider), disabled: busy, "aria-label": `Connect ${method.displayName}`, children: "+ Connect" })) })] }, method.provider));
|
|
709
|
+
})] })) }), unlinkConfirm &&
|
|
710
|
+
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"
|
|
711
|
+
? "Remove Passkey"
|
|
712
|
+
: "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"
|
|
713
|
+
? `Passkey Name: ${unlinkConfirm.displayName}`
|
|
714
|
+
: `Provider Name: ${unlinkConfirm.displayName}` }), unlinkConfirm.id && (_jsx("p", { className: "wallet-modal-unlink-confirm-details-line", children: unlinkConfirm.provider.toLowerCase() === "passkey"
|
|
715
|
+
? `Passkey ID: ${unlinkConfirm.id}`
|
|
716
|
+
: `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"
|
|
717
|
+
? "Remove Passkey"
|
|
718
|
+
: "Remove Provider" }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }) }), document.body)] }) }));
|
|
719
|
+
}
|
|
720
|
+
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(IoClose, { 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: () => {
|
|
721
|
+
if (mfaLoading)
|
|
722
|
+
return;
|
|
723
|
+
if (!getMfaStatus || !enableMfa || !verifySetupMfa) {
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
if (mfaStatus?.enabled) {
|
|
727
|
+
setShowMfaStatusModal(true);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
startMfaSetup();
|
|
731
|
+
}, 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 &&
|
|
732
|
+
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(IoClose, { size: 24 }) })] }) }), document.body), unlinkConfirm &&
|
|
733
|
+
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"
|
|
734
|
+
? "Remove Passkey"
|
|
735
|
+
: "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"
|
|
736
|
+
? `Passkey Name: ${unlinkConfirm.displayName}`
|
|
737
|
+
: `Provider Name: ${unlinkConfirm.displayName}` }), unlinkConfirm.id && (_jsx("p", { className: "wallet-modal-unlink-confirm-details-line", children: unlinkConfirm.provider.toLowerCase() === "passkey"
|
|
738
|
+
? `Passkey ID: ${unlinkConfirm.id}`
|
|
739
|
+
: `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"
|
|
740
|
+
? "Remove Passkey"
|
|
741
|
+
: "Remove Provider" }), _jsx("div", { className: "wallet-modal-unlink-confirm-footer", children: _jsxs("span", { className: "onboarding-footer-text", children: ["Powered by", " ", _jsxs("a", { href: "https://abstraxn.com", target: "_blank", rel: "noopener noreferrer", className: "onboarding-footer-brand", style: {
|
|
742
|
+
display: "inline-flex",
|
|
743
|
+
alignItems: "center",
|
|
744
|
+
gap: "6px",
|
|
745
|
+
verticalAlign: "middle",
|
|
746
|
+
}, children: [_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "18", viewBox: "0 0 48 48", fill: "none", style: { display: "inline-block", verticalAlign: "middle" }, children: [_jsx("path", { d: "M47.9082 37.191L23.9541 23.553L0 9.91504L37.7436 -8.13502e-06L47.9082 37.191Z", fill: "url(#paint0_linear_unlink_footer)" }), _jsx("path", { d: "M13.5156 46.3594L10.1846 47.2344L8.99219 42.873L12.4365 42.4111L13.5156 46.3594ZM20.4268 44.5566L17.1152 45.4199L16.125 41.8818L19.5566 41.3721L20.4268 44.5566ZM26.9307 42.834L23.6152 43.6982L22.8438 40.9443L26.2744 40.4326L26.9307 42.834ZM33.5078 41.1074L30.1875 41.9727L29.6328 39.9951L33.0635 39.4844L33.5078 41.1074ZM39.998 39.4014L36.6729 40.2686L36.3359 39.0674L39.7656 38.5508L39.998 39.4014ZM10.1406 33.9434L11.6807 39.5762L8.15918 39.7568L6.46094 33.543L10.1406 33.9434ZM17.6582 34.5996L18.8916 39.1113L15.4199 39.3496L14.0078 34.3076L17.6582 34.5996ZM24.8779 35.332L25.8047 38.7227L22.3252 38.959L21.2266 35.0361L24.8779 35.332ZM32.0918 36.0723L32.7119 38.3398L29.2227 38.5723L28.4375 35.7656L32.0918 36.0723ZM43.2373 38.5488L43.1172 38.1172L47.7939 37.3516L43.2373 38.5488ZM39.3047 36.8096L39.6182 37.9561L36.1221 38.1846L35.6484 36.4961L39.3047 36.8096ZM47.7939 37.3516L43.0107 37.7939L42.8516 37.2236L47.7939 37.3516ZM47.8291 37.2988L42.7227 36.7529L42.5547 36.1523L47.8291 37.2988ZM47.8652 37.2412L42.3711 35.3486L42.2031 34.7471L47.8652 37.2412ZM38.748 34.8604L39.0664 36.0254L35.3369 35.4043L34.8594 33.6982L38.748 34.8604ZM31.0576 32.3994L31.6787 34.6709L27.959 34.0566L27.1719 31.2461L31.0576 32.3994ZM38.0811 32.6318L38.4092 33.8301L34.4893 32.3496L34.1543 31.1523C34.1005 30.9591 34.0322 30.7719 33.9531 30.5918L38.0811 32.6318ZM23.3682 29.9385L24.291 33.3164L20.5801 32.71L19.4844 28.7949L23.3682 29.9385ZM15.6641 27.4805L16.8896 31.9629L13.1875 31.3594L11.7812 26.3379L15.6641 27.4805ZM29.9463 28.4678L30.5693 30.748L26.6201 29.2812L25.8633 26.583C25.8534 26.5431 25.8417 26.5028 25.8281 26.4639L29.9463 28.4678ZM7.6875 25.0938L9.21484 30.6816L5.44727 29.959L3.75781 23.7793L7.6875 25.0938ZM21.5312 23.3623L22.4492 26.7227L18.5059 25.2627L17.4141 21.3643L21.5312 23.3623ZM13.6104 20.1602L14.8242 24.6006L10.8887 23.1387L9.49219 18.1553L13.6104 20.1602ZM5.2168 16.0654L6.72559 21.585L2.70703 19.9473L1.06055 13.8701L5.2168 16.0654Z", fill: "url(#paint1_linear_unlink_footer)" }), _jsxs("defs", { children: [_jsxs("linearGradient", { id: "paint0_linear_unlink_footer", x1: "7.03362", y1: "6.09543", x2: "47.2003", y2: "57.0656", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] }), _jsxs("linearGradient", { id: "paint1_linear_unlink_footer", x1: "2.53739", y1: "21.5136", x2: "48.7969", y2: "38.5742", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "#F878D2" }), _jsx("stop", { offset: "0.393522", stopColor: "#FDCC81" }), _jsx("stop", { offset: "1", stopColor: "#F9A0D9" })] })] })] }), _jsx("span", { style: {
|
|
747
|
+
color: theme === "dark" ? "#ffffff" : "#111827",
|
|
748
|
+
}, children: "abstraxn" })] })] }) }), _jsx("button", { type: "button", className: "wallet-modal-unlink-confirm-close", onClick: () => setUnlinkConfirm(null), "aria-label": "Close", children: _jsx(IoClose, { size: 24 }) })] }) }), document.body)] }) }));
|
|
35
749
|
}
|
|
36
750
|
//# sourceMappingURL=ManageWalletModal.js.map
|