diff --git a/src/components/settings-modal/crypto-address-setting/__tests__/crypto-address-setting.test.tsx b/src/components/settings-modal/crypto-address-setting/__tests__/crypto-address-setting.test.tsx index a668ec96..10f74183 100644 --- a/src/components/settings-modal/crypto-address-setting/__tests__/crypto-address-setting.test.tsx +++ b/src/components/settings-modal/crypto-address-setting/__tests__/crypto-address-setting.test.tsx @@ -28,7 +28,7 @@ vi.mock('react-i18next', () => ({ crypto_address_not_yours: 'Crypto address is not yours.', crypto_address_verification: 'if the crypto address is resolved p2p', crypto_address_yours: 'Crypto address belongs to this account.', - enter_crypto_address: 'Enter crypto address.', + enter_crypto_address: 'Please enter a valid crypto address.', loading: 'loading', save: 'save', saved: 'saved', @@ -152,6 +152,34 @@ describe('CryptoAddressSetting', () => { expect(getInput().value).toBe('resolved-alias.eth'); }); + it('shows a transient validation message when check is clicked with an empty field', async () => { + hookMocks.useAccount.mockReturnValue({ + author: { + address: '12D3KooWSignerPublicKey', + shortAddress: '12D3KooWSignerPublicKey', + }, + signer: { + address: SIGNER_ADDRESS, + }, + }); + + await render(); + + await act(async () => { + getButtonByText('check').click(); + }); + + expect(container.textContent).toContain('Please enter a valid crypto address.'); + expect(alertSpy).not.toHaveBeenCalled(); + + await act(async () => { + vi.advanceTimersByTime(2000); + }); + + expect(container.textContent).toContain('if the crypto address is resolved p2p'); + expect(container.textContent).not.toContain('Please enter a valid crypto address.'); + }); + it('updates the displayed status after async resolution completes', async () => { await render(); diff --git a/src/components/settings-modal/crypto-address-setting/crypto-address-setting.tsx b/src/components/settings-modal/crypto-address-setting/crypto-address-setting.tsx index 72ca40f1..f6a03682 100644 --- a/src/components/settings-modal/crypto-address-setting/crypto-address-setting.tsx +++ b/src/components/settings-modal/crypto-address-setting/crypto-address-setting.tsx @@ -85,12 +85,22 @@ const showSavedIndicator = (setSavedCryptoAddress: (value: boolean) => void) => }, 2000); }; +type ResolutionStatus = ReturnType; + +const showTransientResolutionStatus = (setTransientResolutionStatus: (value: ResolutionStatus | undefined) => void, status: ResolutionStatus) => { + setTransientResolutionStatus(status); + setTimeout(() => { + setTransientResolutionStatus(undefined); + }, 2000); +}; + const CryptoAddressSettingContent = ({ account }: { account: ReturnType }) => { const { t } = useTranslation(); const [cryptoAddress, setCryptoAddress] = useState(() => getInitialCryptoAddress(account?.author?.address)); const [checkedAddress, setCheckedAddress] = useState(); const [savedCryptoAddress, setSavedCryptoAddress] = useState(false); const [showCryptoAddressInfo, setShowCryptoAddressInfo] = useState(false); + const [transientResolutionStatus, setTransientResolutionStatus] = useState(); const signerAddress = account?.signer?.address; const authorToResolve = checkedAddress ? { ...account?.author, address: checkedAddress } : undefined; @@ -108,7 +118,10 @@ const CryptoAddressSettingContent = ({ account }: { account: ReturnType { const addressToCheck = cryptoAddress.trim(); if (!addressToCheck || !addressToCheck.includes('.')) { - alert(t('enter_crypto_address')); + showTransientResolutionStatus(setTransientResolutionStatus, { + resolveClass: styles.red, + resolveString: t('enter_crypto_address'), + }); return; } @@ -169,6 +182,7 @@ const CryptoAddressSettingContent = ({ account }: { account: ReturnType { setCheckedAddress(undefined); + setTransientResolutionStatus(undefined); setCryptoAddress(e.target.value); }} /> @@ -201,7 +215,7 @@ const CryptoAddressSettingContent = ({ account }: { account: ReturnType {t('check')} {' '} - {resolutionStatus.resolveString} + {(transientResolutionStatus ?? resolutionStatus).resolveString} );