@dynamic-labs/sdk-react-core 3.0.0-alpha.46 → 3.0.0-alpha.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/package.cjs +2 -2
  3. package/package.js +2 -2
  4. package/package.json +13 -13
  5. package/src/index.cjs +2 -2
  6. package/src/index.d.ts +1 -1
  7. package/src/index.js +1 -1
  8. package/src/lib/components/OTPVerificationView/OTPVerificationView.cjs +2 -2
  9. package/src/lib/components/OTPVerificationView/OTPVerificationView.d.ts +1 -0
  10. package/src/lib/components/OTPVerificationView/OTPVerificationView.js +2 -2
  11. package/src/lib/components/PinField/PinField.cjs +2 -2
  12. package/src/lib/components/PinField/PinField.d.ts +1 -1
  13. package/src/lib/components/PinField/PinField.js +2 -2
  14. package/src/lib/components/SendBalanceForm/SendBalanceForm.cjs +1 -1
  15. package/src/lib/components/SendBalanceForm/SendBalanceForm.js +1 -1
  16. package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.cjs +3 -3
  17. package/src/lib/components/SendBalancePageLayout/SendBalancePageLayout.js +3 -3
  18. package/src/lib/components/TransactionConfirmationPageLayout/TransactionConfirmationPageLayout.cjs +3 -3
  19. package/src/lib/components/TransactionConfirmationPageLayout/TransactionConfirmationPageLayout.js +3 -3
  20. package/src/lib/components/TransactionStatusLayout/TransactionStatusLayout.cjs +1 -1
  21. package/src/lib/components/TransactionStatusLayout/TransactionStatusLayout.js +1 -1
  22. package/src/lib/components/UserProfile/parts/UserProfileSocialAccount/UserProfileSocialAccount.cjs +1 -1
  23. package/src/lib/components/UserProfile/parts/UserProfileSocialAccount/UserProfileSocialAccount.js +1 -1
  24. package/src/lib/context/DynamicContext/useDynamicContext/useDynamicContext.cjs +1 -2
  25. package/src/lib/context/DynamicContext/useDynamicContext/useDynamicContext.d.ts +1 -1
  26. package/src/lib/context/DynamicContext/useDynamicContext/useDynamicContext.js +1 -2
  27. package/src/lib/data/api/mfa/mfa.cjs +5 -1
  28. package/src/lib/data/api/mfa/mfa.d.ts +2 -1
  29. package/src/lib/data/api/mfa/mfa.js +6 -2
  30. package/src/lib/locale/en/translation.cjs +3 -1
  31. package/src/lib/locale/en/translation.d.ts +2 -0
  32. package/src/lib/locale/en/translation.js +3 -1
  33. package/src/lib/styles/index.shadow.cjs +1 -1
  34. package/src/lib/styles/index.shadow.js +1 -1
  35. package/src/lib/utils/hooks/index.d.ts +1 -1
  36. package/src/lib/utils/hooks/useMfa/useMfa.cjs +2 -1
  37. package/src/lib/utils/hooks/useMfa/useMfa.d.ts +1 -1
  38. package/src/lib/utils/hooks/useMfa/useMfa.js +2 -1
  39. package/src/lib/utils/hooks/useOnlyConnectedMode/useOnlyConnectedMode.d.ts +0 -1
  40. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.cjs +7 -13
  41. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.js +7 -13
  42. package/src/lib/utils/hooks/useUserAuth/useUserAuth.cjs +2 -1
  43. package/src/lib/utils/hooks/useUserAuth/useUserAuth.js +3 -2
  44. package/src/lib/utils/hooks/useWalletOptions/index.d.ts +1 -0
  45. package/src/lib/utils/hooks/{useSelectWalletOption/useSelectWalletOption.cjs → useWalletOptions/useWalletOptions.cjs} +31 -4
  46. package/src/lib/utils/hooks/useWalletOptions/useWalletOptions.d.ts +9 -0
  47. package/src/lib/utils/hooks/{useSelectWalletOption/useSelectWalletOption.js → useWalletOptions/useWalletOptions.js} +32 -5
  48. package/src/lib/views/MfaVerificationView/MfaVerificationView.cjs +10 -3
  49. package/src/lib/views/MfaVerificationView/MfaVerificationView.js +11 -4
  50. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/ManageMfaWidgetView.cjs +20 -6
  51. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/ManageMfaWidgetView.js +21 -7
  52. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/UserDeviceTile.cjs +3 -4
  53. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/UserDeviceTile.d.ts +2 -1
  54. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/UserDeviceTile.js +3 -4
  55. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/utils/sort.cjs +2 -8
  56. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/utils/sort.d.ts +1 -1
  57. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/utils/sort.js +2 -8
  58. package/src/lib/utils/hooks/useSelectWalletOption/index.d.ts +0 -1
  59. package/src/lib/utils/hooks/useSelectWalletOption/useSelectWalletOption.d.ts +0 -3
@@ -60,6 +60,6 @@ export { useSyncEmbeddedWalletFlow } from './useSyncEmbeddedWalletFlow';
60
60
  export { useSyncOnboardingFlow } from './useSyncOnboardingFlow';
61
61
  export { useExternalAuth } from './useExternalAuth';
62
62
  export { useRefreshUser } from './useRefreshUser';
63
- export { useSelectWalletOption } from './useSelectWalletOption';
63
+ export { useWalletOptions } from './useWalletOptions';
64
64
  export { useResetCookieLocalStorage } from './useResetCookieLocalStorage';
65
65
  export { useSyncMfaFlow } from './useSyncMfaFlow';
@@ -112,12 +112,13 @@ const useMfa = () => {
112
112
  mfaDeviceId: deviceId,
113
113
  });
114
114
  });
115
- const deleteUserDevice = (deviceId) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
115
+ const deleteUserDevice = (deviceId, mfaAuthToken) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
116
116
  if (!verifiedUser) {
117
117
  throw new Error(errors.USER_NOT_LOGGED_IN);
118
118
  }
119
119
  yield mfa.deleteMfaDevice({
120
120
  environmentId,
121
+ mfaAuthToken,
121
122
  mfaDeviceId: deviceId,
122
123
  });
123
124
  });
@@ -7,7 +7,7 @@ export declare const useMfa: () => {
7
7
  }>;
8
8
  readonly authDevice: (code: string, type?: MFADeviceType, deviceId?: string) => Promise<boolean>;
9
9
  readonly authRecoveryCode: (code: string) => Promise<boolean>;
10
- readonly deleteUserDevice: (deviceId: string) => Promise<void>;
10
+ readonly deleteUserDevice: (deviceId: string, mfaAuthToken: string) => Promise<void>;
11
11
  readonly getRecoveryCodes: (generateNewCodes?: boolean) => Promise<string[]>;
12
12
  readonly getUserDevices: () => Promise<MFADevice[]>;
13
13
  readonly updateUserDevice: (deviceId: string) => Promise<void>;
@@ -108,12 +108,13 @@ const useMfa = () => {
108
108
  mfaDeviceId: deviceId,
109
109
  });
110
110
  });
111
- const deleteUserDevice = (deviceId) => __awaiter(void 0, void 0, void 0, function* () {
111
+ const deleteUserDevice = (deviceId, mfaAuthToken) => __awaiter(void 0, void 0, void 0, function* () {
112
112
  if (!verifiedUser) {
113
113
  throw new Error(USER_NOT_LOGGED_IN);
114
114
  }
115
115
  yield deleteMfaDevice({
116
116
  environmentId,
117
+ mfaAuthToken,
117
118
  mfaDeviceId: deviceId,
118
119
  });
119
120
  });
@@ -1 +0,0 @@
1
- export declare const useOnlyConnectedMode: () => boolean;
@@ -228,29 +228,23 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
228
228
  oauthLoginUrl.searchParams.set('code_challenge_method', 'S256');
229
229
  }
230
230
  const isMobile = utils.isMobile();
231
- const effectiveRedirectUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : defaultRedirectUrl;
232
231
  try {
233
232
  const authCode = yield utils.Oauth2Service.getOauthCode({
234
233
  apiProvider: getProviderByType.getProviderByType((_c = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _c !== void 0 ? _c : [], provider),
235
234
  getOAuthResultFromApi: () => oauth.getOAuthResult(environmentId, provider, {
236
235
  state,
237
236
  }),
238
- initWebAuth: () => {
239
- // When we set the redirectUrl, the backend gives preference to a redirect
240
- // experience, which is only desired for mobile
241
- const mobileRedirectUrl = effectiveRedirectUrl || window.location.href;
242
- return oauth.initAuth(environmentId, provider, {
243
- redirectUrl: isMobile
244
- ? removeDynamicOauthParamsFromUrl(mobileRedirectUrl)
245
- : undefined,
246
- state,
247
- });
248
- },
237
+ initWebAuth: ({ redirectUrl } = {}) => oauth.initAuth(environmentId, provider, {
238
+ redirectUrl: redirectUrl
239
+ ? removeDynamicOauthParamsFromUrl(redirectUrl)
240
+ : undefined,
241
+ state,
242
+ }),
249
243
  isMobile,
250
244
  oauthLoginUrl,
251
245
  onSettled,
252
246
  provider,
253
- redirectUrl: effectiveRedirectUrl,
247
+ redirectUrl: redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : defaultRedirectUrl,
254
248
  sessionTimeout,
255
249
  setIsProcessing,
256
250
  state,
@@ -224,29 +224,23 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
224
224
  oauthLoginUrl.searchParams.set('code_challenge_method', 'S256');
225
225
  }
226
226
  const isMobile$1 = isMobile();
227
- const effectiveRedirectUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : defaultRedirectUrl;
228
227
  try {
229
228
  const authCode = yield Oauth2Service.getOauthCode({
230
229
  apiProvider: getProviderByType((_c = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _c !== void 0 ? _c : [], provider),
231
230
  getOAuthResultFromApi: () => getOAuthResult(environmentId, provider, {
232
231
  state,
233
232
  }),
234
- initWebAuth: () => {
235
- // When we set the redirectUrl, the backend gives preference to a redirect
236
- // experience, which is only desired for mobile
237
- const mobileRedirectUrl = effectiveRedirectUrl || window.location.href;
238
- return initAuth(environmentId, provider, {
239
- redirectUrl: isMobile$1
240
- ? removeDynamicOauthParamsFromUrl(mobileRedirectUrl)
241
- : undefined,
242
- state,
243
- });
244
- },
233
+ initWebAuth: ({ redirectUrl } = {}) => initAuth(environmentId, provider, {
234
+ redirectUrl: redirectUrl
235
+ ? removeDynamicOauthParamsFromUrl(redirectUrl)
236
+ : undefined,
237
+ state,
238
+ }),
245
239
  isMobile: isMobile$1,
246
240
  oauthLoginUrl,
247
241
  onSettled,
248
242
  provider,
249
- redirectUrl: effectiveRedirectUrl,
243
+ redirectUrl: redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : defaultRedirectUrl,
250
244
  sessionTimeout,
251
245
  setIsProcessing,
252
246
  state,
@@ -166,7 +166,8 @@ const useUserAuth = ({ authMethod, }) => {
166
166
  });
167
167
  const handleAuthError = (error, { options = {}, onError, }) => {
168
168
  var _a;
169
- if (error instanceof utils.MfaInvalidOtpError) {
169
+ if (error instanceof utils.MfaInvalidOtpError ||
170
+ error instanceof utils.MfaRateLimitedError) {
170
171
  throw error;
171
172
  }
172
173
  // these get caught in onboarding form and handled there
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
- import { DynamicError, MfaInvalidOtpError, EmailAlreadyExistsError, CustomFieldNotUniqueError, UsernameAlreadyExistsError, TooManyEmailVerificationsError, InvalidPhoneNumberError, NoAccessError, AccountExistsError, SandboxMaximumThresholdReachedError, UserHasAccountWithEmailError, sleep } from '@dynamic-labs/utils';
3
+ import { DynamicError, MfaInvalidOtpError, MfaRateLimitedError, EmailAlreadyExistsError, CustomFieldNotUniqueError, UsernameAlreadyExistsError, TooManyEmailVerificationsError, InvalidPhoneNumberError, NoAccessError, AccountExistsError, SandboxMaximumThresholdReachedError, UserHasAccountWithEmailError, sleep } from '@dynamic-labs/utils';
4
4
  import { MfaBackupCodeAcknowledgement } from '@dynamic-labs/sdk-api-core';
5
5
  import { useAccountExistsContext } from '../../../context/AccountExistsContext/AccountExistsContext.js';
6
6
  import 'react';
@@ -162,7 +162,8 @@ const useUserAuth = ({ authMethod, }) => {
162
162
  });
163
163
  const handleAuthError = (error, { options = {}, onError, }) => {
164
164
  var _a;
165
- if (error instanceof MfaInvalidOtpError) {
165
+ if (error instanceof MfaInvalidOtpError ||
166
+ error instanceof MfaRateLimitedError) {
166
167
  throw error;
167
168
  }
168
169
  // these get caught in onboarding form and handled there
@@ -0,0 +1 @@
1
+ export { useWalletOptions } from './useWalletOptions';
@@ -4,10 +4,10 @@
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var _tslib = require('../../../../../_virtual/_tslib.cjs');
7
+ var React = require('react');
7
8
  var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
8
9
  var walletBook = require('@dynamic-labs/wallet-book');
9
10
  var utils = require('@dynamic-labs/utils');
10
- require('react');
11
11
  require('../../../context/DynamicContext/DynamicContext.cjs');
12
12
  require('@dynamic-labs/sdk-api-core');
13
13
  require('../../../shared/logger.cjs');
@@ -93,16 +93,42 @@ require('../../../context/ConnectWithOtpContext/constants.cjs');
93
93
  require('../../../context/ReinitializeContext/ReinitializeContextProvider.cjs');
94
94
  var useInternalDynamicContext = require('../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext.cjs');
95
95
 
96
- const useSelectWalletOption = () => {
96
+ const embeddedWalletsKeys = [
97
+ 'magicemailotp',
98
+ 'magiclink',
99
+ 'magicsocial',
100
+ 'turnkey',
101
+ 'turnkeyhd',
102
+ 'coinbasempc',
103
+ 'zerodev',
104
+ ];
105
+ const useWalletOptions = () => {
97
106
  const { walletConnectorOptions, setShowAuthFlow } = useInternalDynamicContext.useInternalDynamicContext();
98
107
  const { walletBook: walletBook$1 } = walletBook.useWalletBookContext();
99
108
  const { setView } = ViewContext.useViewContext();
100
109
  const { navigateToWalletGroup } = WalletGroupContext.useWalletGroupContext();
101
110
  const { handleWalletItemClick } = useWalletItemActions.useWalletItemActions();
111
+ const walletOptions = React.useMemo(() => {
112
+ var _a;
113
+ return (_a = walletConnectorOptions === null || walletConnectorOptions === void 0 ? void 0 : walletConnectorOptions.filter((option) => !embeddedWalletsKeys.includes(option.walletConnector.key)).map((option) => {
114
+ const groupName = option.group
115
+ ? walletBook.getWalletGroup(walletBook$1, option.group).name
116
+ : undefined;
117
+ return {
118
+ group: option.group,
119
+ groupName,
120
+ key: option.walletConnector.key,
121
+ name: option.name,
122
+ };
123
+ })) !== null && _a !== void 0 ? _a : [];
124
+ }, [walletBook$1, walletConnectorOptions]);
102
125
  const selectWalletOption = (walletKey) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
103
126
  const group = groupWalletOptions.groupWalletOptions(walletBook$1, walletConnectorOptions);
104
127
  const walletOption = group.find((wallet) => wallet.key === walletKey);
105
- logVerboseTroubleshootingMessage.logVerboseTroubleshootingMessage('[useSelectWalletOption] selectWalletOption', { walletKey, walletOption: walletOption === null || walletOption === void 0 ? void 0 : walletOption.key });
128
+ logVerboseTroubleshootingMessage.logVerboseTroubleshootingMessage('[useWalletOptions] selectWalletOption', {
129
+ walletKey,
130
+ walletOption: walletOption === null || walletOption === void 0 ? void 0 : walletOption.key,
131
+ });
106
132
  if (!walletOption) {
107
133
  throw new utils.DynamicError('Invalid wallet option key provided.');
108
134
  }
@@ -123,7 +149,8 @@ const useSelectWalletOption = () => {
123
149
  });
124
150
  return {
125
151
  selectWalletOption,
152
+ walletOptions,
126
153
  };
127
154
  };
128
155
 
129
- exports.useSelectWalletOption = useSelectWalletOption;
156
+ exports.useWalletOptions = useWalletOptions;
@@ -0,0 +1,9 @@
1
+ export declare const useWalletOptions: () => {
2
+ selectWalletOption: (walletKey: string) => Promise<void>;
3
+ walletOptions: {
4
+ group: string | undefined;
5
+ groupName: string | undefined;
6
+ key: string;
7
+ name: string;
8
+ }[];
9
+ };
@@ -1,9 +1,9 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
+ import { useMemo } from 'react';
3
4
  import { isHardwareWalletConnector } from '@dynamic-labs/wallet-connector-core';
4
- import { useWalletBookContext } from '@dynamic-labs/wallet-book';
5
+ import { useWalletBookContext, getWalletGroup } from '@dynamic-labs/wallet-book';
5
6
  import { DynamicError } from '@dynamic-labs/utils';
6
- import 'react';
7
7
  import '../../../context/DynamicContext/DynamicContext.js';
8
8
  import '@dynamic-labs/sdk-api-core';
9
9
  import '../../../shared/logger.js';
@@ -89,16 +89,42 @@ import '../../../context/ConnectWithOtpContext/constants.js';
89
89
  import '../../../context/ReinitializeContext/ReinitializeContextProvider.js';
90
90
  import { useInternalDynamicContext } from '../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext.js';
91
91
 
92
- const useSelectWalletOption = () => {
92
+ const embeddedWalletsKeys = [
93
+ 'magicemailotp',
94
+ 'magiclink',
95
+ 'magicsocial',
96
+ 'turnkey',
97
+ 'turnkeyhd',
98
+ 'coinbasempc',
99
+ 'zerodev',
100
+ ];
101
+ const useWalletOptions = () => {
93
102
  const { walletConnectorOptions, setShowAuthFlow } = useInternalDynamicContext();
94
103
  const { walletBook } = useWalletBookContext();
95
104
  const { setView } = useViewContext();
96
105
  const { navigateToWalletGroup } = useWalletGroupContext();
97
106
  const { handleWalletItemClick } = useWalletItemActions();
107
+ const walletOptions = useMemo(() => {
108
+ var _a;
109
+ return (_a = walletConnectorOptions === null || walletConnectorOptions === void 0 ? void 0 : walletConnectorOptions.filter((option) => !embeddedWalletsKeys.includes(option.walletConnector.key)).map((option) => {
110
+ const groupName = option.group
111
+ ? getWalletGroup(walletBook, option.group).name
112
+ : undefined;
113
+ return {
114
+ group: option.group,
115
+ groupName,
116
+ key: option.walletConnector.key,
117
+ name: option.name,
118
+ };
119
+ })) !== null && _a !== void 0 ? _a : [];
120
+ }, [walletBook, walletConnectorOptions]);
98
121
  const selectWalletOption = (walletKey) => __awaiter(void 0, void 0, void 0, function* () {
99
122
  const group = groupWalletOptions(walletBook, walletConnectorOptions);
100
123
  const walletOption = group.find((wallet) => wallet.key === walletKey);
101
- logVerboseTroubleshootingMessage('[useSelectWalletOption] selectWalletOption', { walletKey, walletOption: walletOption === null || walletOption === void 0 ? void 0 : walletOption.key });
124
+ logVerboseTroubleshootingMessage('[useWalletOptions] selectWalletOption', {
125
+ walletKey,
126
+ walletOption: walletOption === null || walletOption === void 0 ? void 0 : walletOption.key,
127
+ });
102
128
  if (!walletOption) {
103
129
  throw new DynamicError('Invalid wallet option key provided.');
104
130
  }
@@ -119,7 +145,8 @@ const useSelectWalletOption = () => {
119
145
  });
120
146
  return {
121
147
  selectWalletOption,
148
+ walletOptions,
122
149
  };
123
150
  };
124
151
 
125
- export { useSelectWalletOption };
152
+ export { useWalletOptions };
@@ -100,11 +100,18 @@ const MfaVerificationView = ({ type, isInitialSetup = false, showBackButton = fa
100
100
  const { authDevice } = useMfa.useMfa();
101
101
  const [code, setCode] = React.useState('');
102
102
  const [error, setError] = React.useState();
103
+ const [isRateLimited, setIsRateLimited] = React.useState(false);
103
104
  const { data: isValid, isLoading } = usePromise.usePromise(() => authDevice(code, type, deviceId), {
104
105
  deps: [code],
105
106
  enabled: (code === null || code === void 0 ? void 0 : code.length) === 6,
106
- onReject: () => {
107
- setError(new utils.DynamicError(t('dyn_mfa.otp_verification_view.error')));
107
+ onReject: (err) => {
108
+ if (err instanceof utils.MfaRateLimitedError) {
109
+ setIsRateLimited(true);
110
+ setError(new utils.DynamicError(t('dyn_mfa.otp_verification_view.rate_limit_error')));
111
+ }
112
+ else {
113
+ setError(new utils.DynamicError(t('dyn_mfa.otp_verification_view.error')));
114
+ }
108
115
  },
109
116
  onResolve: () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
110
117
  const user = userActions.getUser();
@@ -128,7 +135,7 @@ const MfaVerificationView = ({ type, isInitialSetup = false, showBackButton = fa
128
135
  }
129
136
  setView('mfa-secure-device', { isInitialSetup, type });
130
137
  };
131
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(OTPVerificationView.OTPVerificationView, { MainIcon: passwordHero.ReactComponent, error: error, isLoading: isLoading, onPinComplete: onSubmit, isValid: Boolean(isValid), onPinChange: onCodeChange, description: t('dyn_mfa.otp_verification_view.body'), onClickBack: showBackButton ? onClickBack : undefined }), !isInitialSetup && (jsxRuntime.jsx("div", { className: 'mfa-verification-view__choose-another-method', children: jsxRuntime.jsx(TextButton.TextButton, { className: 'mfa-verification-view__choose-another-method-button', onClick: () => setView('mfa-choose-device', { isInitialSetup }), copykey: 'dyn_mfa.otp_verification_view.choose_another_method', children: t('dyn_mfa.otp_verification_view.choose_another_method') }) }))] }));
138
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(OTPVerificationView.OTPVerificationView, { MainIcon: passwordHero.ReactComponent, error: error, isLoading: isLoading, onPinComplete: onSubmit, isValid: Boolean(isValid), onPinChange: onCodeChange, description: t('dyn_mfa.otp_verification_view.body'), onClickBack: showBackButton ? onClickBack : undefined, disabled: isRateLimited }), !isInitialSetup && (jsxRuntime.jsx("div", { className: 'mfa-verification-view__choose-another-method', children: jsxRuntime.jsx(TextButton.TextButton, { className: 'mfa-verification-view__choose-another-method-button', onClick: () => setView('mfa-choose-device', { isInitialSetup }), copykey: 'dyn_mfa.otp_verification_view.choose_another_method', children: t('dyn_mfa.otp_verification_view.choose_another_method') }) }))] }));
132
139
  };
133
140
 
134
141
  exports.MfaVerificationView = MfaVerificationView;
@@ -3,7 +3,7 @@ import { __awaiter } from '../../../../_virtual/_tslib.js';
3
3
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
4
  import { useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
- import { DynamicError } from '@dynamic-labs/utils';
6
+ import { MfaRateLimitedError, DynamicError } from '@dynamic-labs/utils';
7
7
  import { MfaBackupCodeAcknowledgement } from '@dynamic-labs/sdk-api-core';
8
8
  import '@dynamic-labs/store';
9
9
  import '../../utils/constants/colors.js';
@@ -96,11 +96,18 @@ const MfaVerificationView = ({ type, isInitialSetup = false, showBackButton = fa
96
96
  const { authDevice } = useMfa();
97
97
  const [code, setCode] = useState('');
98
98
  const [error, setError] = useState();
99
+ const [isRateLimited, setIsRateLimited] = useState(false);
99
100
  const { data: isValid, isLoading } = usePromise(() => authDevice(code, type, deviceId), {
100
101
  deps: [code],
101
102
  enabled: (code === null || code === void 0 ? void 0 : code.length) === 6,
102
- onReject: () => {
103
- setError(new DynamicError(t('dyn_mfa.otp_verification_view.error')));
103
+ onReject: (err) => {
104
+ if (err instanceof MfaRateLimitedError) {
105
+ setIsRateLimited(true);
106
+ setError(new DynamicError(t('dyn_mfa.otp_verification_view.rate_limit_error')));
107
+ }
108
+ else {
109
+ setError(new DynamicError(t('dyn_mfa.otp_verification_view.error')));
110
+ }
104
111
  },
105
112
  onResolve: () => __awaiter(void 0, void 0, void 0, function* () {
106
113
  const user = getUser();
@@ -124,7 +131,7 @@ const MfaVerificationView = ({ type, isInitialSetup = false, showBackButton = fa
124
131
  }
125
132
  setView('mfa-secure-device', { isInitialSetup, type });
126
133
  };
127
- return (jsxs(Fragment, { children: [jsx(OTPVerificationView, { MainIcon: SvgPasswordHero, error: error, isLoading: isLoading, onPinComplete: onSubmit, isValid: Boolean(isValid), onPinChange: onCodeChange, description: t('dyn_mfa.otp_verification_view.body'), onClickBack: showBackButton ? onClickBack : undefined }), !isInitialSetup && (jsx("div", { className: 'mfa-verification-view__choose-another-method', children: jsx(TextButton, { className: 'mfa-verification-view__choose-another-method-button', onClick: () => setView('mfa-choose-device', { isInitialSetup }), copykey: 'dyn_mfa.otp_verification_view.choose_another_method', children: t('dyn_mfa.otp_verification_view.choose_another_method') }) }))] }));
134
+ return (jsxs(Fragment, { children: [jsx(OTPVerificationView, { MainIcon: SvgPasswordHero, error: error, isLoading: isLoading, onPinComplete: onSubmit, isValid: Boolean(isValid), onPinChange: onCodeChange, description: t('dyn_mfa.otp_verification_view.body'), onClickBack: showBackButton ? onClickBack : undefined, disabled: isRateLimited }), !isInitialSetup && (jsx("div", { className: 'mfa-verification-view__choose-another-method', children: jsx(TextButton, { className: 'mfa-verification-view__choose-another-method-button', onClick: () => setView('mfa-choose-device', { isInitialSetup }), copykey: 'dyn_mfa.otp_verification_view.choose_another_method', children: t('dyn_mfa.otp_verification_view.choose_another_method') }) }))] }));
128
135
  };
129
136
 
130
137
  export { MfaVerificationView };
@@ -27,6 +27,7 @@ require('../../../../shared/utils/classes/storage/localStorage.cjs');
27
27
  require('../../../../shared/utils/classes/storage/sessionStorage.cjs');
28
28
  var useEffectOnce = require('../../../../shared/utils/hooks/useEffectOnce/useEffectOnce.cjs');
29
29
  require('../../../../shared/consts/index.cjs');
30
+ var useInternalDynamicContext = require('../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext.cjs');
30
31
  require('../../../../context/CaptchaContext/CaptchaContext.cjs');
31
32
  require('../../../../context/ErrorContext/ErrorContext.cjs');
32
33
  require('@dynamic-labs/multi-wallet');
@@ -101,32 +102,45 @@ require('../../../../components/InlineWidget/InlineWidget.cjs');
101
102
  require('qrcode');
102
103
 
103
104
  const ManageMfaWidgetView = () => {
105
+ var _a;
104
106
  const [userDevices, setUserDevices] = React.useState([]);
107
+ const [mfaMethod, setMfaMethod] = React.useState();
105
108
  const [loading, setLoading] = React.useState(false);
106
109
  const { setDynamicWidgetView } = DynamicWidgetContext.useWidgetContext();
107
- const { setShowMfaQRCode } = useDynamicModals.useDynamicModals();
110
+ const { setShowMfaQRCode, setShowOTPVerification } = useDynamicModals.useDynamicModals();
108
111
  const { getUserDevices, deleteUserDevice } = useMfa.useMfa();
109
112
  const { t } = reactI18next.useTranslation();
113
+ const { projectSettings } = useInternalDynamicContext.useInternalDynamicContext();
114
+ const isMfaRequired = Boolean((_a = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.security.mfa) === null || _a === void 0 ? void 0 : _a.required);
110
115
  const getDevices = React.useCallback(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
111
116
  setLoading(true);
112
117
  const devices = yield getUserDevices();
113
118
  // set the user devices with the default device first
114
- setUserDevices(sort.sortAndNameDevices(devices));
119
+ setUserDevices(sort.sortDevices(devices));
115
120
  setLoading(false);
116
121
  }), [getUserDevices]);
117
122
  // re-fetch devices when a new device is added
118
- useDynamicEvents.useDynamicEvents('mfaCompletionSuccess', () => getDevices());
123
+ useDynamicEvents.useDynamicEvents('mfaCompletionSuccess', (_b) => _tslib.__awaiter(void 0, [_b], void 0, function* ({ mfaToken }) {
124
+ if (mfaToken) {
125
+ // we now require an MFA token to delete a device which is an async operation
126
+ if ((mfaMethod === null || mfaMethod === void 0 ? void 0 : mfaMethod.action) === 'remove') {
127
+ yield deleteUserDevice(mfaMethod.params.deviceId, mfaToken);
128
+ setMfaMethod(undefined);
129
+ }
130
+ }
131
+ getDevices();
132
+ }));
119
133
  // delete device and then re-fetch devices
120
134
  const deleteDevice = (id) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
121
- yield deleteUserDevice(id);
122
- getDevices();
135
+ setMfaMethod({ action: 'remove', params: { deviceId: id } });
136
+ setShowOTPVerification(true);
123
137
  });
124
138
  // load devices on initial page load
125
139
  useEffectOnce.useEffectOnce(() => {
126
140
  getDevices();
127
141
  });
128
142
  const backButton = (jsxRuntime.jsx(IconButton.IconButton, { type: 'button', onClick: () => setDynamicWidgetView('settings'), "data-testid": 'back-button', children: jsxRuntime.jsx(chevronLeft.ReactComponent, {}) }));
129
- return (jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view', children: [jsxRuntime.jsx(ModalHeader.ModalHeader, { leading: backButton, children: jsxRuntime.jsx("div", { className: 'send-balance-page-layout__header-content', children: jsxRuntime.jsx(Typography.Typography, { variant: 'title', color: 'primary', copykey: 'dyn_manage_mfa.title', children: t('dyn_manage_mfa.title') }) }) }), jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view__scroll-container', children: [loading && jsxRuntime.jsx(MfaDeviceTileSkeleton.MfaDeviceTileSkeleton, {}), !loading && userDevices.length === 0 && (jsxRuntime.jsx(Typography.Typography, { className: 'manage-mfa-widget-view__no-devices', variant: 'body_normal', color: 'secondary', copykey: 'dyn_manage_mfa.no_devices', children: t('dyn_manage_mfa.no_devices') })), userDevices.map((device, index) => (jsxRuntime.jsx(UserDeviceTile.UserDeviceTile, { userDevice: device, index: index, deleteDevice: deleteDevice }, device.id)))] }), userDevices.length > 0 || (jsxRuntime.jsx("div", { className: 'manage-mfa-widget-view__add-mfa-button-container', children: jsxRuntime.jsx(TypographyButton.TypographyButton, { buttonClassName: 'manage-mfa-widget-view__add-mfa-button-container__button', onClick: () => setShowMfaQRCode(true), copykey: 'dyn_manage_mfa.add_mfa_button', startSlot: jsxRuntime.jsx(add.ReactComponent, {}), children: t('dyn_manage_mfa.add_mfa_button') }) }))] }));
143
+ return (jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view', children: [jsxRuntime.jsx(ModalHeader.ModalHeader, { leading: backButton, children: jsxRuntime.jsx("div", { className: 'send-balance-page-layout__header-content', children: jsxRuntime.jsx(Typography.Typography, { variant: 'title', color: 'primary', copykey: 'dyn_manage_mfa.title', children: t('dyn_manage_mfa.title') }) }) }), jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view__scroll-container', children: [loading && jsxRuntime.jsx(MfaDeviceTileSkeleton.MfaDeviceTileSkeleton, {}), !loading && userDevices.length === 0 && (jsxRuntime.jsx(Typography.Typography, { className: 'manage-mfa-widget-view__no-devices', variant: 'body_normal', color: 'secondary', copykey: 'dyn_manage_mfa.no_devices', children: t('dyn_manage_mfa.no_devices') })), userDevices.map((device, index) => (jsxRuntime.jsx(UserDeviceTile.UserDeviceTile, { isMfaRequired: isMfaRequired, userDevice: device, index: index, deleteDevice: deleteDevice }, device.id)))] }), userDevices.length > 0 || (jsxRuntime.jsx("div", { className: 'manage-mfa-widget-view__add-mfa-button-container', children: jsxRuntime.jsx(TypographyButton.TypographyButton, { buttonClassName: 'manage-mfa-widget-view__add-mfa-button-container__button', onClick: () => setShowMfaQRCode(true), copykey: 'dyn_manage_mfa.add_mfa_button', startSlot: jsxRuntime.jsx(add.ReactComponent, {}), children: t('dyn_manage_mfa.add_mfa_button') }) }))] }));
130
144
  };
131
145
 
132
146
  exports.ManageMfaWidgetView = ManageMfaWidgetView;
@@ -23,6 +23,7 @@ import '../../../../shared/utils/classes/storage/localStorage.js';
23
23
  import '../../../../shared/utils/classes/storage/sessionStorage.js';
24
24
  import { useEffectOnce } from '../../../../shared/utils/hooks/useEffectOnce/useEffectOnce.js';
25
25
  import '../../../../shared/consts/index.js';
26
+ import { useInternalDynamicContext } from '../../../../context/DynamicContext/useDynamicContext/useInternalDynamicContext.js';
26
27
  import '../../../../context/CaptchaContext/CaptchaContext.js';
27
28
  import '../../../../context/ErrorContext/ErrorContext.js';
28
29
  import '@dynamic-labs/multi-wallet';
@@ -71,7 +72,7 @@ import '../../../../context/PasskeyContext/PasskeyContext.js';
71
72
  import '../ManagePasskeysWidgetView/PasskeyCard/PasskeyCard.js';
72
73
  import { MfaDeviceTileSkeleton } from '../../../../components/MfaDeviceTileSkeleton/MfaDeviceTileSkeleton.js';
73
74
  import { UserDeviceTile } from './components/UserDeviceTile.js';
74
- import { sortAndNameDevices } from './components/utils/sort.js';
75
+ import { sortDevices } from './components/utils/sort.js';
75
76
  import '../../../../../polyfills.js';
76
77
  import '../../../../context/ErrorBoundary/ErrorBoundaryBase.js';
77
78
  import '../../../../context/ErrorBoundary/ErrorBoundaryContext.js';
@@ -97,32 +98,45 @@ import '../../../../components/InlineWidget/InlineWidget.js';
97
98
  import 'qrcode';
98
99
 
99
100
  const ManageMfaWidgetView = () => {
101
+ var _a;
100
102
  const [userDevices, setUserDevices] = useState([]);
103
+ const [mfaMethod, setMfaMethod] = useState();
101
104
  const [loading, setLoading] = useState(false);
102
105
  const { setDynamicWidgetView } = useWidgetContext();
103
- const { setShowMfaQRCode } = useDynamicModals();
106
+ const { setShowMfaQRCode, setShowOTPVerification } = useDynamicModals();
104
107
  const { getUserDevices, deleteUserDevice } = useMfa();
105
108
  const { t } = useTranslation();
109
+ const { projectSettings } = useInternalDynamicContext();
110
+ const isMfaRequired = Boolean((_a = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.security.mfa) === null || _a === void 0 ? void 0 : _a.required);
106
111
  const getDevices = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
107
112
  setLoading(true);
108
113
  const devices = yield getUserDevices();
109
114
  // set the user devices with the default device first
110
- setUserDevices(sortAndNameDevices(devices));
115
+ setUserDevices(sortDevices(devices));
111
116
  setLoading(false);
112
117
  }), [getUserDevices]);
113
118
  // re-fetch devices when a new device is added
114
- useDynamicEvents('mfaCompletionSuccess', () => getDevices());
119
+ useDynamicEvents('mfaCompletionSuccess', (_b) => __awaiter(void 0, [_b], void 0, function* ({ mfaToken }) {
120
+ if (mfaToken) {
121
+ // we now require an MFA token to delete a device which is an async operation
122
+ if ((mfaMethod === null || mfaMethod === void 0 ? void 0 : mfaMethod.action) === 'remove') {
123
+ yield deleteUserDevice(mfaMethod.params.deviceId, mfaToken);
124
+ setMfaMethod(undefined);
125
+ }
126
+ }
127
+ getDevices();
128
+ }));
115
129
  // delete device and then re-fetch devices
116
130
  const deleteDevice = (id) => __awaiter(void 0, void 0, void 0, function* () {
117
- yield deleteUserDevice(id);
118
- getDevices();
131
+ setMfaMethod({ action: 'remove', params: { deviceId: id } });
132
+ setShowOTPVerification(true);
119
133
  });
120
134
  // load devices on initial page load
121
135
  useEffectOnce(() => {
122
136
  getDevices();
123
137
  });
124
138
  const backButton = (jsx(IconButton, { type: 'button', onClick: () => setDynamicWidgetView('settings'), "data-testid": 'back-button', children: jsx(SvgChevronLeft, {}) }));
125
- return (jsxs("div", { className: 'manage-mfa-widget-view', children: [jsx(ModalHeader, { leading: backButton, children: jsx("div", { className: 'send-balance-page-layout__header-content', children: jsx(Typography, { variant: 'title', color: 'primary', copykey: 'dyn_manage_mfa.title', children: t('dyn_manage_mfa.title') }) }) }), jsxs("div", { className: 'manage-mfa-widget-view__scroll-container', children: [loading && jsx(MfaDeviceTileSkeleton, {}), !loading && userDevices.length === 0 && (jsx(Typography, { className: 'manage-mfa-widget-view__no-devices', variant: 'body_normal', color: 'secondary', copykey: 'dyn_manage_mfa.no_devices', children: t('dyn_manage_mfa.no_devices') })), userDevices.map((device, index) => (jsx(UserDeviceTile, { userDevice: device, index: index, deleteDevice: deleteDevice }, device.id)))] }), userDevices.length > 0 || (jsx("div", { className: 'manage-mfa-widget-view__add-mfa-button-container', children: jsx(TypographyButton, { buttonClassName: 'manage-mfa-widget-view__add-mfa-button-container__button', onClick: () => setShowMfaQRCode(true), copykey: 'dyn_manage_mfa.add_mfa_button', startSlot: jsx(SvgAdd, {}), children: t('dyn_manage_mfa.add_mfa_button') }) }))] }));
139
+ return (jsxs("div", { className: 'manage-mfa-widget-view', children: [jsx(ModalHeader, { leading: backButton, children: jsx("div", { className: 'send-balance-page-layout__header-content', children: jsx(Typography, { variant: 'title', color: 'primary', copykey: 'dyn_manage_mfa.title', children: t('dyn_manage_mfa.title') }) }) }), jsxs("div", { className: 'manage-mfa-widget-view__scroll-container', children: [loading && jsx(MfaDeviceTileSkeleton, {}), !loading && userDevices.length === 0 && (jsx(Typography, { className: 'manage-mfa-widget-view__no-devices', variant: 'body_normal', color: 'secondary', copykey: 'dyn_manage_mfa.no_devices', children: t('dyn_manage_mfa.no_devices') })), userDevices.map((device, index) => (jsx(UserDeviceTile, { isMfaRequired: isMfaRequired, userDevice: device, index: index, deleteDevice: deleteDevice }, device.id)))] }), userDevices.length > 0 || (jsx("div", { className: 'manage-mfa-widget-view__add-mfa-button-container', children: jsx(TypographyButton, { buttonClassName: 'manage-mfa-widget-view__add-mfa-button-container__button', onClick: () => setShowMfaQRCode(true), copykey: 'dyn_manage_mfa.add_mfa_button', startSlot: jsx(SvgAdd, {}), children: t('dyn_manage_mfa.add_mfa_button') }) }))] }));
126
140
  };
127
141
 
128
142
  export { ManageMfaWidgetView };
@@ -83,7 +83,6 @@ require('../../../../../components/Popper/PopperContext/PopperContext.cjs');
83
83
  require('../../../../../views/WalletList/WalletList.cjs');
84
84
  require('../../../../DynamicBridgeWidget/views/WalletsView/components/SecondaryWallets/SecondaryWallets.cjs');
85
85
  require('@hcaptcha/react-hcaptcha');
86
- var Badge = require('../../../../../components/Badge/Badge.cjs');
87
86
  require('../../../../../context/IpConfigurationContext/IpConfigurationContext.cjs');
88
87
  require('../../../../../components/PasskeyCreatedSuccessBanner/PasskeyCreatedSuccessBanner.cjs');
89
88
  require('../../../../../context/SendBalanceContext/SendBalanceContext.cjs');
@@ -93,7 +92,7 @@ require('../../../../../context/ReinitializeContext/ReinitializeContextProvider.
93
92
  require('../../../../../components/InlineWidget/InlineWidget.cjs');
94
93
  require('qrcode');
95
94
 
96
- const UserDeviceTile = ({ userDevice, deleteDevice, }) => {
95
+ const UserDeviceTile = ({ userDevice, deleteDevice, isMfaRequired, }) => {
97
96
  const optionsMenu = [
98
97
  {
99
98
  Icon: null,
@@ -102,10 +101,10 @@ const UserDeviceTile = ({ userDevice, deleteDevice, }) => {
102
101
  },
103
102
  ];
104
103
  const timeSinceCreated = userDevice.verifiedAt && getTimeSince.getTimeSince(new Date(userDevice.verifiedAt));
105
- return (jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view__list-tile', children: [jsxRuntime.jsx(authenticator.ReactComponent, { className: 'manage-mfa-widget-view__list-tile__icon' }), jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view__list-tile__details', children: [jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view__list-tile__details__title', children: [jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', color: 'primary', children: userDevice.alias || 'Authenticator App' }), userDevice._default && jsxRuntime.jsx(Badge.Badge, { text: 'Default' })] }), timeSinceCreated && (jsxRuntime.jsxs(Typography.Typography, { variant: 'body_small', color: 'secondary', children: ["Created ", timeSinceCreated.value, " ", timeSinceCreated.unit, " ago"] }))] }), jsxRuntime.jsx("div", { style: {
104
+ return (jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view__list-tile', children: [jsxRuntime.jsx(authenticator.ReactComponent, { className: 'manage-mfa-widget-view__list-tile__icon' }), jsxRuntime.jsxs("div", { className: 'manage-mfa-widget-view__list-tile__details', children: [jsxRuntime.jsx("div", { className: 'manage-mfa-widget-view__list-tile__details__title', children: jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', color: 'primary', children: userDevice.alias || 'Authenticator App' }) }), timeSinceCreated && (jsxRuntime.jsxs(Typography.Typography, { variant: 'body_small', color: 'secondary', children: ["Created ", timeSinceCreated.value, " ", timeSinceCreated.unit, " ago"] }))] }), isMfaRequired || (jsxRuntime.jsx("div", { style: {
106
105
  cursor: 'pointer',
107
106
  display: 'flex',
108
- }, children: jsxRuntime.jsx(DotsMenu.DotsMenu, { direction: 'left', "data-testid": 'dots-menu', options: optionsMenu, buttonClassName: 'manage-mfa-widget-view__list-tile__dots-menu', buttonClassNameWithOpenMenu: 'manage-mfa-widget-view__list-tile__dots-menu' }) })] }, userDevice.id));
107
+ }, children: jsxRuntime.jsx(DotsMenu.DotsMenu, { direction: 'left', "data-testid": 'dots-menu', options: optionsMenu, buttonClassName: 'manage-mfa-widget-view__list-tile__dots-menu', buttonClassNameWithOpenMenu: 'manage-mfa-widget-view__list-tile__dots-menu' }) }))] }, userDevice.id));
109
108
  };
110
109
 
111
110
  exports.UserDeviceTile = UserDeviceTile;
@@ -4,5 +4,6 @@ export type UserDeviceTileProps = {
4
4
  userDevice: MFADevice;
5
5
  index: number;
6
6
  deleteDevice: (id: string) => void;
7
+ isMfaRequired: boolean;
7
8
  };
8
- export declare const UserDeviceTile: ({ userDevice, deleteDevice, }: UserDeviceTileProps) => JSX.Element;
9
+ export declare const UserDeviceTile: ({ userDevice, deleteDevice, isMfaRequired, }: UserDeviceTileProps) => JSX.Element;
@@ -79,7 +79,6 @@ import '../../../../../components/Popper/PopperContext/PopperContext.js';
79
79
  import '../../../../../views/WalletList/WalletList.js';
80
80
  import '../../../../DynamicBridgeWidget/views/WalletsView/components/SecondaryWallets/SecondaryWallets.js';
81
81
  import '@hcaptcha/react-hcaptcha';
82
- import { Badge } from '../../../../../components/Badge/Badge.js';
83
82
  import '../../../../../context/IpConfigurationContext/IpConfigurationContext.js';
84
83
  import '../../../../../components/PasskeyCreatedSuccessBanner/PasskeyCreatedSuccessBanner.js';
85
84
  import '../../../../../context/SendBalanceContext/SendBalanceContext.js';
@@ -89,7 +88,7 @@ import '../../../../../context/ReinitializeContext/ReinitializeContextProvider.j
89
88
  import '../../../../../components/InlineWidget/InlineWidget.js';
90
89
  import 'qrcode';
91
90
 
92
- const UserDeviceTile = ({ userDevice, deleteDevice, }) => {
91
+ const UserDeviceTile = ({ userDevice, deleteDevice, isMfaRequired, }) => {
93
92
  const optionsMenu = [
94
93
  {
95
94
  Icon: null,
@@ -98,10 +97,10 @@ const UserDeviceTile = ({ userDevice, deleteDevice, }) => {
98
97
  },
99
98
  ];
100
99
  const timeSinceCreated = userDevice.verifiedAt && getTimeSince(new Date(userDevice.verifiedAt));
101
- return (jsxs("div", { className: 'manage-mfa-widget-view__list-tile', children: [jsx(SvgAuthenticator, { className: 'manage-mfa-widget-view__list-tile__icon' }), jsxs("div", { className: 'manage-mfa-widget-view__list-tile__details', children: [jsxs("div", { className: 'manage-mfa-widget-view__list-tile__details__title', children: [jsx(Typography, { variant: 'body_normal', color: 'primary', children: userDevice.alias || 'Authenticator App' }), userDevice._default && jsx(Badge, { text: 'Default' })] }), timeSinceCreated && (jsxs(Typography, { variant: 'body_small', color: 'secondary', children: ["Created ", timeSinceCreated.value, " ", timeSinceCreated.unit, " ago"] }))] }), jsx("div", { style: {
100
+ return (jsxs("div", { className: 'manage-mfa-widget-view__list-tile', children: [jsx(SvgAuthenticator, { className: 'manage-mfa-widget-view__list-tile__icon' }), jsxs("div", { className: 'manage-mfa-widget-view__list-tile__details', children: [jsx("div", { className: 'manage-mfa-widget-view__list-tile__details__title', children: jsx(Typography, { variant: 'body_normal', color: 'primary', children: userDevice.alias || 'Authenticator App' }) }), timeSinceCreated && (jsxs(Typography, { variant: 'body_small', color: 'secondary', children: ["Created ", timeSinceCreated.value, " ", timeSinceCreated.unit, " ago"] }))] }), isMfaRequired || (jsx("div", { style: {
102
101
  cursor: 'pointer',
103
102
  display: 'flex',
104
- }, children: jsx(DotsMenu, { direction: 'left', "data-testid": 'dots-menu', options: optionsMenu, buttonClassName: 'manage-mfa-widget-view__list-tile__dots-menu', buttonClassNameWithOpenMenu: 'manage-mfa-widget-view__list-tile__dots-menu' }) })] }, userDevice.id));
103
+ }, children: jsx(DotsMenu, { direction: 'left', "data-testid": 'dots-menu', options: optionsMenu, buttonClassName: 'manage-mfa-widget-view__list-tile__dots-menu', buttonClassNameWithOpenMenu: 'manage-mfa-widget-view__list-tile__dots-menu' }) }))] }, userDevice.id));
105
104
  };
106
105
 
107
106
  export { UserDeviceTile };
@@ -10,14 +10,8 @@ const sortDevicesByVerifiedDateDesc = (a, b) => {
10
10
  const dateB = b.verifiedAt ? new Date(b.verifiedAt).getTime() : 0;
11
11
  return dateA - dateB;
12
12
  };
13
- const sortAndNameDevices = (devices) => devices
14
- .sort(sortDevicesByVerifiedDateDesc)
15
- .map((device, index) => {
16
- device.alias = device.alias || `Authenticator App ${index + 1}`;
17
- return device;
18
- })
19
- .sort(sortDevicesByDefault);
13
+ const sortDevices = (devices) => devices.sort(sortDevicesByVerifiedDateDesc).sort(sortDevicesByDefault);
20
14
 
21
- exports.sortAndNameDevices = sortAndNameDevices;
15
+ exports.sortDevices = sortDevices;
22
16
  exports.sortDevicesByDefault = sortDevicesByDefault;
23
17
  exports.sortDevicesByVerifiedDateDesc = sortDevicesByVerifiedDateDesc;