@dynamic-labs/sdk-react-core 0.18.0-RC.26 → 0.18.0-RC.27

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 (34) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/package.cjs +1 -1
  3. package/package.js +1 -1
  4. package/package.json +8 -8
  5. package/src/lib/components/NetworkPicker/NetworkPicker.cjs +1 -1
  6. package/src/lib/components/NetworkPicker/NetworkPicker.js +1 -1
  7. package/src/lib/components/UserAddress/UserAddress.cjs +1 -1
  8. package/src/lib/components/UserAddress/UserAddress.js +1 -1
  9. package/src/lib/utils/hooks/useConnectedAccountWallet/useConnectedAccountWallet.cjs +12 -15
  10. package/src/lib/utils/hooks/useConnectedAccountWallet/useConnectedAccountWallet.d.ts +1 -1
  11. package/src/lib/utils/hooks/useConnectedAccountWallet/useConnectedAccountWallet.js +12 -15
  12. package/src/lib/utils/hooks/usePromise/usePromise.cjs +70 -63
  13. package/src/lib/utils/hooks/usePromise/usePromise.d.ts +27 -14
  14. package/src/lib/utils/hooks/usePromise/usePromise.js +71 -64
  15. package/src/lib/utils/hooks/usePromise/usePromise.types.d.ts +9 -0
  16. package/src/lib/utils/hooks/usePromise/utils/createReducer/createReducer.cjs +18 -0
  17. package/src/lib/utils/hooks/usePromise/utils/createReducer/createReducer.d.ts +13 -0
  18. package/src/lib/utils/hooks/usePromise/utils/createReducer/createReducer.js +14 -0
  19. package/src/lib/utils/hooks/usePromise/utils/createReducer/index.d.ts +1 -0
  20. package/src/lib/utils/hooks/usePromise/utils/index.d.ts +2 -0
  21. package/src/lib/utils/hooks/usePromise/utils/resolveFetcher/index.d.ts +1 -0
  22. package/src/lib/utils/hooks/usePromise/utils/resolveFetcher/resolveFetcher.cjs +32 -0
  23. package/src/lib/utils/hooks/usePromise/utils/resolveFetcher/resolveFetcher.d.ts +5 -0
  24. package/src/lib/utils/hooks/usePromise/utils/resolveFetcher/resolveFetcher.js +28 -0
  25. package/src/lib/views/NetworkNotSupported/NetworkNotSupported.cjs +1 -1
  26. package/src/lib/views/NetworkNotSupported/NetworkNotSupported.js +1 -1
  27. package/src/lib/views/NetworkNotSupportedSwitchManual/NetworkNotSupportedSwitchManual.cjs +3 -1
  28. package/src/lib/views/NetworkNotSupportedSwitchManual/NetworkNotSupportedSwitchManual.js +3 -1
  29. package/src/lib/views/SendBalanceView/SendBalanceView.cjs +2 -2
  30. package/src/lib/views/SendBalanceView/SendBalanceView.js +2 -2
  31. package/src/lib/views/TransactionConfirmationView/hooks/useTransactionData/useTransactionData.cjs +1 -1
  32. package/src/lib/views/TransactionConfirmationView/hooks/useTransactionData/useTransactionData.js +1 -1
  33. package/src/lib/widgets/DynamicWidget/prompts/PendingAccountSwitchModal/PendingAccountSwitchModal.cjs +1 -1
  34. package/src/lib/widgets/DynamicWidget/prompts/PendingAccountSwitchModal/PendingAccountSwitchModal.js +1 -1
package/CHANGELOG.md CHANGED
@@ -1,4 +1,10 @@
1
1
 
2
+ ## [0.18.0-RC.27](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.0-RC.26...v0.18.0-RC.27) (2023-08-03)
3
+
4
+ ### Bug Fixes
5
+
6
+ * fixes circular dependency issues on usePromise
7
+
2
8
  ## [0.18.0-RC.26](https://github.com/dynamic-labs/DynamicAuth/compare/v0.18.0-RC.24...v0.18.0-RC.26) (2023-08-02)
3
9
 
4
10
 
package/package.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var version = "0.18.0-RC.26";
5
+ var version = "0.18.0-RC.27";
6
6
  var dependencies = {
7
7
  "react-focus-lock": "2.9.2",
8
8
  "@dynamic-labs/iconic": "0.1.23",
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
- var version = "0.18.0-RC.26";
1
+ var version = "0.18.0-RC.27";
2
2
  var dependencies = {
3
3
  "react-focus-lock": "2.9.2",
4
4
  "@dynamic-labs/iconic": "0.1.23",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/sdk-react-core",
3
- "version": "0.18.0-RC.26",
3
+ "version": "0.18.0-RC.27",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/dynamic-labs/DynamicAuth.git",
@@ -16,13 +16,13 @@
16
16
  "formik": "2.2.9",
17
17
  "qrcode": "1.5.1",
18
18
  "ethers": "5.7.2",
19
- "@dynamic-labs/logger": "0.18.0-RC.26",
20
- "@dynamic-labs/multi-wallet": "0.18.0-RC.26",
21
- "@dynamic-labs/rpc-providers": "0.18.0-RC.26",
22
- "@dynamic-labs/types": "0.18.0-RC.26",
23
- "@dynamic-labs/utils": "0.18.0-RC.26",
24
- "@dynamic-labs/wallet-book": "0.18.0-RC.26",
25
- "@dynamic-labs/wallet-connector-core": "0.18.0-RC.26"
19
+ "@dynamic-labs/logger": "0.18.0-RC.27",
20
+ "@dynamic-labs/multi-wallet": "0.18.0-RC.27",
21
+ "@dynamic-labs/rpc-providers": "0.18.0-RC.27",
22
+ "@dynamic-labs/types": "0.18.0-RC.27",
23
+ "@dynamic-labs/utils": "0.18.0-RC.27",
24
+ "@dynamic-labs/wallet-book": "0.18.0-RC.27",
25
+ "@dynamic-labs/wallet-connector-core": "0.18.0-RC.27"
26
26
  },
27
27
  "devDependencies": {
28
28
  "semver": "7.3.8"
@@ -53,7 +53,7 @@ const NetworkPicker = ({ activeClassName = '', buttonClassName = '', checkboxCla
53
53
  const pickerRef = React.useRef(null);
54
54
  const [newNetworkId, setNewNetworkId] = React.useState(undefined);
55
55
  const { loadingNetwork, network, setNetwork } = useInternalDynamicContext.useInternalDynamicContext();
56
- const { data: supportedWalletNetworks } = usePromise.usePromise(() => connector === null || connector === void 0 ? void 0 : connector.getSupportedNetworks(), [network]);
56
+ const { data: supportedWalletNetworks } = usePromise.usePromise(() => connector === null || connector === void 0 ? void 0 : connector.getSupportedNetworks(), { deps: [network] });
57
57
  const shouldAllowOpenDropdown = isNetworkUnsupported.isNetworkUnsupported(network, evmNetworks) || (evmNetworks === null || evmNetworks === void 0 ? void 0 : evmNetworks.length) > 1;
58
58
  // Ref to anchor popper to
59
59
  const anchorRef = React.useRef(null);
@@ -49,7 +49,7 @@ const NetworkPicker = ({ activeClassName = '', buttonClassName = '', checkboxCla
49
49
  const pickerRef = useRef(null);
50
50
  const [newNetworkId, setNewNetworkId] = useState(undefined);
51
51
  const { loadingNetwork, network, setNetwork } = useInternalDynamicContext();
52
- const { data: supportedWalletNetworks } = usePromise(() => connector === null || connector === void 0 ? void 0 : connector.getSupportedNetworks(), [network]);
52
+ const { data: supportedWalletNetworks } = usePromise(() => connector === null || connector === void 0 ? void 0 : connector.getSupportedNetworks(), { deps: [network] });
53
53
  const shouldAllowOpenDropdown = isNetworkUnsupported(network, evmNetworks) || (evmNetworks === null || evmNetworks === void 0 ? void 0 : evmNetworks.length) > 1;
54
54
  // Ref to anchor popper to
55
55
  const anchorRef = useRef(null);
@@ -51,7 +51,7 @@ const UserAddress = ({ userProfile, walletConnector }) => {
51
51
  var _a;
52
52
  const walletAddress = (_a = userProfile === null || userProfile === void 0 ? void 0 : userProfile.verifiedCredentials.find((verifiedCredential) => verifiedCredential.id === userProfile.lastVerifiedCredentialId)) === null || _a === void 0 ? void 0 : _a.address;
53
53
  const nameService = useFetchNameService.useFetchNameService(walletAddress);
54
- const { data: walletConnectorAddress } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.fetchPublicAddress(), [], {
54
+ const { data: walletConnectorAddress } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.fetchPublicAddress(), {
55
55
  enabled: !userProfile && Boolean(walletConnector),
56
56
  });
57
57
  return (jsxRuntime.jsxs("div", Object.assign({ className: 'user-address__container' }, { children: [jsxRuntime.jsx(StatusDot.StatusDot, { variant: 'green', containerClassName: 'user-address__status-dot' }), (nameService === null || nameService === void 0 ? void 0 : nameService.name) ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Typography.Typography, Object.assign({ variant: 'numbers_big', color: 'primary', className: 'user-address' }, { children: nameService.name })), jsxRuntime.jsx("div", { className: 'dynamic-widget-wallet-header__seperator' }), jsxRuntime.jsx(Typography.Typography, Object.assign({ variant: 'numbers_medium', color: 'secondary', className: 'user-address' }, { children: shortenWalletAddress.shortenWalletAddress(walletAddress, 3, 3) }))] })) : (jsxRuntime.jsx(Typography.Typography, Object.assign({ variant: 'numbers_big', color: 'primary', className: 'user-address' }, { children: shortenWalletAddress.shortenWalletAddress(walletAddress || walletConnectorAddress, 4, 4) })))] })));
@@ -47,7 +47,7 @@ const UserAddress = ({ userProfile, walletConnector }) => {
47
47
  var _a;
48
48
  const walletAddress = (_a = userProfile === null || userProfile === void 0 ? void 0 : userProfile.verifiedCredentials.find((verifiedCredential) => verifiedCredential.id === userProfile.lastVerifiedCredentialId)) === null || _a === void 0 ? void 0 : _a.address;
49
49
  const nameService = useFetchNameService(walletAddress);
50
- const { data: walletConnectorAddress } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.fetchPublicAddress(), [], {
50
+ const { data: walletConnectorAddress } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.fetchPublicAddress(), {
51
51
  enabled: !userProfile && Boolean(walletConnector),
52
52
  });
53
53
  return (jsxs("div", Object.assign({ className: 'user-address__container' }, { children: [jsx(StatusDot, { variant: 'green', containerClassName: 'user-address__status-dot' }), (nameService === null || nameService === void 0 ? void 0 : nameService.name) ? (jsxs(Fragment, { children: [jsx(Typography, Object.assign({ variant: 'numbers_big', color: 'primary', className: 'user-address' }, { children: nameService.name })), jsx("div", { className: 'dynamic-widget-wallet-header__seperator' }), jsx(Typography, Object.assign({ variant: 'numbers_medium', color: 'secondary', className: 'user-address' }, { children: shortenWalletAddress(walletAddress, 3, 3) }))] })) : (jsx(Typography, Object.assign({ variant: 'numbers_big', color: 'primary', className: 'user-address' }, { children: shortenWalletAddress(walletAddress || walletConnectorAddress, 4, 4) })))] })));
@@ -4,20 +4,17 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var usePromise = require('../usePromise/usePromise.cjs');
6
6
 
7
- const useConnectedAccountWallet = (connector, secondaryWallets) => {
8
- const { data: wallet } = usePromise.usePromise(() => {
9
- if (!connector) {
10
- return;
11
- }
12
- return connector
13
- .getConnectedAccounts()
14
- .then((connectedAccounts) => secondaryWallets.find((secondaryWallet) => {
15
- var _a;
16
- return secondaryWallet.address.toLowerCase() ===
17
- ((_a = connectedAccounts[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase());
18
- }));
19
- }, [connector, secondaryWallets]);
20
- return wallet;
21
- };
7
+ const useConnectedAccountWallet = (connector, secondaryWallets) => usePromise.usePromise(() => {
8
+ if (!connector) {
9
+ return;
10
+ }
11
+ return connector
12
+ .getConnectedAccounts()
13
+ .then((connectedAccounts) => secondaryWallets.find((secondaryWallet) => {
14
+ var _a;
15
+ return secondaryWallet.address.toLowerCase() ===
16
+ ((_a = connectedAccounts[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase());
17
+ }));
18
+ }, { deps: [connector, secondaryWallets] });
22
19
 
23
20
  exports.useConnectedAccountWallet = useConnectedAccountWallet;
@@ -1,2 +1,2 @@
1
1
  import { Wallet, WalletConnector } from '../../../..';
2
- export declare const useConnectedAccountWallet: (connector: WalletConnector | undefined, secondaryWallets: Wallet[]) => Wallet | undefined;
2
+ export declare const useConnectedAccountWallet: (connector: WalletConnector | undefined, secondaryWallets: Wallet[]) => import("../usePromise").PromiseState<Wallet | undefined, Error>;
@@ -1,19 +1,16 @@
1
1
  import { usePromise } from '../usePromise/usePromise.js';
2
2
 
3
- const useConnectedAccountWallet = (connector, secondaryWallets) => {
4
- const { data: wallet } = usePromise(() => {
5
- if (!connector) {
6
- return;
7
- }
8
- return connector
9
- .getConnectedAccounts()
10
- .then((connectedAccounts) => secondaryWallets.find((secondaryWallet) => {
11
- var _a;
12
- return secondaryWallet.address.toLowerCase() ===
13
- ((_a = connectedAccounts[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase());
14
- }));
15
- }, [connector, secondaryWallets]);
16
- return wallet;
17
- };
3
+ const useConnectedAccountWallet = (connector, secondaryWallets) => usePromise(() => {
4
+ if (!connector) {
5
+ return;
6
+ }
7
+ return connector
8
+ .getConnectedAccounts()
9
+ .then((connectedAccounts) => secondaryWallets.find((secondaryWallet) => {
10
+ var _a;
11
+ return secondaryWallet.address.toLowerCase() ===
12
+ ((_a = connectedAccounts[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase());
13
+ }));
14
+ }, { deps: [connector, secondaryWallets] });
18
15
 
19
16
  export { useConnectedAccountWallet };
@@ -2,7 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var _tslib = require('../../../../../_virtual/_tslib.cjs');
6
5
  var React = require('react');
7
6
  require('@dynamic-labs/sdk-api');
8
7
  var logger = require('../../../shared/logger.cjs');
@@ -16,85 +15,93 @@ require('../../constants/colors.cjs');
16
15
  require('../../../shared/utils/classes/storage/localStorage.cjs');
17
16
  require('ethers');
18
17
  require('../../../shared/consts/index.cjs');
18
+ var resolveFetcher = require('./utils/resolveFetcher/resolveFetcher.cjs');
19
+ var createReducer = require('./utils/createReducer/createReducer.cjs');
19
20
 
20
21
  /**
21
- * usePromise hook
22
+ * Custom hook for handling promises and fetching data.
23
+ * @template T - The type of the data returned by the promise.
24
+ * @template E - The type of the error thrown by the promise.
25
+ * @param {() => T | Promise<T>} fetcher - A function that returns the data or a promise that resolves to the data.
26
+ * @param {UsePromiseOptions<T, E>} [options={}] - Options for the hook.
27
+ * @param {number} [options.retries] - The number of times to retry the fetch in case of failure.
28
+ * @param {T} [options.initialData] - The initial data the hook will use until the promise is resolved.
29
+ * @param {DependencyList} [options.deps=[]] - An array of dependencies for the hook.
30
+ * @param {boolean} [options.enabled] - Flag indicating whether the fetch should be enabled or not.
31
+ * @param {(data: T) => void} [options.onResolve] - Callback to be called when the fetch is resolved successfully.
32
+ * @param {(error: E) => void} [options.onReject] - Callback to be called when the fetch is rejected with an error.
33
+ * @returns {PromiseState<T, E>} - The state object containing the data, error, and loading status.
34
+ * @example
35
+ * // Example usage with a simple fetcher function
36
+ * const fetcher = fetch('https://api.example.com/data');
22
37
  *
23
- * A React hook to handle promises and fetching data, providing the ability to track loading, data, and error state.
38
+ * const MyComponent = () => {
39
+ * const { data, isLoading, error } = usePromise(fetcher);
24
40
  *
25
- * @template T The type of data returned from the fetcher function.
26
- * @template E The type of error returned from the fetcher function.
41
+ * if (isLoading) {
42
+ * return <div>Loading...</div>;
43
+ * }
27
44
  *
28
- * @param {() => T | Promise<T>} fetcher - A function that returns a value or a promise.
29
- * @param {DependencyList} [deps = []] - Dependency list for the hook to react to changes and refetch.
30
- * @param {UsePromiseOptions} [options = { enabled: true }] - Options to configure the hook's behavior.
45
+ * if (error) {
46
+ * return <div>Error: {error.message}</div>;
47
+ * }
31
48
  *
32
- * @returns {PromiseState<T, E>} - Object containing the hook state, including data, error, and loading status.
49
+ * return <div>Data: {data}</div>;
50
+ * };
33
51
  */
34
- const usePromise = (fetcher, deps = [], options = {
35
- enabled: true,
36
- }) => {
37
- // Convert the dependency list to a string representation for comparison (useful for useEffect dependencies)
38
- const key = JSON.stringify(deps);
39
- const [state, setState] = React.useState({
52
+ const usePromise = (fetcher, options) => {
53
+ const lastCallTimestamp = React.useRef(new Date().getTime());
54
+ const { deps = [], initialData = undefined, enabled = true, retries = 0, onReject = () => { }, onResolve = () => { }, } = options || {};
55
+ const [state, dispatch] = React.useReducer(createReducer.createReducer(), {
56
+ data: initialData,
40
57
  isLoading: true,
41
58
  });
42
- /**
43
- * Fetch data from the fetcher function.
44
- * @param {Function} onData - Callback function to handle successful data retrieval.
45
- * @param {Function} onError - Callback function to handle errors during data retrieval.
46
- */
47
- const fetch = ({ onData, onError, }) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
48
- try {
49
- let data;
50
- const fetchData = fetcher();
51
- if (fetchData instanceof Promise) {
52
- data = yield fetchData;
53
- }
54
- else {
55
- data = fetchData;
56
- }
57
- onData(data);
58
- }
59
- catch (error) {
60
- logger.logger.error(error);
61
- onError(error);
59
+ const callback = React.useCallback(() => {
60
+ const callTimestamp = new Date().getTime();
61
+ const diffFromLastCall = callTimestamp - lastCallTimestamp.current;
62
+ if (diffFromLastCall < 5) {
63
+ logger.logger.warn('usePromise: Fetcher function was called too soon. Please make sure you are not calling the fetcher function inside a loop or a synchronous function.', deps);
62
64
  }
63
- });
64
- React.useEffect(() => {
65
- if (!options.enabled)
66
- return;
67
- // Flag to track if the another fetch has been triggered before the current one has completed
68
- let isInvalid = false;
65
+ lastCallTimestamp.current = callTimestamp;
69
66
  if (!state.isLoading) {
70
- setState({
71
- isLoading: true,
67
+ dispatch({
68
+ payload: true,
69
+ type: 'SET_LOADING',
72
70
  });
73
71
  }
74
- fetch({
75
- onData: (data) => {
76
- if (isInvalid)
77
- return;
78
- setState({
79
- data,
80
- isLoading: false,
72
+ resolveFetcher.resolveFetcher(fetcher, { retries }, (error, data) => {
73
+ if (callTimestamp !== lastCallTimestamp.current)
74
+ return;
75
+ if (error) {
76
+ logger.logger.error(error);
77
+ dispatch({
78
+ payload: error,
79
+ type: 'SET_ERROR',
81
80
  });
82
- },
83
- onError: (error) => {
84
- if (isInvalid)
85
- return;
86
- setState({
87
- error,
88
- isLoading: false,
81
+ onReject === null || onReject === void 0 ? void 0 : onReject(error);
82
+ return;
83
+ }
84
+ if (data) {
85
+ dispatch({
86
+ payload: data,
87
+ type: 'SET_DATA',
89
88
  });
90
- },
89
+ onResolve === null || onResolve === void 0 ? void 0 : onResolve(data);
90
+ return;
91
+ }
92
+ dispatch({
93
+ payload: false,
94
+ type: 'SET_LOADING',
95
+ });
91
96
  });
92
- return () => {
93
- isInvalid = true;
94
- };
95
97
  // eslint-disable-next-line react-hooks/exhaustive-deps
96
- }, [key, options.enabled]);
97
- return Object.assign(Object.assign({}, state), { isLoading: state.isLoading });
98
+ }, deps);
99
+ React.useEffect(() => {
100
+ if (enabled) {
101
+ callback();
102
+ }
103
+ }, [callback, enabled]);
104
+ return state;
98
105
  };
99
106
 
100
107
  exports.usePromise = usePromise;
@@ -1,20 +1,33 @@
1
- import { DependencyList } from 'react';
2
- import { PromiseState } from './usePromise.types';
3
- export type UsePromiseOptions = {
4
- enabled?: boolean;
5
- };
1
+ import { UsePromiseOptions, PromiseState } from './usePromise.types';
6
2
  /**
7
- * usePromise hook
3
+ * Custom hook for handling promises and fetching data.
4
+ * @template T - The type of the data returned by the promise.
5
+ * @template E - The type of the error thrown by the promise.
6
+ * @param {() => T | Promise<T>} fetcher - A function that returns the data or a promise that resolves to the data.
7
+ * @param {UsePromiseOptions<T, E>} [options={}] - Options for the hook.
8
+ * @param {number} [options.retries] - The number of times to retry the fetch in case of failure.
9
+ * @param {T} [options.initialData] - The initial data the hook will use until the promise is resolved.
10
+ * @param {DependencyList} [options.deps=[]] - An array of dependencies for the hook.
11
+ * @param {boolean} [options.enabled] - Flag indicating whether the fetch should be enabled or not.
12
+ * @param {(data: T) => void} [options.onResolve] - Callback to be called when the fetch is resolved successfully.
13
+ * @param {(error: E) => void} [options.onReject] - Callback to be called when the fetch is rejected with an error.
14
+ * @returns {PromiseState<T, E>} - The state object containing the data, error, and loading status.
15
+ * @example
16
+ * // Example usage with a simple fetcher function
17
+ * const fetcher = fetch('https://api.example.com/data');
8
18
  *
9
- * A React hook to handle promises and fetching data, providing the ability to track loading, data, and error state.
19
+ * const MyComponent = () => {
20
+ * const { data, isLoading, error } = usePromise(fetcher);
10
21
  *
11
- * @template T The type of data returned from the fetcher function.
12
- * @template E The type of error returned from the fetcher function.
22
+ * if (isLoading) {
23
+ * return <div>Loading...</div>;
24
+ * }
13
25
  *
14
- * @param {() => T | Promise<T>} fetcher - A function that returns a value or a promise.
15
- * @param {DependencyList} [deps = []] - Dependency list for the hook to react to changes and refetch.
16
- * @param {UsePromiseOptions} [options = { enabled: true }] - Options to configure the hook's behavior.
26
+ * if (error) {
27
+ * return <div>Error: {error.message}</div>;
28
+ * }
17
29
  *
18
- * @returns {PromiseState<T, E>} - Object containing the hook state, including data, error, and loading status.
30
+ * return <div>Data: {data}</div>;
31
+ * };
19
32
  */
20
- export declare const usePromise: <T = unknown, E = unknown>(fetcher: () => T | Promise<T>, deps?: DependencyList, options?: UsePromiseOptions) => PromiseState<T, E>;
33
+ export declare const usePromise: <T, E = Error>(fetcher: () => T | Promise<T>, options?: UsePromiseOptions<T, E> | undefined) => PromiseState<T, E>;
@@ -1,5 +1,4 @@
1
- import { __awaiter } from '../../../../../_virtual/_tslib.js';
2
- import { useState, useEffect } from 'react';
1
+ import { useRef, useReducer, useCallback, useEffect } from 'react';
3
2
  import '@dynamic-labs/sdk-api';
4
3
  import { logger } from '../../../shared/logger.js';
5
4
  import '@dynamic-labs/iconic';
@@ -12,85 +11,93 @@ import '../../constants/colors.js';
12
11
  import '../../../shared/utils/classes/storage/localStorage.js';
13
12
  import 'ethers';
14
13
  import '../../../shared/consts/index.js';
14
+ import { resolveFetcher } from './utils/resolveFetcher/resolveFetcher.js';
15
+ import { createReducer } from './utils/createReducer/createReducer.js';
15
16
 
16
17
  /**
17
- * usePromise hook
18
+ * Custom hook for handling promises and fetching data.
19
+ * @template T - The type of the data returned by the promise.
20
+ * @template E - The type of the error thrown by the promise.
21
+ * @param {() => T | Promise<T>} fetcher - A function that returns the data or a promise that resolves to the data.
22
+ * @param {UsePromiseOptions<T, E>} [options={}] - Options for the hook.
23
+ * @param {number} [options.retries] - The number of times to retry the fetch in case of failure.
24
+ * @param {T} [options.initialData] - The initial data the hook will use until the promise is resolved.
25
+ * @param {DependencyList} [options.deps=[]] - An array of dependencies for the hook.
26
+ * @param {boolean} [options.enabled] - Flag indicating whether the fetch should be enabled or not.
27
+ * @param {(data: T) => void} [options.onResolve] - Callback to be called when the fetch is resolved successfully.
28
+ * @param {(error: E) => void} [options.onReject] - Callback to be called when the fetch is rejected with an error.
29
+ * @returns {PromiseState<T, E>} - The state object containing the data, error, and loading status.
30
+ * @example
31
+ * // Example usage with a simple fetcher function
32
+ * const fetcher = fetch('https://api.example.com/data');
18
33
  *
19
- * A React hook to handle promises and fetching data, providing the ability to track loading, data, and error state.
34
+ * const MyComponent = () => {
35
+ * const { data, isLoading, error } = usePromise(fetcher);
20
36
  *
21
- * @template T The type of data returned from the fetcher function.
22
- * @template E The type of error returned from the fetcher function.
37
+ * if (isLoading) {
38
+ * return <div>Loading...</div>;
39
+ * }
23
40
  *
24
- * @param {() => T | Promise<T>} fetcher - A function that returns a value or a promise.
25
- * @param {DependencyList} [deps = []] - Dependency list for the hook to react to changes and refetch.
26
- * @param {UsePromiseOptions} [options = { enabled: true }] - Options to configure the hook's behavior.
41
+ * if (error) {
42
+ * return <div>Error: {error.message}</div>;
43
+ * }
27
44
  *
28
- * @returns {PromiseState<T, E>} - Object containing the hook state, including data, error, and loading status.
45
+ * return <div>Data: {data}</div>;
46
+ * };
29
47
  */
30
- const usePromise = (fetcher, deps = [], options = {
31
- enabled: true,
32
- }) => {
33
- // Convert the dependency list to a string representation for comparison (useful for useEffect dependencies)
34
- const key = JSON.stringify(deps);
35
- const [state, setState] = useState({
48
+ const usePromise = (fetcher, options) => {
49
+ const lastCallTimestamp = useRef(new Date().getTime());
50
+ const { deps = [], initialData = undefined, enabled = true, retries = 0, onReject = () => { }, onResolve = () => { }, } = options || {};
51
+ const [state, dispatch] = useReducer(createReducer(), {
52
+ data: initialData,
36
53
  isLoading: true,
37
54
  });
38
- /**
39
- * Fetch data from the fetcher function.
40
- * @param {Function} onData - Callback function to handle successful data retrieval.
41
- * @param {Function} onError - Callback function to handle errors during data retrieval.
42
- */
43
- const fetch = ({ onData, onError, }) => __awaiter(void 0, void 0, void 0, function* () {
44
- try {
45
- let data;
46
- const fetchData = fetcher();
47
- if (fetchData instanceof Promise) {
48
- data = yield fetchData;
49
- }
50
- else {
51
- data = fetchData;
52
- }
53
- onData(data);
54
- }
55
- catch (error) {
56
- logger.error(error);
57
- onError(error);
55
+ const callback = useCallback(() => {
56
+ const callTimestamp = new Date().getTime();
57
+ const diffFromLastCall = callTimestamp - lastCallTimestamp.current;
58
+ if (diffFromLastCall < 5) {
59
+ logger.warn('usePromise: Fetcher function was called too soon. Please make sure you are not calling the fetcher function inside a loop or a synchronous function.', deps);
58
60
  }
59
- });
60
- useEffect(() => {
61
- if (!options.enabled)
62
- return;
63
- // Flag to track if the another fetch has been triggered before the current one has completed
64
- let isInvalid = false;
61
+ lastCallTimestamp.current = callTimestamp;
65
62
  if (!state.isLoading) {
66
- setState({
67
- isLoading: true,
63
+ dispatch({
64
+ payload: true,
65
+ type: 'SET_LOADING',
68
66
  });
69
67
  }
70
- fetch({
71
- onData: (data) => {
72
- if (isInvalid)
73
- return;
74
- setState({
75
- data,
76
- isLoading: false,
68
+ resolveFetcher(fetcher, { retries }, (error, data) => {
69
+ if (callTimestamp !== lastCallTimestamp.current)
70
+ return;
71
+ if (error) {
72
+ logger.error(error);
73
+ dispatch({
74
+ payload: error,
75
+ type: 'SET_ERROR',
77
76
  });
78
- },
79
- onError: (error) => {
80
- if (isInvalid)
81
- return;
82
- setState({
83
- error,
84
- isLoading: false,
77
+ onReject === null || onReject === void 0 ? void 0 : onReject(error);
78
+ return;
79
+ }
80
+ if (data) {
81
+ dispatch({
82
+ payload: data,
83
+ type: 'SET_DATA',
85
84
  });
86
- },
85
+ onResolve === null || onResolve === void 0 ? void 0 : onResolve(data);
86
+ return;
87
+ }
88
+ dispatch({
89
+ payload: false,
90
+ type: 'SET_LOADING',
91
+ });
87
92
  });
88
- return () => {
89
- isInvalid = true;
90
- };
91
93
  // eslint-disable-next-line react-hooks/exhaustive-deps
92
- }, [key, options.enabled]);
93
- return Object.assign(Object.assign({}, state), { isLoading: state.isLoading });
94
+ }, deps);
95
+ useEffect(() => {
96
+ if (enabled) {
97
+ callback();
98
+ }
99
+ }, [callback, enabled]);
100
+ return state;
94
101
  };
95
102
 
96
103
  export { usePromise };
@@ -1,5 +1,14 @@
1
+ import { DependencyList } from 'react';
1
2
  export type PromiseState<T, E> = {
2
3
  data?: T;
3
4
  error?: E;
4
5
  isLoading: boolean;
5
6
  };
7
+ export type UsePromiseOptions<T, E> = {
8
+ deps?: DependencyList;
9
+ retries?: number;
10
+ enabled?: boolean;
11
+ initialData?: T;
12
+ onResolve?: (data: T) => void;
13
+ onReject?: (error: E) => void;
14
+ };
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const createReducer = () => (state, action) => {
6
+ switch (action.type) {
7
+ case 'SET_DATA':
8
+ return Object.assign(Object.assign({}, state), { data: action.payload, isLoading: false });
9
+ case 'SET_ERROR':
10
+ return Object.assign(Object.assign({}, state), { error: action.payload, isLoading: false });
11
+ case 'SET_LOADING':
12
+ return Object.assign(Object.assign({}, state), { isLoading: action.payload });
13
+ default:
14
+ return state;
15
+ }
16
+ };
17
+
18
+ exports.createReducer = createReducer;
@@ -0,0 +1,13 @@
1
+ import { PromiseState } from '../../usePromise.types';
2
+ type ReducerAction<T = unknown, E = unknown> = {
3
+ type: 'SET_DATA';
4
+ payload: T;
5
+ } | {
6
+ type: 'SET_ERROR';
7
+ payload: E;
8
+ } | {
9
+ type: 'SET_LOADING';
10
+ payload: boolean;
11
+ };
12
+ export declare const createReducer: <T = unknown, E = unknown>() => (state: PromiseState<T, E>, action: ReducerAction<T, E>) => PromiseState<T, E>;
13
+ export {};
@@ -0,0 +1,14 @@
1
+ const createReducer = () => (state, action) => {
2
+ switch (action.type) {
3
+ case 'SET_DATA':
4
+ return Object.assign(Object.assign({}, state), { data: action.payload, isLoading: false });
5
+ case 'SET_ERROR':
6
+ return Object.assign(Object.assign({}, state), { error: action.payload, isLoading: false });
7
+ case 'SET_LOADING':
8
+ return Object.assign(Object.assign({}, state), { isLoading: action.payload });
9
+ default:
10
+ return state;
11
+ }
12
+ };
13
+
14
+ export { createReducer };
@@ -0,0 +1 @@
1
+ export { createReducer } from './createReducer';
@@ -0,0 +1,2 @@
1
+ export * from './resolveFetcher';
2
+ export * from './createReducer';
@@ -0,0 +1 @@
1
+ export { resolveFetcher } from './resolveFetcher';
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _tslib = require('../../../../../../../_virtual/_tslib.cjs');
6
+
7
+ const isPromise = (value) => value instanceof Promise;
8
+ const resolveFetcher = (fetcher, { retries }, callback) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
9
+ const totalNumberOfAttempts = retries ? retries + 1 : 1;
10
+ let currentAttempt = 0;
11
+ let data;
12
+ let err;
13
+ while (currentAttempt < totalNumberOfAttempts) {
14
+ currentAttempt = currentAttempt + 1;
15
+ try {
16
+ const result = fetcher();
17
+ if (isPromise(result)) {
18
+ data = yield result;
19
+ }
20
+ else {
21
+ data = result;
22
+ }
23
+ err = undefined;
24
+ }
25
+ catch (error) {
26
+ err = error;
27
+ }
28
+ }
29
+ callback(err, data);
30
+ });
31
+
32
+ exports.resolveFetcher = resolveFetcher;
@@ -0,0 +1,5 @@
1
+ type ResolveFetcherOptions = {
2
+ retries?: number;
3
+ };
4
+ export declare const resolveFetcher: <E, T>(fetcher: () => T | Promise<T>, { retries }: ResolveFetcherOptions, callback: (err: E | undefined, data: T | undefined) => void) => Promise<void>;
5
+ export {};
@@ -0,0 +1,28 @@
1
+ import { __awaiter } from '../../../../../../../_virtual/_tslib.js';
2
+
3
+ const isPromise = (value) => value instanceof Promise;
4
+ const resolveFetcher = (fetcher, { retries }, callback) => __awaiter(void 0, void 0, void 0, function* () {
5
+ const totalNumberOfAttempts = retries ? retries + 1 : 1;
6
+ let currentAttempt = 0;
7
+ let data;
8
+ let err;
9
+ while (currentAttempt < totalNumberOfAttempts) {
10
+ currentAttempt = currentAttempt + 1;
11
+ try {
12
+ const result = fetcher();
13
+ if (isPromise(result)) {
14
+ data = yield result;
15
+ }
16
+ else {
17
+ data = result;
18
+ }
19
+ err = undefined;
20
+ }
21
+ catch (error) {
22
+ err = error;
23
+ }
24
+ }
25
+ callback(err, data);
26
+ });
27
+
28
+ export { resolveFetcher };
@@ -55,7 +55,7 @@ var useApplyWalletConnectorNetwork = require('../../utils/hooks/useApplyWalletCo
55
55
  const NetworkNotSupported = () => {
56
56
  const { network, onboardingImageUrl, selectedWalletConnector: walletConnector, connectedWallets, primaryWallet, } = useInternalDynamicContext.useInternalDynamicContext();
57
57
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
58
- const { data: walletConnectorNetwork } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), [primaryWallet, walletConnector, connectedWallets]);
58
+ const { data: walletConnectorNetwork } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), { deps: [primaryWallet, walletConnector, connectedWallets] });
59
59
  const finishConnectAndSign = useConnectAndSign.useConnectAndSign();
60
60
  const [isNetworkPickerOpen, setIsNetworkPickerOpen] = React.useState(false);
61
61
  // Finishes auth flow when wallet switches to proper network
@@ -51,7 +51,7 @@ import { useApplyWalletConnectorNetwork } from '../../utils/hooks/useApplyWallet
51
51
  const NetworkNotSupported = () => {
52
52
  const { network, onboardingImageUrl, selectedWalletConnector: walletConnector, connectedWallets, primaryWallet, } = useInternalDynamicContext();
53
53
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
54
- const { data: walletConnectorNetwork } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), [primaryWallet, walletConnector, connectedWallets]);
54
+ const { data: walletConnectorNetwork } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), { deps: [primaryWallet, walletConnector, connectedWallets] });
55
55
  const finishConnectAndSign = useConnectAndSign();
56
56
  const [isNetworkPickerOpen, setIsNetworkPickerOpen] = useState(false);
57
57
  // Finishes auth flow when wallet switches to proper network
@@ -56,7 +56,9 @@ const NetworkNotSupportedSwitchManual = () => {
56
56
  var _a, _b;
57
57
  const { user, selectedWalletConnector: walletConnector, connectedWallets, } = useInternalDynamicContext.useInternalDynamicContext();
58
58
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
59
- const { data: walletConnectorNetwork } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), [walletConnector, connectedWallets]);
59
+ const { data: walletConnectorNetwork } = usePromise.usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), {
60
+ deps: [walletConnector, connectedWallets],
61
+ });
60
62
  const finishConnectAndSign = useConnectAndSign.useConnectAndSign();
61
63
  // Finishes auth flow when wallet switches to proper network
62
64
  React.useEffect(() => {
@@ -52,7 +52,9 @@ const NetworkNotSupportedSwitchManual = () => {
52
52
  var _a, _b;
53
53
  const { user, selectedWalletConnector: walletConnector, connectedWallets, } = useInternalDynamicContext();
54
54
  // Refresh selectedWalletConnector network when primaryWallet or connectedWallets updates
55
- const { data: walletConnectorNetwork } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), [walletConnector, connectedWallets]);
55
+ const { data: walletConnectorNetwork } = usePromise(() => walletConnector === null || walletConnector === void 0 ? void 0 : walletConnector.getNetwork(), {
56
+ deps: [walletConnector, connectedWallets],
57
+ });
56
58
  const finishConnectAndSign = useConnectAndSign();
57
59
  // Finishes auth flow when wallet switches to proper network
58
60
  useEffect(() => {
@@ -59,8 +59,8 @@ const SendBalanceView = ({ initialRecipientAddress = '', initialValue, onClickBa
59
59
  if (!primaryWallet) {
60
60
  throw new utils.DynamicError('Primary wallet is not available, send balance cannot be displayed');
61
61
  }
62
- const { data: balance } = usePromise.usePromise(() => primaryWallet.connector.getBalance(), [primaryWallet]);
63
- const { data: provider } = usePromise.usePromise(() => primaryWallet.connector.getWeb3Provider(), [primaryWallet]);
62
+ const { data: balance } = usePromise.usePromise(() => primaryWallet.connector.getBalance());
63
+ const { data: provider } = usePromise.usePromise(() => primaryWallet.connector.getWeb3Provider());
64
64
  const evmNetworks = ((primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector) &&
65
65
  primaryWallet.connector.evmNetworks) ||
66
66
  [];
@@ -55,8 +55,8 @@ const SendBalanceView = ({ initialRecipientAddress = '', initialValue, onClickBa
55
55
  if (!primaryWallet) {
56
56
  throw new DynamicError('Primary wallet is not available, send balance cannot be displayed');
57
57
  }
58
- const { data: balance } = usePromise(() => primaryWallet.connector.getBalance(), [primaryWallet]);
59
- const { data: provider } = usePromise(() => primaryWallet.connector.getWeb3Provider(), [primaryWallet]);
58
+ const { data: balance } = usePromise(() => primaryWallet.connector.getBalance());
59
+ const { data: provider } = usePromise(() => primaryWallet.connector.getWeb3Provider());
60
60
  const evmNetworks = ((primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector) &&
61
61
  primaryWallet.connector.evmNetworks) ||
62
62
  [];
@@ -54,7 +54,7 @@ const useTransactionData = ({ provider, transaction, }) => {
54
54
  // because alchemy checks the origin address funds and can return an error if
55
55
  // origin wallet has no funds for the transaction
56
56
  // https://docs.alchemy.com/reference/eth-estimategas
57
- const { from } = transaction, transactionWithNoOrigin = _tslib.__rest(transaction, ["from"]);
57
+ const transactionWithNoOrigin = _tslib.__rest(transaction, ["from"]);
58
58
  return provider.estimateGas(transactionWithNoOrigin);
59
59
  });
60
60
  const { data: gasPrice, isLoading: isFeeDataLoading } = usePromise.usePromise(() => provider.getGasPrice());
@@ -50,7 +50,7 @@ const useTransactionData = ({ provider, transaction, }) => {
50
50
  // because alchemy checks the origin address funds and can return an error if
51
51
  // origin wallet has no funds for the transaction
52
52
  // https://docs.alchemy.com/reference/eth-estimategas
53
- const { from } = transaction, transactionWithNoOrigin = __rest(transaction, ["from"]);
53
+ const transactionWithNoOrigin = __rest(transaction, ["from"]);
54
54
  return provider.estimateGas(transactionWithNoOrigin);
55
55
  });
56
56
  const { data: gasPrice, isLoading: isFeeDataLoading } = usePromise(() => provider.getGasPrice());
@@ -17,7 +17,7 @@ const PendingAccountSwitchModal = () => {
17
17
  const { selectedWalletWithAction, primaryWallet, secondaryWallets } = useInternalDynamicContext.useInternalDynamicContext();
18
18
  const selectedConnector = (_a = selectedWalletWithAction === null || selectedWalletWithAction === void 0 ? void 0 : selectedWalletWithAction.wallet) === null || _a === void 0 ? void 0 : _a.connector;
19
19
  const isSameWallet = (selectedConnector === null || selectedConnector === void 0 ? void 0 : selectedConnector.name) === (primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector.name);
20
- const connectedWallet = useConnectedAccountWallet.useConnectedAccountWallet((_b = selectedWalletWithAction === null || selectedWalletWithAction === void 0 ? void 0 : selectedWalletWithAction.wallet) === null || _b === void 0 ? void 0 : _b.connector, secondaryWallets);
20
+ const { data: connectedWallet } = useConnectedAccountWallet.useConnectedAccountWallet((_b = selectedWalletWithAction === null || selectedWalletWithAction === void 0 ? void 0 : selectedWalletWithAction.wallet) === null || _b === void 0 ? void 0 : _b.connector, secondaryWallets);
21
21
  React.useEffect(() => {
22
22
  //flow client library only supports one connected wallet at any given time.
23
23
  const disconnectAndConnect = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
@@ -13,7 +13,7 @@ const PendingAccountSwitchModal = () => {
13
13
  const { selectedWalletWithAction, primaryWallet, secondaryWallets } = useInternalDynamicContext();
14
14
  const selectedConnector = (_a = selectedWalletWithAction === null || selectedWalletWithAction === void 0 ? void 0 : selectedWalletWithAction.wallet) === null || _a === void 0 ? void 0 : _a.connector;
15
15
  const isSameWallet = (selectedConnector === null || selectedConnector === void 0 ? void 0 : selectedConnector.name) === (primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.connector.name);
16
- const connectedWallet = useConnectedAccountWallet((_b = selectedWalletWithAction === null || selectedWalletWithAction === void 0 ? void 0 : selectedWalletWithAction.wallet) === null || _b === void 0 ? void 0 : _b.connector, secondaryWallets);
16
+ const { data: connectedWallet } = useConnectedAccountWallet((_b = selectedWalletWithAction === null || selectedWalletWithAction === void 0 ? void 0 : selectedWalletWithAction.wallet) === null || _b === void 0 ? void 0 : _b.connector, secondaryWallets);
17
17
  useEffect(() => {
18
18
  //flow client library only supports one connected wallet at any given time.
19
19
  const disconnectAndConnect = () => __awaiter(void 0, void 0, void 0, function* () {