diff --git a/src/components/forms/validator.test.ts b/src/components/forms/validator.test.ts index 533e4c23..a8c47d66 100644 --- a/src/components/forms/validator.test.ts +++ b/src/components/forms/validator.test.ts @@ -14,6 +14,7 @@ import { addressIsNotCurrentSafe, OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR, mustBeHexData, + validAddressBookName, } from 'src/components/forms/validator' describe('Forms > Validators', () => { @@ -249,4 +250,26 @@ describe('Forms > Validators', () => { expect(differentFrom('a')('a')).toEqual(getDifferentFromErrMsg('a')) }) }) + + describe('validAddressBookName validator', () => { + it('Returns error for an empty string', () => { + expect(validAddressBookName('')).toBe('Should be 1 to 50 symbols') + }) + it('Returns error for a name longer than 50 chars', () => { + expect(validAddressBookName('abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabc')).toBe( + 'Should be 1 to 50 symbols', + ) + }) + it('Returns error for a blacklisted name', () => { + const blacklistedErrorMessage = 'Name should not include: UNKNOWN, OWNER #, MY WALLET' + + expect(validAddressBookName('unknown')).toBe(blacklistedErrorMessage) + expect(validAddressBookName('unknown a')).toBe(blacklistedErrorMessage) + expect(validAddressBookName('owner #1')).toBe(blacklistedErrorMessage) + expect(validAddressBookName('My Wallet')).toBe(blacklistedErrorMessage) + }) + it('Returns undefined for a non-blacklisted name', () => { + expect(validAddressBookName('A valid name')).toBeUndefined() + }) + }) }) diff --git a/src/components/forms/validator.ts b/src/components/forms/validator.ts index 90ac6cde..5040e352 100644 --- a/src/components/forms/validator.ts +++ b/src/components/forms/validator.ts @@ -5,6 +5,7 @@ import { getWeb3 } from 'src/logic/wallets/getWeb3' import { isFeatureEnabled } from 'src/config' import { FEATURES } from 'src/config/networks/network.d' import { isValidAddress } from 'src/utils/isValidAddress' +import { ADDRESS_BOOK_INVALID_NAMES, isValidAddressBookName } from 'src/logic/addressBook/utils' type ValidatorReturnType = string | undefined export type GenericValidatorType = (...args: unknown[]) => ValidatorReturnType @@ -134,3 +135,15 @@ export const differentFrom = (diffValue: number | string) => (value: string): Va } export const noErrorsOn = (name: string, errors: Record): boolean => errors[name] === undefined + +export const validAddressBookName = (name: string): string | undefined => { + const lengthError = minMaxLength(1, 50)(name) + + if (lengthError === undefined) { + return isValidAddressBookName(name) + ? undefined + : `Name should not include: ${ADDRESS_BOOK_INVALID_NAMES.join(', ')}` + } + + return lengthError +} diff --git a/src/logic/addressBook/store/reducer/index.ts b/src/logic/addressBook/store/reducer/index.ts index 759b8a19..5b1259d5 100644 --- a/src/logic/addressBook/store/reducer/index.ts +++ b/src/logic/addressBook/store/reducer/index.ts @@ -2,7 +2,7 @@ import { Action, handleActions } from 'redux-actions' import { AddressBookEntry, AddressBookState } from 'src/logic/addressBook/model/addressBook' import { ADDRESS_BOOK_ACTIONS } from 'src/logic/addressBook/store/actions' -import { getEntryIndex, isValidAddressBookName } from 'src/logic/addressBook/utils' +import { getEntryIndex } from 'src/logic/addressBook/utils' import { AppReduxState } from 'src/store' export const ADDRESS_BOOK_REDUCER_ID = 'addressBook' @@ -15,11 +15,6 @@ export default handleActions( const newState = [...state] const addressBookEntry = action.payload - if (!isValidAddressBookName(addressBookEntry.name)) { - // prevent adding an invalid name - return newState - } - const entryIndex = getEntryIndex(newState, addressBookEntry) // update @@ -48,20 +43,17 @@ export default handleActions( const newState = [...state] const addressBookEntries = action.payload - addressBookEntries - // exclude those entries with invalid name - .filter(({ name }) => isValidAddressBookName(name)) - .forEach((addressBookEntry) => { - const entryIndex = getEntryIndex(newState, addressBookEntry) + addressBookEntries.forEach((addressBookEntry) => { + const entryIndex = getEntryIndex(newState, addressBookEntry) - if (entryIndex >= 0) { - // update - newState[entryIndex] = addressBookEntry - } else { - // add - newState.push(addressBookEntry) - } - }) + if (entryIndex >= 0) { + // update + newState[entryIndex] = addressBookEntry + } else { + // add + newState.push(addressBookEntry) + } + }) return newState }, diff --git a/src/logic/addressBook/utils/index.ts b/src/logic/addressBook/utils/index.ts index be027db2..c08e462c 100644 --- a/src/logic/addressBook/utils/index.ts +++ b/src/logic/addressBook/utils/index.ts @@ -15,7 +15,7 @@ export type OldAddressBookType = { [safeAddress: string]: [OldAddressBookEntry] } -const ADDRESS_BOOK_INVALID_NAMES = ['UNKNOWN', 'OWNER #', 'MY WALLET', ''] +export const ADDRESS_BOOK_INVALID_NAMES = ['UNKNOWN', 'OWNER #', 'MY WALLET'] type GetNameFromAddressBookOptions = { filterOnlyValidName: boolean diff --git a/src/routes/load/components/DetailsForm/index.tsx b/src/routes/load/components/DetailsForm/index.tsx index e3b49176..4adb2dbc 100644 --- a/src/routes/load/components/DetailsForm/index.tsx +++ b/src/routes/load/components/DetailsForm/index.tsx @@ -15,7 +15,7 @@ import { noErrorsOn, required, composeValidators, - minMaxLength, + validAddressBookName, } from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Col from 'src/components/layout/Col' @@ -95,7 +95,7 @@ const DetailsForm = ({ errors, form }: DetailsFormProps): React.ReactElement => placeholder="Name of the Safe*" text="Safe name" type="text" - validate={composeValidators(required, minMaxLength(1, 50))} + validate={composeValidators(required, validAddressBookName)} testId="load-safe-name-field" /> diff --git a/src/routes/open/components/SafeNameForm/index.tsx b/src/routes/open/components/SafeNameForm/index.tsx index 67240bdf..d8a29619 100644 --- a/src/routes/open/components/SafeNameForm/index.tsx +++ b/src/routes/open/components/SafeNameForm/index.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components' import OpenPaper from 'src/components/Stepper/OpenPaper' import Field from 'src/components/forms/Field' import TextField from 'src/components/forms/TextField' -import { composeValidators, minMaxLength, required } from 'src/components/forms/validator' +import { composeValidators, required, validAddressBookName } from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Paragraph from 'src/components/layout/Paragraph' import { FIELD_NAME } from 'src/routes/open/components/fields' @@ -56,7 +56,7 @@ const SafeNameForm = ({ safeName }: { safeName: string }): React.ReactElement => placeholder="Name of the new Safe" text="Safe name" type="text" - validate={composeValidators(required, minMaxLength(1, 50))} + validate={composeValidators(required, validAddressBookName)} testId="create-safe-name-field" /> diff --git a/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx b/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx index 3af9c40c..fe3bc4dd 100644 --- a/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx +++ b/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx @@ -9,7 +9,7 @@ import AddressInput from 'src/components/forms/AddressInput' import Field from 'src/components/forms/Field' import GnoForm from 'src/components/forms/GnoForm' import TextField from 'src/components/forms/TextField' -import { composeValidators, minMaxLength, required, uniqueAddress } from 'src/components/forms/validator' +import { composeValidators, required, uniqueAddress, validAddressBookName } from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Col from 'src/components/layout/Col' import Row from 'src/components/layout/Row' @@ -90,11 +90,11 @@ export const CreateEditEntryModal = ({ diff --git a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx index 71e98a78..d6bbada5 100644 --- a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx @@ -17,9 +17,9 @@ import TextField from 'src/components/forms/TextField' import { addressIsNotCurrentSafe, composeValidators, - minMaxLength, required, uniqueAddress, + validAddressBookName, } from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Col from 'src/components/layout/Col' @@ -118,7 +118,7 @@ export const OwnerForm = ({ onClose, onSubmit, initialValues }: OwnerFormProps): testId={ADD_OWNER_NAME_INPUT_TEST_ID} text="Owner name*" type="text" - validate={composeValidators(required, minMaxLength(1, 50))} + validate={composeValidators(required, validAddressBookName)} /> {async (address: string) => { diff --git a/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.tsx b/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.tsx index a423e420..9caed1ea 100644 --- a/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/EditOwnerModal/index.tsx @@ -6,7 +6,7 @@ import { useDispatch } from 'react-redux' import Field from 'src/components/forms/Field' import GnoForm from 'src/components/forms/GnoForm' import TextField from 'src/components/forms/TextField' -import { composeValidators, minMaxLength, required } from 'src/components/forms/validator' +import { composeValidators, required, validAddressBookName } from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Hairline from 'src/components/layout/Hairline' import Paragraph from 'src/components/layout/Paragraph' @@ -76,7 +76,7 @@ export const EditOwnerModal = ({ isOpen, onClose, owner }: OwnProps): React.Reac testId={RENAME_OWNER_INPUT_TEST_ID} text="Owner name*" type="text" - validate={composeValidators(required, minMaxLength(1, 50))} + validate={composeValidators(required, validAddressBookName)} /> diff --git a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx index 1de744cb..0ed8f358 100644 --- a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx @@ -12,9 +12,9 @@ import TextField from 'src/components/forms/TextField' import { addressIsNotCurrentSafe, composeValidators, - minMaxLength, required, uniqueAddress, + validAddressBookName, } from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Col from 'src/components/layout/Col' @@ -146,7 +146,7 @@ export const OwnerForm = ({ onClose, onSubmit, owner, initialValues }: OwnerForm testId={REPLACE_OWNER_NAME_INPUT_TEST_ID} text="Owner name*" type="text" - validate={composeValidators(required, minMaxLength(1, 50))} + validate={composeValidators(required, validAddressBookName)} /> {async (address: string) => { diff --git a/src/routes/safe/components/Settings/SafeDetails/index.tsx b/src/routes/safe/components/Settings/SafeDetails/index.tsx index 434b2b63..fbc90e72 100644 --- a/src/routes/safe/components/Settings/SafeDetails/index.tsx +++ b/src/routes/safe/components/Settings/SafeDetails/index.tsx @@ -10,7 +10,7 @@ import Modal from 'src/components/Modal' import Field from 'src/components/forms/Field' import GnoForm from 'src/components/forms/GnoForm' import TextField from 'src/components/forms/TextField' -import { composeValidators, minMaxLength, required } from 'src/components/forms/validator' +import { composeValidators, required, validAddressBookName } from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Button from 'src/components/layout/Button' import Col from 'src/components/layout/Col' @@ -166,7 +166,7 @@ const SafeDetails = (): ReactElement => { testId={SAFE_NAME_INPUT_TEST_ID} text="Safe name*" type="text" - validate={composeValidators(required, minMaxLength(1, 50))} + validate={composeValidators(required, validAddressBookName)} />