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

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 (71) hide show
  1. package/CHANGELOG.md +34 -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/shared/utils/functions/hasPendingRequirements/hasPendingRequirements.cjs +10 -0
  34. package/src/lib/shared/utils/functions/hasPendingRequirements/hasPendingRequirements.d.ts +2 -0
  35. package/src/lib/shared/utils/functions/hasPendingRequirements/hasPendingRequirements.js +6 -0
  36. package/src/lib/shared/utils/functions/hasPendingRequirements/index.d.ts +1 -0
  37. package/src/lib/shared/utils/functions/index.d.ts +1 -0
  38. package/src/lib/store/hooks/useUser/useUser.cjs +2 -4
  39. package/src/lib/store/hooks/useUser/useUser.js +2 -4
  40. package/src/lib/styles/index.shadow.cjs +1 -1
  41. package/src/lib/styles/index.shadow.js +1 -1
  42. package/src/lib/utils/functions/isCookieEnabled/isCookieEnabled.cjs +8 -1
  43. package/src/lib/utils/functions/isCookieEnabled/isCookieEnabled.js +8 -1
  44. package/src/lib/utils/hooks/index.d.ts +1 -1
  45. package/src/lib/utils/hooks/useExternalAuth/useExternalAuth.cjs +4 -1
  46. package/src/lib/utils/hooks/useExternalAuth/useExternalAuth.js +4 -1
  47. package/src/lib/utils/hooks/useMfa/useMfa.cjs +2 -1
  48. package/src/lib/utils/hooks/useMfa/useMfa.d.ts +1 -1
  49. package/src/lib/utils/hooks/useMfa/useMfa.js +2 -1
  50. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.cjs +7 -13
  51. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.js +7 -13
  52. package/src/lib/utils/hooks/useUserAuth/useUserAuth.cjs +2 -1
  53. package/src/lib/utils/hooks/useUserAuth/useUserAuth.js +3 -2
  54. package/src/lib/utils/hooks/useWalletOptions/index.d.ts +1 -0
  55. package/src/lib/utils/hooks/{useSelectWalletOption/useSelectWalletOption.cjs → useWalletOptions/useWalletOptions.cjs} +31 -4
  56. package/src/lib/utils/hooks/useWalletOptions/useWalletOptions.d.ts +9 -0
  57. package/src/lib/utils/hooks/{useSelectWalletOption/useSelectWalletOption.js → useWalletOptions/useWalletOptions.js} +32 -5
  58. package/src/lib/views/CollectUserDataView/CollectUserDataView.cjs +6 -5
  59. package/src/lib/views/CollectUserDataView/CollectUserDataView.js +6 -5
  60. package/src/lib/views/MfaVerificationView/MfaVerificationView.cjs +10 -3
  61. package/src/lib/views/MfaVerificationView/MfaVerificationView.js +11 -4
  62. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/ManageMfaWidgetView.cjs +20 -6
  63. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/ManageMfaWidgetView.js +21 -7
  64. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/UserDeviceTile.cjs +3 -4
  65. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/UserDeviceTile.d.ts +2 -1
  66. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/UserDeviceTile.js +3 -4
  67. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/utils/sort.cjs +2 -8
  68. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/utils/sort.d.ts +1 -1
  69. package/src/lib/widgets/DynamicWidget/views/ManageMfaWidgetView/components/utils/sort.js +2 -8
  70. package/src/lib/utils/hooks/useSelectWalletOption/index.d.ts +0 -1
  71. package/src/lib/utils/hooks/useSelectWalletOption/useSelectWalletOption.d.ts +0 -3
@@ -4,6 +4,7 @@
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var sdkApiCore = require('@dynamic-labs/sdk-api-core');
7
+ var utils = require('@dynamic-labs/utils');
7
8
  require('@dynamic-labs/store');
8
9
  require('../../constants/colors.cjs');
9
10
  require('../../constants/values.cjs');
@@ -16,7 +17,6 @@ require('react');
16
17
  require('@dynamic-labs/wallet-book');
17
18
  require('../../../shared/utils/classes/storage/localStorage.cjs');
18
19
  require('../../../shared/utils/classes/storage/sessionStorage.cjs');
19
- require('@dynamic-labs/utils');
20
20
  require('../../../shared/consts/index.cjs');
21
21
  var projectSettingsActions = require('../../../store/actions/projectSettingsActions/projectSettingsActions.cjs');
22
22
  require('../../../../../_virtual/_tslib.cjs');
@@ -91,6 +91,13 @@ require('../../../context/ReinitializeContext/ReinitializeContextProvider.cjs');
91
91
 
92
92
  const isCookieEnabled = () => {
93
93
  var _a, _b, _c, _d;
94
+ /**
95
+ * There is no cookie on native mobile applications
96
+ * so this feature must be disabled for native mobile
97
+ */
98
+ if (utils.PlatformService.isNativeMobile) {
99
+ return false;
100
+ }
94
101
  const securitySettings = (_b = (_a = projectSettingsActions.getProjectSettings()) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.security;
95
102
  if (!securitySettings)
96
103
  return false;
@@ -1,5 +1,6 @@
1
1
  'use client'
2
2
  import { AuthStorageEnum } from '@dynamic-labs/sdk-api-core';
3
+ import { PlatformService } from '@dynamic-labs/utils';
3
4
  import '@dynamic-labs/store';
4
5
  import '../../constants/colors.js';
5
6
  import '../../constants/values.js';
@@ -12,7 +13,6 @@ import 'react';
12
13
  import '@dynamic-labs/wallet-book';
13
14
  import '../../../shared/utils/classes/storage/localStorage.js';
14
15
  import '../../../shared/utils/classes/storage/sessionStorage.js';
15
- import '@dynamic-labs/utils';
16
16
  import '../../../shared/consts/index.js';
17
17
  import { getProjectSettings } from '../../../store/actions/projectSettingsActions/projectSettingsActions.js';
18
18
  import '../../../../../_virtual/_tslib.js';
@@ -87,6 +87,13 @@ import '../../../context/ReinitializeContext/ReinitializeContextProvider.js';
87
87
 
88
88
  const isCookieEnabled = () => {
89
89
  var _a, _b, _c, _d;
90
+ /**
91
+ * There is no cookie on native mobile applications
92
+ * so this feature must be disabled for native mobile
93
+ */
94
+ if (PlatformService.isNativeMobile) {
95
+ return false;
96
+ }
90
97
  const securitySettings = (_b = (_a = getProjectSettings()) === null || _a === void 0 ? void 0 : _a.settings) === null || _b === void 0 ? void 0 : _b.security;
91
98
  if (!securitySettings)
92
99
  return false;
@@ -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';
@@ -17,6 +17,7 @@ require('../../constants/colors.cjs');
17
17
  require('../../constants/values.cjs');
18
18
  require('../../../shared/utils/classes/storage/localStorage.cjs');
19
19
  require('../../../shared/utils/classes/storage/sessionStorage.cjs');
20
+ var hasPendingRequirements = require('../../../shared/utils/functions/hasPendingRequirements/hasPendingRequirements.cjs');
20
21
  require('../../../shared/consts/index.cjs');
21
22
  require('../../../config/ApiEndpoint.cjs');
22
23
  require('@dynamic-labs/multi-wallet');
@@ -109,7 +110,9 @@ const useExternalAuth = () => {
109
110
  externalJwt,
110
111
  });
111
112
  setCallback('authSuccess');
112
- setShowAuthFlow(false);
113
+ if (userProfile && !hasPendingRequirements.hasPendingRequirements(userProfile)) {
114
+ setShowAuthFlow(false);
115
+ }
113
116
  return userProfile;
114
117
  }
115
118
  catch (e) {
@@ -13,6 +13,7 @@ import '../../constants/colors.js';
13
13
  import '../../constants/values.js';
14
14
  import '../../../shared/utils/classes/storage/localStorage.js';
15
15
  import '../../../shared/utils/classes/storage/sessionStorage.js';
16
+ import { hasPendingRequirements } from '../../../shared/utils/functions/hasPendingRequirements/hasPendingRequirements.js';
16
17
  import '../../../shared/consts/index.js';
17
18
  import '../../../config/ApiEndpoint.js';
18
19
  import '@dynamic-labs/multi-wallet';
@@ -105,7 +106,9 @@ const useExternalAuth = () => {
105
106
  externalJwt,
106
107
  });
107
108
  setCallback('authSuccess');
108
- setShowAuthFlow(false);
109
+ if (userProfile && !hasPendingRequirements(userProfile)) {
110
+ setShowAuthFlow(false);
111
+ }
109
112
  return userProfile;
110
113
  }
111
114
  catch (e) {
@@ -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
  });
@@ -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 };
@@ -107,15 +107,16 @@ const CollectUserDataView = () => {
107
107
  const [isNetworkPickerOpen, setIsNetworkPickerOpen] = React.useState(false);
108
108
  const nameService = useFetchNameService.useFetchNameService();
109
109
  const { t } = reactI18next.useTranslation();
110
- if (!walletConnector || !userWithMissingInfo) {
110
+ if (!userWithMissingInfo) {
111
111
  return null;
112
112
  }
113
- const evmNetworks = walletConnector.evmNetworks || [];
113
+ const evmNetworks = (walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.evmNetworks) || [];
114
114
  const _isSupportedNetwork = !network || isSupportedNetwork.isSupportedNetwork({ network, walletConnector });
115
+ const shouldDisplayWrongNetworkState = !_isSupportedNetwork && Boolean(walletConnector);
115
116
  const walletAddress = (_a = userWithMissingInfo === null || userWithMissingInfo === void 0 ? void 0 : userWithMissingInfo.verifiedCredentials.find((verifiedCredential) => verifiedCredential.id === userWithMissingInfo.lastVerifiedCredentialId)) === null || _a === void 0 ? void 0 : _a.address;
116
- return (jsxRuntime.jsxs("div", { className: 'collect-user-data', "data-testid": 'collect-user-data-view', children: [jsxRuntime.jsxs("div", { className: 'collect-user-data__network-container', children: [jsxRuntime.jsxs("div", { className: 'collect-user-data__img-container', children: [(nameService === null || nameService === void 0 ? void 0 : nameService.avatar) ? (jsxRuntime.jsx("img", { src: nameService.avatar, alt: '', className: 'collect-user-data__img collect-user-data__img--rounded' })) : (jsxRuntime.jsx(AuthProviderIcon.AuthProviderIcon, { iconSize: 28 })), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', color: 'primary', weight: 'medium', className: 'collect-user-data__wallet-address', children: (nameService === null || nameService === void 0 ? void 0 : nameService.name) || shortenWalletAddress.shortenWalletAddress(walletAddress, 3, 3) })] }), jsxRuntime.jsx(NetworkPicker.NetworkPicker, { currentNetwork: network, evmNetworks: evmNetworks, connector: walletConnector, showNetworkName: true, isNetworkPickerOpen: isNetworkPickerOpen, setIsNetworkPickerOpen: setIsNetworkPickerOpen, buttonClassName: 'collect-user-data__network-picker-button', mainClassName: 'collect-user-data__network-picker' })] }), onboardingImageUrl && (jsxRuntime.jsx("img", { className: 'collect-user-data__main-img', src: onboardingImageUrl, alt: 'onboarding' })), !_isSupportedNetwork && (jsxRuntime.jsx(ErrorContainer.ErrorContainer, { withIcon: false, className: 'collect-user-data__error--not-supported', copykey: 'dyn_collect_user_data.not_supported_network.error_message', children: t('dyn_collect_user_data.not_supported_network.error_message') })), jsxRuntime.jsxs("div", { className: classNames.classNames('collect-user-data__form', {
117
- 'collect-user-data__form--error': !_isSupportedNetwork,
118
- }), children: [jsxRuntime.jsx("div", { className: 'collect-user-data__success-icon', children: jsxRuntime.jsx(Icon.Icon, { color: 'text-primary', size: 'large', children: jsxRuntime.jsx(checkConnection.ReactComponent, {}) }) }), jsxRuntime.jsx(OnboardingUserDataForm.OnboardingUserDataForm, { disableSubmit: !_isSupportedNetwork, userProfile: userWithMissingInfo, children: !_isSupportedNetwork ? (jsxRuntime.jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsxRuntime.jsx(Typography.Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.not_supported_network.title', children: t('dyn_collect_user_data.not_supported_network.title') }), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', weight: 'regular', color: 'secondary', copykey: 'dyn_collect_user_data.not_supported_network.description', children: t('dyn_collect_user_data.not_supported_network.description') })] })) : (jsxRuntime.jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsxRuntime.jsx(Typography.Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.greeting', children: (projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.general.collectUserDataWelcomeHeader) ||
117
+ return (jsxRuntime.jsxs("div", { className: 'collect-user-data', "data-testid": 'collect-user-data-view', children: [jsxRuntime.jsxs("div", { className: 'collect-user-data__network-container', children: [jsxRuntime.jsxs("div", { className: 'collect-user-data__img-container', children: [(nameService === null || nameService === void 0 ? void 0 : nameService.avatar) ? (jsxRuntime.jsx("img", { src: nameService.avatar, alt: '', className: 'collect-user-data__img collect-user-data__img--rounded' })) : (jsxRuntime.jsx(AuthProviderIcon.AuthProviderIcon, { iconSize: 28 })), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', color: 'primary', weight: 'medium', className: 'collect-user-data__wallet-address', children: (nameService === null || nameService === void 0 ? void 0 : nameService.name) || shortenWalletAddress.shortenWalletAddress(walletAddress, 3, 3) })] }), walletConnector && (jsxRuntime.jsx(NetworkPicker.NetworkPicker, { currentNetwork: network, evmNetworks: evmNetworks, connector: walletConnector, showNetworkName: true, isNetworkPickerOpen: isNetworkPickerOpen, setIsNetworkPickerOpen: setIsNetworkPickerOpen, buttonClassName: 'collect-user-data__network-picker-button', mainClassName: 'collect-user-data__network-picker' }))] }), onboardingImageUrl && (jsxRuntime.jsx("img", { className: 'collect-user-data__main-img', src: onboardingImageUrl, alt: 'onboarding' })), shouldDisplayWrongNetworkState && (jsxRuntime.jsx(ErrorContainer.ErrorContainer, { withIcon: false, className: 'collect-user-data__error--not-supported', copykey: 'dyn_collect_user_data.not_supported_network.error_message', children: t('dyn_collect_user_data.not_supported_network.error_message') })), jsxRuntime.jsxs("div", { className: classNames.classNames('collect-user-data__form', {
118
+ 'collect-user-data__form--error': shouldDisplayWrongNetworkState,
119
+ }), children: [jsxRuntime.jsx("div", { className: 'collect-user-data__success-icon', children: jsxRuntime.jsx(Icon.Icon, { color: 'text-primary', size: 'large', children: jsxRuntime.jsx(checkConnection.ReactComponent, {}) }) }), jsxRuntime.jsx(OnboardingUserDataForm.OnboardingUserDataForm, { disableSubmit: shouldDisplayWrongNetworkState, userProfile: userWithMissingInfo, children: shouldDisplayWrongNetworkState ? (jsxRuntime.jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsxRuntime.jsx(Typography.Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.not_supported_network.title', children: t('dyn_collect_user_data.not_supported_network.title') }), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', weight: 'regular', color: 'secondary', copykey: 'dyn_collect_user_data.not_supported_network.description', children: t('dyn_collect_user_data.not_supported_network.description') })] })) : (jsxRuntime.jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsxRuntime.jsx(Typography.Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.greeting', children: (projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.general.collectUserDataWelcomeHeader) ||
119
120
  t('dyn_collect_user_data.greeting', { appName }) }), jsxRuntime.jsx(Typography.Typography, { variant: 'body_normal', weight: 'regular', color: 'secondary', copykey: 'dyn_collect_user_data.description', children: (projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.general.collectUserDataWelcomeMessage) ||
120
121
  t('dyn_collect_user_data.description') })] })) }), jsxRuntime.jsx(TextButton.TextButton, { className: 'collect-user-data__log-out', onClick: handleLogOut, copykey: 'dyn_collect_user_data.log_out_button', children: t('dyn_collect_user_data.log_out_button') })] })] }));
121
122
  };
@@ -103,15 +103,16 @@ const CollectUserDataView = () => {
103
103
  const [isNetworkPickerOpen, setIsNetworkPickerOpen] = useState(false);
104
104
  const nameService = useFetchNameService();
105
105
  const { t } = useTranslation();
106
- if (!walletConnector || !userWithMissingInfo) {
106
+ if (!userWithMissingInfo) {
107
107
  return null;
108
108
  }
109
- const evmNetworks = walletConnector.evmNetworks || [];
109
+ const evmNetworks = (walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.evmNetworks) || [];
110
110
  const _isSupportedNetwork = !network || isSupportedNetwork({ network, walletConnector });
111
+ const shouldDisplayWrongNetworkState = !_isSupportedNetwork && Boolean(walletConnector);
111
112
  const walletAddress = (_a = userWithMissingInfo === null || userWithMissingInfo === void 0 ? void 0 : userWithMissingInfo.verifiedCredentials.find((verifiedCredential) => verifiedCredential.id === userWithMissingInfo.lastVerifiedCredentialId)) === null || _a === void 0 ? void 0 : _a.address;
112
- return (jsxs("div", { className: 'collect-user-data', "data-testid": 'collect-user-data-view', children: [jsxs("div", { className: 'collect-user-data__network-container', children: [jsxs("div", { className: 'collect-user-data__img-container', children: [(nameService === null || nameService === void 0 ? void 0 : nameService.avatar) ? (jsx("img", { src: nameService.avatar, alt: '', className: 'collect-user-data__img collect-user-data__img--rounded' })) : (jsx(AuthProviderIcon, { iconSize: 28 })), jsx(Typography, { variant: 'body_normal', color: 'primary', weight: 'medium', className: 'collect-user-data__wallet-address', children: (nameService === null || nameService === void 0 ? void 0 : nameService.name) || shortenWalletAddress(walletAddress, 3, 3) })] }), jsx(NetworkPicker, { currentNetwork: network, evmNetworks: evmNetworks, connector: walletConnector, showNetworkName: true, isNetworkPickerOpen: isNetworkPickerOpen, setIsNetworkPickerOpen: setIsNetworkPickerOpen, buttonClassName: 'collect-user-data__network-picker-button', mainClassName: 'collect-user-data__network-picker' })] }), onboardingImageUrl && (jsx("img", { className: 'collect-user-data__main-img', src: onboardingImageUrl, alt: 'onboarding' })), !_isSupportedNetwork && (jsx(ErrorContainer, { withIcon: false, className: 'collect-user-data__error--not-supported', copykey: 'dyn_collect_user_data.not_supported_network.error_message', children: t('dyn_collect_user_data.not_supported_network.error_message') })), jsxs("div", { className: classNames('collect-user-data__form', {
113
- 'collect-user-data__form--error': !_isSupportedNetwork,
114
- }), children: [jsx("div", { className: 'collect-user-data__success-icon', children: jsx(Icon, { color: 'text-primary', size: 'large', children: jsx(SvgCheckConnection, {}) }) }), jsx(OnboardingUserDataForm, { disableSubmit: !_isSupportedNetwork, userProfile: userWithMissingInfo, children: !_isSupportedNetwork ? (jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsx(Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.not_supported_network.title', children: t('dyn_collect_user_data.not_supported_network.title') }), jsx(Typography, { variant: 'body_normal', weight: 'regular', color: 'secondary', copykey: 'dyn_collect_user_data.not_supported_network.description', children: t('dyn_collect_user_data.not_supported_network.description') })] })) : (jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsx(Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.greeting', children: (projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.general.collectUserDataWelcomeHeader) ||
113
+ return (jsxs("div", { className: 'collect-user-data', "data-testid": 'collect-user-data-view', children: [jsxs("div", { className: 'collect-user-data__network-container', children: [jsxs("div", { className: 'collect-user-data__img-container', children: [(nameService === null || nameService === void 0 ? void 0 : nameService.avatar) ? (jsx("img", { src: nameService.avatar, alt: '', className: 'collect-user-data__img collect-user-data__img--rounded' })) : (jsx(AuthProviderIcon, { iconSize: 28 })), jsx(Typography, { variant: 'body_normal', color: 'primary', weight: 'medium', className: 'collect-user-data__wallet-address', children: (nameService === null || nameService === void 0 ? void 0 : nameService.name) || shortenWalletAddress(walletAddress, 3, 3) })] }), walletConnector && (jsx(NetworkPicker, { currentNetwork: network, evmNetworks: evmNetworks, connector: walletConnector, showNetworkName: true, isNetworkPickerOpen: isNetworkPickerOpen, setIsNetworkPickerOpen: setIsNetworkPickerOpen, buttonClassName: 'collect-user-data__network-picker-button', mainClassName: 'collect-user-data__network-picker' }))] }), onboardingImageUrl && (jsx("img", { className: 'collect-user-data__main-img', src: onboardingImageUrl, alt: 'onboarding' })), shouldDisplayWrongNetworkState && (jsx(ErrorContainer, { withIcon: false, className: 'collect-user-data__error--not-supported', copykey: 'dyn_collect_user_data.not_supported_network.error_message', children: t('dyn_collect_user_data.not_supported_network.error_message') })), jsxs("div", { className: classNames('collect-user-data__form', {
114
+ 'collect-user-data__form--error': shouldDisplayWrongNetworkState,
115
+ }), children: [jsx("div", { className: 'collect-user-data__success-icon', children: jsx(Icon, { color: 'text-primary', size: 'large', children: jsx(SvgCheckConnection, {}) }) }), jsx(OnboardingUserDataForm, { disableSubmit: shouldDisplayWrongNetworkState, userProfile: userWithMissingInfo, children: shouldDisplayWrongNetworkState ? (jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsx(Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.not_supported_network.title', children: t('dyn_collect_user_data.not_supported_network.title') }), jsx(Typography, { variant: 'body_normal', weight: 'regular', color: 'secondary', copykey: 'dyn_collect_user_data.not_supported_network.description', children: t('dyn_collect_user_data.not_supported_network.description') })] })) : (jsxs("div", { className: 'collect-user-data__welcome-container', children: [jsx(Typography, { variant: 'title', color: 'primary', className: 'collect-user-data__welcome-title', copykey: 'dyn_collect_user_data.greeting', children: (projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.general.collectUserDataWelcomeHeader) ||
115
116
  t('dyn_collect_user_data.greeting', { appName }) }), jsx(Typography, { variant: 'body_normal', weight: 'regular', color: 'secondary', copykey: 'dyn_collect_user_data.description', children: (projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.general.collectUserDataWelcomeMessage) ||
116
117
  t('dyn_collect_user_data.description') })] })) }), jsx(TextButton, { className: 'collect-user-data__log-out', onClick: handleLogOut, copykey: 'dyn_collect_user_data.log_out_button', children: t('dyn_collect_user_data.log_out_button') })] })] }));
117
118
  };
@@ -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;