diff --git a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js index 5f70f739948..3f8c7089b8f 100644 --- a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js +++ b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.js @@ -447,6 +447,7 @@ export class NetworkSettings extends PureComponent { blockExplorerUrls: [], selectedRpcEndpointIndex: 0, blockExplorerUrl: undefined, + blockExplorerUrlForm: undefined, nickname: undefined, chainId: undefined, ticker: undefined, @@ -1288,10 +1289,21 @@ export class NetworkSettings extends PureComponent { }; onBlockExplorerItemAdd = async (url) => { + // If URL is empty or undefined, return early if (!url) { return; } + // Check if the URL already exists in blockExplorerUrls + const { blockExplorerUrls } = this.state; + const urlExists = blockExplorerUrls.includes(url); + + if (urlExists) { + // If the URL already exists, return early + return; + } + + // If the URL doesn't exist, proceed with adding it await this.setState((prevState) => ({ blockExplorerUrls: [...prevState.blockExplorerUrls, url], })); @@ -1351,6 +1363,7 @@ export class NetworkSettings extends PureComponent { onBlockExplorerUrlChange = async (url) => { const { addMode } = this.state; await this.setState({ + blockExplorerUrlForm: url, blockExplorerUrl: url, }); @@ -1486,7 +1499,10 @@ export class NetworkSettings extends PureComponent { }; closeAddBlockExplorerRpcForm = () => { - this.setState({ showAddBlockExplorerForm: { isVisible: false } }); + this.setState({ + showAddBlockExplorerForm: { isVisible: false }, + blockExplorerUrlForm: undefined, + }); }; closeRpcModal = () => { @@ -1603,6 +1619,7 @@ export class NetworkSettings extends PureComponent { rpcUrlForm, rpcNameForm, rpcName, + blockExplorerUrlForm, } = this.state; const { route, networkConfigurations } = this.props; const isCustomMainnet = route.params?.isCustomMainnet; @@ -2204,6 +2221,7 @@ export class NetworkSettings extends PureComponent { ref={this.inputBlockExplorerURL} style={inputStyle} autoCapitalize={'none'} + value={blockExplorerUrlForm} autoCorrect={false} onChangeText={this.onBlockExplorerUrlChange} placeholder={strings( @@ -2214,23 +2232,30 @@ export class NetworkSettings extends PureComponent { onSubmitEditing={this.toggleNetworkDetailsModal} keyboardAppearance={themeAppearance} /> - {blockExplorerUrl && !isUrl(blockExplorerUrl) && ( - - - {strings('app_settings.invalid_block_explorer_url')} - - - )} + {blockExplorerUrl && + (!isUrl(blockExplorerUrl) || + blockExplorerUrls.includes(blockExplorerUrlForm)) && ( + + + {strings('app_settings.invalid_block_explorer_url')} + + + )} + { - this.onBlockExplorerItemAdd(blockExplorerUrl); + this.onBlockExplorerItemAdd(blockExplorerUrlForm); }} width={ButtonWidthTypes.Full} labelTextVariant={TextVariant.DisplayMD} - isDisabled={!blockExplorerUrl || !isUrl(blockExplorerUrl)} + isDisabled={ + !blockExplorerUrl || + !blockExplorerUrlForm || + !isUrl(blockExplorerUrl) + } /> diff --git a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.test.tsx b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.test.tsx index 1ecffde7034..c9f2e148817 100644 --- a/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.test.tsx +++ b/app/components/Views/Settings/NetworksSettings/NetworkSettings/index.test.tsx @@ -781,6 +781,47 @@ describe('NetworkSettings', () => { ); }); + it('should not add an empty Block Explorer URL and should return early', async () => { + const instance = wrapper.instance(); + + // Initially, blockExplorerUrls should be empty + expect(wrapper.state('blockExplorerUrls').length).toBe(0); + + // Open Block Explorer form modal and attempt to add an empty URL + instance.openAddBlockExplorerForm(); + await instance.onBlockExplorerItemAdd(''); + + // Ensure the state is not updated with the empty URL + expect(wrapper.state('blockExplorerUrls').length).toBe(0); + expect(wrapper.state('blockExplorerUrl')).toBeUndefined(); + }); + + it('should not add an existing Block Explorer URL and should return early', async () => { + const instance = wrapper.instance(); + + // Set initial state with an existing block explorer URL + await instance.setState({ + blockExplorerUrls: ['https://existing-blockexplorer.com'], + }); + + // Ensure the initial state contains the existing URL + expect(wrapper.state('blockExplorerUrls').length).toBe(1); + expect(wrapper.state('blockExplorerUrls')[0]).toBe( + 'https://existing-blockexplorer.com', + ); + + // Attempt to add the same URL again + await instance.onBlockExplorerItemAdd( + 'https://existing-blockexplorer.com', + ); + + // Ensure the state remains unchanged and no duplicate is added + expect(wrapper.state('blockExplorerUrls').length).toBe(1); + expect(wrapper.state('blockExplorerUrls')[0]).toBe( + 'https://existing-blockexplorer.com', + ); + }); + it('should call validateRpcAndChainId when chainId and rpcUrl are set', async () => { const instance = wrapper.instance(); const validateRpcAndChainIdSpy = jest.spyOn(