diff --git a/src/CONST.ts b/src/CONST.ts index 73375043bc50..a3c78964d305 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1567,6 +1567,10 @@ const CONST = { FORM_CHARACTER_LIMIT: 50, LEGAL_NAMES_CHARACTER_LIMIT: 150, LOGIN_CHARACTER_LIMIT: 254, + + TITLE_CHARACTER_LIMIT: 100, + DESCRIPTION_LIMIT: 500, + WORKSPACE_NAME_CHARACTER_LIMIT: 80, AVATAR_CROP_MODAL: { // The next two constants control what is min and max value of the image crop scale. diff --git a/src/languages/en.ts b/src/languages/en.ts index 3eb9f4ca6e7f..6460cae55ee3 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1677,7 +1677,6 @@ export default { nameInputLabel: 'Name', nameInputHelpText: 'This is the name you will see on your workspace.', nameIsRequiredError: 'You need to define a name for your workspace.', - nameIsTooLongError: `Your workspace name can be at most ${CONST.WORKSPACE_NAME_CHARACTER_LIMIT} characters long.`, currencyInputLabel: 'Default currency', currencyInputHelpText: 'All expenses on this workspace will be converted to this currency.', currencyInputDisabledText: "The default currency can't be changed because this workspace is linked to a USD bank account.", diff --git a/src/languages/es.ts b/src/languages/es.ts index cba4a0daba32..bea43ea6156b 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1700,7 +1700,6 @@ export default { nameInputLabel: 'Nombre', nameInputHelpText: 'Este es el nombre que verás en tu espacio de trabajo.', nameIsRequiredError: 'Debes definir un nombre para tu espacio de trabajo.', - nameIsTooLongError: `El nombre de su espacio de trabajo no puede tener más de ${CONST.WORKSPACE_NAME_CHARACTER_LIMIT} caracteres.`, currencyInputLabel: 'Moneda por defecto', currencyInputHelpText: 'Todas los gastos en este espacio de trabajo serán convertidos a esta moneda.', currencyInputDisabledText: 'La moneda predeterminada no se puede cambiar porque este espacio de trabajo está vinculado a una cuenta bancaria en USD.', diff --git a/src/pages/iou/request/step/IOURequestStepDescription.js b/src/pages/iou/request/step/IOURequestStepDescription.js index 25477170f505..3c8243b89e60 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.js +++ b/src/pages/iou/request/step/IOURequestStepDescription.js @@ -12,6 +12,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; import compose from '@libs/compose'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import * as IOU from '@userActions/IOU'; @@ -71,6 +72,24 @@ function IOURequestStepDescription({ }, []), ); + /** + * @param {Object} values + * @param {String} values.title + * @returns {Object} - An object containing the errors for each inputID + */ + const validate = useCallback((values) => { + const errors = {}; + + if (values.moneyRequestComment.length > CONST.DESCRIPTION_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'moneyRequestComment', [ + 'common.error.characterLimitExceedCounter', + {length: values.moneyRequestComment.length, limit: CONST.DESCRIPTION_LIMIT}, + ]); + } + + return errors; + }, []); + const navigateBack = () => { Navigation.goBack(backTo || ROUTES.HOME); }; @@ -115,6 +134,7 @@ function IOURequestStepDescription({ style={[styles.flexGrow1, styles.ph5]} formID={ONYXKEYS.FORMS.MONEY_REQUEST_DESCRIPTION_FORM} onSubmit={updateComment} + validate={validate} submitButtonText={translate('common.save')} enabledWhenOffline > diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js index edb54534b76c..e45253462b60 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js @@ -58,25 +58,23 @@ function LegalNamePage(props) { ErrorUtils.addErrorMessage(errors, 'legalFirstName', 'privatePersonalDetails.error.hasInvalidCharacter'); } else if (_.isEmpty(values.legalFirstName)) { errors.legalFirstName = 'common.error.fieldRequired'; + } else if (values.legalFirstName.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'legalFirstName', ['common.error.characterLimitExceedCounter', {length: values.legalFirstName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } if (ValidationUtils.doesContainReservedWord(values.legalFirstName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { ErrorUtils.addErrorMessage(errors, 'legalFirstName', 'personalDetails.error.containsReservedWord'); } - if (values.legalFirstName.length > CONST.LEGAL_NAME.MAX_LENGTH) { - ErrorUtils.addErrorMessage(errors, 'legalFirstName', ['common.error.characterLimitExceedCounter', {length: values.legalFirstName.length, limit: CONST.LEGAL_NAME.MAX_LENGTH}]); - } if (!ValidationUtils.isValidLegalName(values.legalLastName)) { ErrorUtils.addErrorMessage(errors, 'legalLastName', 'privatePersonalDetails.error.hasInvalidCharacter'); } else if (_.isEmpty(values.legalLastName)) { errors.legalLastName = 'common.error.fieldRequired'; + } else if (values.legalLastName.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'legalLastName', ['common.error.characterLimitExceedCounter', {length: values.legalLastName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } if (ValidationUtils.doesContainReservedWord(values.legalLastName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { ErrorUtils.addErrorMessage(errors, 'legalLastName', 'personalDetails.error.containsReservedWord'); } - if (values.legalLastName.length > CONST.LEGAL_NAME.MAX_LENGTH) { - ErrorUtils.addErrorMessage(errors, 'legalLastName', ['common.error.characterLimitExceedCounter', {length: values.legalLastName.length, limit: CONST.LEGAL_NAME.MAX_LENGTH}]); - } return errors; }, []); @@ -111,7 +109,6 @@ function LegalNamePage(props) { aria-label={props.translate('privatePersonalDetails.legalFirstName')} role={CONST.ROLE.PRESENTATION} defaultValue={legalFirstName} - maxLength={CONST.LEGAL_NAME.MAX_LENGTH + CONST.SEARCH_MAX_LENGTH} spellCheck={false} /> @@ -124,7 +121,6 @@ function LegalNamePage(props) { aria-label={props.translate('privatePersonalDetails.legalLastName')} role={CONST.ROLE.PRESENTATION} defaultValue={legalLastName} - maxLength={CONST.LEGAL_NAME.MAX_LENGTH + CONST.SEARCH_MAX_LENGTH} spellCheck={false} /> diff --git a/src/pages/settings/Report/RoomNamePage.tsx b/src/pages/settings/Report/RoomNamePage.tsx index 30226bc6f502..aa2aa7dd5c07 100644 --- a/src/pages/settings/Report/RoomNamePage.tsx +++ b/src/pages/settings/Report/RoomNamePage.tsx @@ -65,6 +65,8 @@ function RoomNamePage({report, policy, reports}: RoomNamePageProps) { } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, report?.policyID ?? '')) { // The room name can't be set to one that already exists on the policy ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); + } else if (values.roomName.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'roomName', ['common.error.characterLimitExceedCounter', {length: values.roomName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } return errors; diff --git a/src/pages/tasks/NewTaskDescriptionPage.js b/src/pages/tasks/NewTaskDescriptionPage.js index b11e7c163755..2a0c867c60a8 100644 --- a/src/pages/tasks/NewTaskDescriptionPage.js +++ b/src/pages/tasks/NewTaskDescriptionPage.js @@ -13,6 +13,7 @@ import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; import compose from '@libs/compose'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import updateMultilineInputRange from '@libs/updateMultilineInputRange'; import * as Task from '@userActions/Task'; @@ -47,6 +48,20 @@ function NewTaskDescriptionPage(props) { Navigation.goBack(ROUTES.NEW_TASK); }; + /** + * @param {Object} values - form input values passed by the Form component + * @returns {Boolean} + */ + function validate(values) { + const errors = {}; + + if (values.taskDescription.length > CONST.DESCRIPTION_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'taskDescription', ['common.error.characterLimitExceedCounter', {length: values.taskDescription.length, limit: CONST.DESCRIPTION_LIMIT}]); + } + + return errors; + } + return ( validate(values)} onSubmit={(values) => onSubmit(values)} enabledWhenOffline > diff --git a/src/pages/tasks/NewTaskDetailsPage.js b/src/pages/tasks/NewTaskDetailsPage.js index 3dab58dfad04..e4c1d627a99f 100644 --- a/src/pages/tasks/NewTaskDetailsPage.js +++ b/src/pages/tasks/NewTaskDetailsPage.js @@ -58,6 +58,11 @@ function NewTaskDetailsPage(props) { if (!values.taskTitle) { // We error if the user doesn't enter a task name ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); + } else if (values.taskTitle.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'taskTitle', ['common.error.characterLimitExceedCounter', {length: values.taskTitle.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); + } + if (values.taskDescription.length > CONST.DESCRIPTION_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'taskDescription', ['common.error.characterLimitExceedCounter', {length: values.taskDescription.length, limit: CONST.DESCRIPTION_LIMIT}]); } return errors; diff --git a/src/pages/tasks/NewTaskTitlePage.js b/src/pages/tasks/NewTaskTitlePage.js index 7bf6065625c0..e6da2a06435d 100644 --- a/src/pages/tasks/NewTaskTitlePage.js +++ b/src/pages/tasks/NewTaskTitlePage.js @@ -48,6 +48,8 @@ function NewTaskTitlePage(props) { if (!values.taskTitle) { // We error if the user doesn't enter a task name ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); + } else if (values.taskTitle.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'taskTitle', ['common.error.characterLimitExceedCounter', {length: values.taskTitle.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } return errors; diff --git a/src/pages/tasks/TaskDescriptionPage.js b/src/pages/tasks/TaskDescriptionPage.js index c5dab0dc2f94..962d9f959563 100644 --- a/src/pages/tasks/TaskDescriptionPage.js +++ b/src/pages/tasks/TaskDescriptionPage.js @@ -14,6 +14,7 @@ import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; import compose from '@libs/compose'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; @@ -39,7 +40,20 @@ const defaultProps = { const parser = new ExpensiMark(); function TaskDescriptionPage(props) { const styles = useThemeStyles(); - const validate = useCallback(() => ({}), []); + + /** + * @param {Object} values - form input values passed by the Form component + * @returns {Boolean} + */ + const validate = useCallback((values) => { + const errors = {}; + + if (values.description.length > CONST.DESCRIPTION_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'description', ['common.error.characterLimitExceedCounter', {length: values.description.length, limit: CONST.DESCRIPTION_LIMIT}]); + } + + return errors; + }, []); const submit = useCallback( (values) => { diff --git a/src/pages/tasks/TaskTitlePage.js b/src/pages/tasks/TaskTitlePage.js index 9b3d28a0d032..9fd1f29d3a0d 100644 --- a/src/pages/tasks/TaskTitlePage.js +++ b/src/pages/tasks/TaskTitlePage.js @@ -12,6 +12,7 @@ import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalD import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import withReportOrNotFound from '@pages/home/report/withReportOrNotFound'; @@ -44,6 +45,8 @@ function TaskTitlePage(props) { if (_.isEmpty(values.title)) { errors.title = 'newTaskPage.pleaseEnterTaskName'; + } else if (values.title.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'title', ['common.error.characterLimitExceedCounter', {length: values.title.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } return errors; diff --git a/src/pages/workspace/WorkspaceNamePage.tsx b/src/pages/workspace/WorkspaceNamePage.tsx index e9d1ddd021d0..59679456be56 100644 --- a/src/pages/workspace/WorkspaceNamePage.tsx +++ b/src/pages/workspace/WorkspaceNamePage.tsx @@ -8,6 +8,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ValidationUtils from '@libs/ValidationUtils'; import * as Policy from '@userActions/Policy'; @@ -41,10 +42,10 @@ function WorkspaceNamePage({policy}: Props) { if (!ValidationUtils.isRequiredFulfilled(name)) { errors.name = 'workspace.editor.nameIsRequiredError'; - } else if ([...name].length > CONST.WORKSPACE_NAME_CHARACTER_LIMIT) { + } else if ([...name].length > CONST.TITLE_CHARACTER_LIMIT) { // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 // code units. - errors.name = 'workspace.editor.nameIsTooLongError'; + ErrorUtils.addErrorMessage(errors, 'name', ['common.error.characterLimitExceedCounter', {length: [...name].length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } return errors; diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 1c6981b9936a..45b574414375 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -210,6 +210,8 @@ function WorkspaceNewRoomPage(props) { } else if (ValidationUtils.isExistingRoomName(values.roomName, props.reports, values.policyID)) { // Certain names are reserved for default rooms and should not be used for policy rooms. ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); + } else if (values.roomName.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'roomName', ['common.error.characterLimitExceedCounter', {length: values.roomName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); } if (!values.policyID) {