diff --git a/src/components/AddPaymentCard/PaymentCardForm.tsx b/src/components/AddPaymentCard/PaymentCardForm.tsx index 61e9a2d1860a..055026573864 100644 --- a/src/components/AddPaymentCard/PaymentCardForm.tsx +++ b/src/components/AddPaymentCard/PaymentCardForm.tsx @@ -138,35 +138,35 @@ function PaymentCardForm({ const [isCurrencyModalVisible, setIsCurrencyModalVisible] = useState(false); const [currency, setCurrency] = useState(CONST.CURRENCY.USD); - const validate = (formValues: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(formValues, REQUIRED_FIELDS); + const validate = (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS); - if (formValues.nameOnCard && !ValidationUtils.isValidLegalName(formValues.nameOnCard)) { - errors.nameOnCard = label.error.nameOnCard; + if (values.nameOnCard && !ValidationUtils.isValidLegalName(values.nameOnCard)) { + errors.nameOnCard = translate('addDebitCardPage.error.invalidName'); } - if (formValues.cardNumber && !ValidationUtils.isValidDebitCard(formValues.cardNumber.replace(/ /g, ''))) { - errors.cardNumber = label.error.cardNumber; + if (values.cardNumber && !ValidationUtils.isValidDebitCard(values.cardNumber.replace(/ /g, ''))) { + errors.cardNumber = translate('addDebitCardPage.error.debitCardNumber'); } - if (formValues.expirationDate && !ValidationUtils.isValidExpirationDate(formValues.expirationDate)) { - errors.expirationDate = label.error.expirationDate; + if (values.expirationDate && !ValidationUtils.isValidExpirationDate(values.expirationDate)) { + errors.expirationDate = translate('addDebitCardPage.error.expirationDate'); } - if (formValues.securityCode && !ValidationUtils.isValidSecurityCode(formValues.securityCode)) { - errors.securityCode = label.error.securityCode; + if (values.securityCode && !ValidationUtils.isValidSecurityCode(values.securityCode)) { + errors.securityCode = translate('addDebitCardPage.error.securityCode'); } - if (formValues.addressStreet && !ValidationUtils.isValidAddress(formValues.addressStreet)) { - errors.addressStreet = label.error.addressStreet; + if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) { + errors.addressStreet = translate('addDebitCardPage.error.addressStreet'); } - if (formValues.addressZipCode && !ValidationUtils.isValidZipCode(formValues.addressZipCode)) { - errors.addressZipCode = label.error.addressZipCode; + if (values.addressZipCode && !ValidationUtils.isValidZipCode(values.addressZipCode)) { + errors.addressZipCode = translate('addDebitCardPage.error.addressZipCode'); } - if (!formValues.acceptTerms) { - errors.acceptTerms = 'common.error.acceptTerms'; + if (!values.acceptTerms) { + errors.acceptTerms = translate('common.error.acceptTerms'); } return errors; diff --git a/src/components/AddPlaidBankAccount.tsx b/src/components/AddPlaidBankAccount.tsx index a1430615e37b..a112b36705c3 100644 --- a/src/components/AddPlaidBankAccount.tsx +++ b/src/components/AddPlaidBankAccount.tsx @@ -172,6 +172,7 @@ function AddPlaidBankAccount({ })); const {icon, iconSize, iconStyles} = getBankIcon({styles}); const plaidErrors = plaidData?.errors; + // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style const plaidDataErrorMessage = !isEmptyObject(plaidErrors) ? (Object.values(plaidErrors)[0] as string) : ''; const bankName = plaidData?.bankName; diff --git a/src/components/AddressForm.tsx b/src/components/AddressForm.tsx index 296ecce7d092..27822fb390a6 100644 --- a/src/components/AddressForm.tsx +++ b/src/components/AddressForm.tsx @@ -3,7 +3,6 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; -import type {MaybePhraseKey} from '@libs/Localize'; import * as ValidationUtils from '@libs/ValidationUtils'; import CONST from '@src/CONST'; import type {Country} from '@src/CONST'; @@ -76,7 +75,7 @@ function AddressForm({ const zipSampleFormat = (country && (CONST.COUNTRY_ZIP_REGEX_DATA[country] as CountryZipRegex)?.samples) ?? ''; - const zipFormat: MaybePhraseKey = ['common.zipCodeExampleFormat', {zipSampleFormat}]; + const zipFormat = translate('common.zipCodeExampleFormat', {zipSampleFormat}); const isUSAForm = country === CONST.COUNTRY.US; @@ -87,50 +86,53 @@ function AddressForm({ * @returns - An object containing the errors for each inputID */ - const validator = useCallback((values: FormOnyxValues): Errors => { - const errors: Errors & { - zipPostCode?: string | string[]; - } = {}; - const requiredFields = ['addressLine1', 'city', 'country', 'state'] as const; - - // Check "State" dropdown is a valid state if selected Country is USA - if (values.country === CONST.COUNTRY.US && !values.state) { - errors.state = 'common.error.fieldRequired'; - } - - // Add "Field required" errors if any required field is empty - requiredFields.forEach((fieldKey) => { - const fieldValue = values[fieldKey] ?? ''; - if (ValidationUtils.isRequiredFulfilled(fieldValue)) { - return; + const validator = useCallback( + (values: FormOnyxValues): Errors => { + const errors: Errors & { + zipPostCode?: string | string[]; + } = {}; + const requiredFields = ['addressLine1', 'city', 'country', 'state'] as const; + + // Check "State" dropdown is a valid state if selected Country is USA + if (values.country === CONST.COUNTRY.US && !values.state) { + errors.state = translate('common.error.fieldRequired'); } - errors[fieldKey] = 'common.error.fieldRequired'; - }); + // Add "Field required" errors if any required field is empty + requiredFields.forEach((fieldKey) => { + const fieldValue = values[fieldKey] ?? ''; + if (ValidationUtils.isRequiredFulfilled(fieldValue)) { + return; + } + + errors[fieldKey] = translate('common.error.fieldRequired'); + }); - // If no country is selected, default value is an empty string and there's no related regex data so we default to an empty object - const countryRegexDetails = (values.country ? CONST.COUNTRY_ZIP_REGEX_DATA?.[values.country] : {}) as CountryZipRegex; + // If no country is selected, default value is an empty string and there's no related regex data so we default to an empty object + const countryRegexDetails = (values.country ? CONST.COUNTRY_ZIP_REGEX_DATA?.[values.country] : {}) as CountryZipRegex; - // The postal code system might not exist for a country, so no regex either for them. - const countrySpecificZipRegex = countryRegexDetails?.regex; - const countryZipFormat = countryRegexDetails?.samples ?? ''; + // The postal code system might not exist for a country, so no regex either for them. + const countrySpecificZipRegex = countryRegexDetails?.regex; + const countryZipFormat = countryRegexDetails?.samples ?? ''; - ErrorUtils.addErrorMessage(errors, 'firstName', 'bankAccount.error.firstName'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('bankAccount.error.firstName')); - if (countrySpecificZipRegex) { - if (!countrySpecificZipRegex.test(values.zipPostCode?.trim().toUpperCase())) { - if (ValidationUtils.isRequiredFulfilled(values.zipPostCode?.trim())) { - errors.zipPostCode = ['privatePersonalDetails.error.incorrectZipFormat', countryZipFormat]; - } else { - errors.zipPostCode = 'common.error.fieldRequired'; + if (countrySpecificZipRegex) { + if (!countrySpecificZipRegex.test(values.zipPostCode?.trim().toUpperCase())) { + if (ValidationUtils.isRequiredFulfilled(values.zipPostCode?.trim())) { + errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat', countryZipFormat); + } else { + errors.zipPostCode = translate('common.error.fieldRequired'); + } } + } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(values?.zipPostCode?.trim()?.toUpperCase() ?? '')) { + errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat'); } - } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(values?.zipPostCode?.trim()?.toUpperCase() ?? '')) { - errors.zipPostCode = 'privatePersonalDetails.error.incorrectZipFormat'; - } - return errors; - }, []); + return errors; + }, + [translate], + ); return ( void; /** Error text to display */ - errorText?: MaybePhraseKey; + errorText?: string; /** Hint text to display */ hint?: string; diff --git a/src/components/AmountPicker/types.ts b/src/components/AmountPicker/types.ts index f7025685d840..5069893f8186 100644 --- a/src/components/AmountPicker/types.ts +++ b/src/components/AmountPicker/types.ts @@ -1,6 +1,5 @@ import type {AmountFormProps} from '@components/AmountForm'; import type {MenuItemBaseProps} from '@components/MenuItem'; -import type {MaybePhraseKey} from '@libs/Localize'; type AmountSelectorModalProps = { /** Whether the modal is visible */ @@ -24,7 +23,7 @@ type AmountPickerProps = { title?: string | ((value?: string) => string); /** Form Error description */ - errorText?: MaybePhraseKey; + errorText?: string; /** Callback to call when the input changes */ onInputChange?: (value: string | undefined) => void; diff --git a/src/components/CheckboxWithLabel.tsx b/src/components/CheckboxWithLabel.tsx index dd169576186e..db62aa9e1441 100644 --- a/src/components/CheckboxWithLabel.tsx +++ b/src/components/CheckboxWithLabel.tsx @@ -3,7 +3,6 @@ import React, {useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import variables from '@styles/variables'; import Checkbox from './Checkbox'; import FormHelpMessage from './FormHelpMessage'; @@ -41,7 +40,7 @@ type CheckboxWithLabelProps = RequiredLabelProps & { style?: StyleProp; /** Error text to display */ - errorText?: MaybePhraseKey; + errorText?: string; /** Value for checkbox. This prop is intended to be set by FormProvider only */ value?: boolean; diff --git a/src/components/CountrySelector.tsx b/src/components/CountrySelector.tsx index 002c0c6d4b0a..62fdc85687e1 100644 --- a/src/components/CountrySelector.tsx +++ b/src/components/CountrySelector.tsx @@ -4,7 +4,6 @@ import type {ForwardedRef} from 'react'; import type {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import type {Country} from '@src/CONST'; @@ -13,7 +12,7 @@ import MenuItemWithTopDescription from './MenuItemWithTopDescription'; type CountrySelectorProps = { /** Form error text. e.g when no country is selected */ - errorText?: MaybePhraseKey; + errorText?: string; /** Callback called when the country changes. */ onInputChange?: (value?: string) => void; diff --git a/src/components/DotIndicatorMessage.tsx b/src/components/DotIndicatorMessage.tsx index 3f72bbf429aa..564d2eeb8c75 100644 --- a/src/components/DotIndicatorMessage.tsx +++ b/src/components/DotIndicatorMessage.tsx @@ -7,7 +7,6 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {isReceiptError} from '@libs/ErrorUtils'; import fileDownload from '@libs/fileDownload'; -import type {MaybePhraseKey} from '@libs/Localize'; import * as Localize from '@libs/Localize'; import type {ReceiptError} from '@src/types/onyx/Transaction'; import Icon from './Icon'; @@ -23,7 +22,7 @@ type DotIndicatorMessageProps = { * timestamp: 'message', * } */ - messages: Record; + messages: Record; /** The type of message, 'error' shows a red dot, 'success' shows a green dot */ type: 'error' | 'success'; @@ -45,12 +44,12 @@ function DotIndicatorMessage({messages = {}, style, type, textStyles}: DotIndica } // Fetch the keys, sort them, and map through each key to get the corresponding message - const sortedMessages: Array = Object.keys(messages) + const sortedMessages: Array = Object.keys(messages) .sort() - .map((key) => messages[key]); - + .map((key) => messages[key]) + .filter((message): message is string | ReceiptError => message !== null); // Removing duplicates using Set and transforming the result into an array - const uniqueMessages: Array = [...new Set(sortedMessages)].map((message) => (isReceiptError(message) ? message : Localize.translateIfPhraseKey(message))); + const uniqueMessages: Array = [...new Set(sortedMessages)].map((message) => message); const isErrorMessage = type === 'error'; diff --git a/src/components/Form/FormProvider.tsx b/src/components/Form/FormProvider.tsx index 3d20f910dca0..16ecc3805d2d 100644 --- a/src/components/Form/FormProvider.tsx +++ b/src/components/Form/FormProvider.tsx @@ -253,10 +253,10 @@ function FormProvider( const errorFields = formState?.errorFields?.[inputID] ?? {}; const fieldErrorMessage = - (Object.keys(errorFields) + Object.keys(errorFields) .sort() .map((key) => errorFields[key]) - .at(-1) as string) ?? ''; + .at(-1) ?? ''; const inputRef = inputProps.ref; diff --git a/src/components/Form/types.ts b/src/components/Form/types.ts index 331f1c943b30..9aa8bc921164 100644 --- a/src/components/Form/types.ts +++ b/src/components/Form/types.ts @@ -18,7 +18,6 @@ import type StateSelector from '@components/StateSelector'; import type TextInput from '@components/TextInput'; import type TextPicker from '@components/TextPicker'; import type ValuePicker from '@components/ValuePicker'; -import type {MaybePhraseKey} from '@libs/Localize'; import type BusinessTypePicker from '@pages/ReimbursementAccount/BusinessInfo/substeps/TypeBusiness/BusinessTypePicker'; import type {Country} from '@src/CONST'; import type {OnyxFormKey, OnyxValues} from '@src/ONYXKEYS'; @@ -139,7 +138,7 @@ type FormRef = { type InputRefs = Record>; -type FormInputErrors = Partial, MaybePhraseKey>>; +type FormInputErrors = Partial, string | undefined>>; export type { FormProps, diff --git a/src/components/FormAlertWithSubmitButton.tsx b/src/components/FormAlertWithSubmitButton.tsx index 137012478549..cd177a1d77a3 100644 --- a/src/components/FormAlertWithSubmitButton.tsx +++ b/src/components/FormAlertWithSubmitButton.tsx @@ -2,13 +2,12 @@ import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import Button from './Button'; import FormAlertWrapper from './FormAlertWrapper'; type FormAlertWithSubmitButtonProps = { /** Error message to display above button */ - message?: MaybePhraseKey; + message?: string; /** Whether the button is disabled */ isDisabled?: boolean; diff --git a/src/components/FormAlertWrapper.tsx b/src/components/FormAlertWrapper.tsx index d8b379208a29..525182070095 100644 --- a/src/components/FormAlertWrapper.tsx +++ b/src/components/FormAlertWrapper.tsx @@ -4,7 +4,6 @@ import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import type Network from '@src/types/onyx/Network'; import FormHelpMessage from './FormHelpMessage'; import {withNetwork} from './OnyxProvider'; @@ -29,7 +28,7 @@ type FormAlertWrapperProps = { isMessageHtml?: boolean; /** Error message to display above button */ - message?: MaybePhraseKey; + message?: string; /** Props to detect online status */ network: Network; diff --git a/src/components/FormHelpMessage.tsx b/src/components/FormHelpMessage.tsx index 4f1d784788bf..01a5a1eaf3a8 100644 --- a/src/components/FormHelpMessage.tsx +++ b/src/components/FormHelpMessage.tsx @@ -4,14 +4,13 @@ import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as Localize from '@libs/Localize'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import Text from './Text'; type FormHelpMessageProps = { /** Error or hint text. Ignored when children is not empty */ - message?: Localize.MaybePhraseKey; + message?: string; /** Children to render next to dot indicator */ children?: React.ReactNode; @@ -33,8 +32,6 @@ function FormHelpMessage({message = '', children, isError = true, style, shouldS return null; } - const translatedMessage = Localize.translateIfPhraseKey(message); - return ( {isError && shouldShowRedDotIndicator && ( @@ -44,7 +41,7 @@ function FormHelpMessage({message = '', children, isError = true, style, shouldS /> )} - {children ?? {translatedMessage}} + {children ?? {message}} ); diff --git a/src/components/MagicCodeInput.tsx b/src/components/MagicCodeInput.tsx index deff56a534ee..6239243cb5ab 100644 --- a/src/components/MagicCodeInput.tsx +++ b/src/components/MagicCodeInput.tsx @@ -7,7 +7,6 @@ import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; -import type {MaybePhraseKey} from '@libs/Localize'; import * as ValidationUtils from '@libs/ValidationUtils'; import CONST from '@src/CONST'; import FormHelpMessage from './FormHelpMessage'; @@ -33,7 +32,7 @@ type MagicCodeInputProps = { shouldDelayFocus?: boolean; /** Error text to display */ - errorText?: MaybePhraseKey; + errorText?: string; /** Specifies autocomplete hints for the system, so it can provide autofill */ autoComplete: AutoCompleteVariant; diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 0ad729e13662..06edd921440c 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -14,7 +14,6 @@ import ControlSelection from '@libs/ControlSelection'; import convertToLTR from '@libs/convertToLTR'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import getButtonState from '@libs/getButtonState'; -import type {MaybePhraseKey} from '@libs/Localize'; import type {AvatarSource} from '@libs/UserUtils'; import variables from '@styles/variables'; import * as Session from '@userActions/Session'; @@ -154,13 +153,13 @@ type MenuItemBaseProps = { shouldShowDescriptionOnTop?: boolean; /** Error to display at the bottom of the component */ - errorText?: MaybePhraseKey; + errorText?: string; /** Any additional styles to pass to error text. */ errorTextStyle?: StyleProp; /** Hint to display at the bottom of the component */ - hintText?: MaybePhraseKey; + hintText?: string; /** Should the error text red dot indicator be shown */ shouldShowRedDotIndicator?: boolean; diff --git a/src/components/MessagesRow.tsx b/src/components/MessagesRow.tsx index 7c764ec94fcd..6a5be5db07bc 100644 --- a/src/components/MessagesRow.tsx +++ b/src/components/MessagesRow.tsx @@ -4,7 +4,6 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import type * as Localize from '@libs/Localize'; import CONST from '@src/CONST'; import type {ReceiptError} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -16,7 +15,7 @@ import Tooltip from './Tooltip'; type MessagesRowProps = { /** The messages to display */ - messages: Record; + messages: Record; /** The type of message, 'error' shows a red dot, 'success' shows a green dot */ type: 'error' | 'success'; diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 3e7f8a65846f..87fc207dd1fd 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -35,6 +35,7 @@ import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot'; import * as IOU from '@userActions/IOU'; import type {IOUAction, IOUType} from '@src/CONST'; import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; @@ -320,7 +321,7 @@ function MoneyRequestConfirmationList({ const previousTransactionCurrency = usePrevious(transaction?.currency); const isFocused = useIsFocused(); - const [formError, debouncedFormError, setFormError] = useDebouncedState(''); + const [formError, debouncedFormError, setFormError] = useDebouncedState(''); const [didConfirm, setDidConfirm] = useState(false); const [didConfirmSplit, setDidConfirmSplit] = useState(false); @@ -755,20 +756,20 @@ function MoneyRequestConfirmationList({ }, [ selectedParticipants, + isEditingSplitBill, isMerchantRequired, isMerchantEmpty, shouldDisplayFieldError, transaction, + iouCategory.length, + formError, iouType, + setFormError, onSendMoney, iouCurrencyCode, isDistanceRequest, - iouCategory, isDistanceRequestWithPendingRoute, iouAmount, - isEditingSplitBill, - formError, - setFormError, onConfirm, ], ); @@ -820,7 +821,7 @@ function MoneyRequestConfirmationList({ )} @@ -837,10 +838,11 @@ function MoneyRequestConfirmationList({ policyID, splitOrRequestOptions, formError, - debouncedFormError, - shouldShowReadOnlySplits, styles.ph1, styles.mb2, + shouldShowReadOnlySplits, + debouncedFormError, + translate, ]); // An intermediate structure that helps us classify the fields as "primary" and "supplementary". diff --git a/src/components/OfflineWithFeedback.tsx b/src/components/OfflineWithFeedback.tsx index 1ff3ee2ed737..70354c4a4676 100644 --- a/src/components/OfflineWithFeedback.tsx +++ b/src/components/OfflineWithFeedback.tsx @@ -5,8 +5,6 @@ import {View} from 'react-native'; import useNetwork from '@hooks/useNetwork'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as ErrorUtils from '@libs/ErrorUtils'; -import type {MaybePhraseKey} from '@libs/Localize'; import mapChildrenFlat from '@libs/mapChildrenFlat'; import shouldRenderOffscreen from '@libs/shouldRenderOffscreen'; import type {AllStyles} from '@styles/utils/types'; @@ -63,10 +61,6 @@ type OfflineWithFeedbackProps = ChildrenProps & { type StrikethroughProps = Partial & {style: Array}; -function isMaybePhraseKeyType(message: unknown): message is MaybePhraseKey { - return typeof message === 'string' || Array.isArray(message); -} - function OfflineWithFeedback({ pendingAction, canDismissError = true, @@ -90,8 +84,8 @@ function OfflineWithFeedback({ // Some errors have a null message. This is used to apply opacity only and to avoid showing redundant messages. const errorEntries = Object.entries(errors ?? {}); - const filteredErrorEntries = errorEntries.filter((errorEntry): errorEntry is [string, MaybePhraseKey | ReceiptError] => errorEntry[1] !== null); - const errorMessages = mapValues(Object.fromEntries(filteredErrorEntries), (error) => (isMaybePhraseKeyType(error) ? ErrorUtils.getErrorMessageWithTranslationData(error) : error)); + const filteredErrorEntries = errorEntries.filter((errorEntry): errorEntry is [string, string | ReceiptError] => errorEntry[1] !== null); + const errorMessages = mapValues(Object.fromEntries(filteredErrorEntries), (error) => error); const hasErrorMessages = !isEmptyObject(errorMessages); const isOfflinePendingAction = !!isOffline && !!pendingAction; diff --git a/src/components/PDFView/PDFPasswordForm.tsx b/src/components/PDFView/PDFPasswordForm.tsx index e1ef83c9b60d..4b6491addbef 100644 --- a/src/components/PDFView/PDFPasswordForm.tsx +++ b/src/components/PDFView/PDFPasswordForm.tsx @@ -47,13 +47,13 @@ function PDFPasswordForm({isFocused, isPasswordInvalid = false, shouldShowLoadin const errorText = useMemo(() => { if (isPasswordInvalid) { - return 'attachmentView.passwordIncorrect'; + return translate('attachmentView.passwordIncorrect'); } if (validationErrorText) { return validationErrorText; } return ''; - }, [isPasswordInvalid, validationErrorText]); + }, [isPasswordInvalid, validationErrorText, translate]); useEffect(() => { if (!isFocused) { @@ -90,7 +90,7 @@ function PDFPasswordForm({isFocused, isPasswordInvalid = false, shouldShowLoadin return true; } if (!password) { - setValidationErrorText('attachmentView.passwordRequired'); + setValidationErrorText(translate('attachmentView.passwordRequired')); } return false; }; diff --git a/src/components/Picker/types.ts b/src/components/Picker/types.ts index d935ebe8fdc5..a6a942f41f26 100644 --- a/src/components/Picker/types.ts +++ b/src/components/Picker/types.ts @@ -1,6 +1,5 @@ import type {ChangeEvent, Component, ReactElement} from 'react'; import type {MeasureLayoutOnSuccessCallback, NativeMethods, StyleProp, ViewStyle} from 'react-native'; -import type {MaybePhraseKey} from '@libs/Localize'; type MeasureLayoutOnFailCallback = () => void; @@ -59,7 +58,7 @@ type BasePickerProps = { placeholder?: PickerPlaceholder; /** Error text to display */ - errorText?: MaybePhraseKey; + errorText?: string; /** Customize the BasePicker container */ containerStyles?: StyleProp; diff --git a/src/components/RadioButtonWithLabel.tsx b/src/components/RadioButtonWithLabel.tsx index 50cca4abcf03..43f44065f5d9 100644 --- a/src/components/RadioButtonWithLabel.tsx +++ b/src/components/RadioButtonWithLabel.tsx @@ -3,7 +3,6 @@ import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import FormHelpMessage from './FormHelpMessage'; import * as Pressables from './Pressable'; import RadioButton from './RadioButton'; @@ -29,7 +28,7 @@ type RadioButtonWithLabelProps = { hasError?: boolean; /** Error text to display */ - errorText?: MaybePhraseKey; + errorText?: string; }; const PressableWithFeedback = Pressables.PressableWithFeedback; diff --git a/src/components/RadioButtons.tsx b/src/components/RadioButtons.tsx index 2030ce8f0bfd..07e8fe38f772 100644 --- a/src/components/RadioButtons.tsx +++ b/src/components/RadioButtons.tsx @@ -3,7 +3,6 @@ import type {ForwardedRef} from 'react'; import {View} from 'react-native'; import type {StyleProp, ViewStyle} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import FormHelpMessage from './FormHelpMessage'; import RadioButtonWithLabel from './RadioButtonWithLabel'; @@ -24,7 +23,7 @@ type RadioButtonsProps = { onPress: (value: string) => void; /** Potential error text provided by a form InputWrapper */ - errorText?: MaybePhraseKey; + errorText?: string; /** Style for radio button */ radioButtonStyle?: StyleProp; diff --git a/src/components/RoomNameInput/types.ts b/src/components/RoomNameInput/types.ts index 80f08a01e472..763d0f3f2668 100644 --- a/src/components/RoomNameInput/types.ts +++ b/src/components/RoomNameInput/types.ts @@ -1,10 +1,9 @@ import type {NativeSyntheticEvent, ReturnKeyTypeOptions, TextInputFocusEventData, TextInputSubmitEditingEventData} from 'react-native'; -import type {MaybePhraseKey} from '@libs/Localize'; type RoomNameInputProps = { value?: string; disabled?: boolean; - errorText?: MaybePhraseKey; + errorText?: string; onChangeText?: (value: string) => void; onSubmitEditing?: (event: NativeSyntheticEvent) => void; onInputChange?: (value: string) => void; diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index f70cac628498..3ea9c3a32646 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -1,6 +1,5 @@ import type {MutableRefObject, ReactElement, ReactNode} from 'react'; import type {GestureResponderEvent, InputModeOptions, LayoutChangeEvent, SectionListData, StyleProp, TextInput, TextStyle, ViewStyle} from 'react-native'; -import type {MaybePhraseKey} from '@libs/Localize'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import type CONST from '@src/CONST'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; @@ -293,7 +292,7 @@ type BaseSelectionListProps = Partial & { textInputPlaceholder?: string; /** Hint for the text input */ - textInputHint?: MaybePhraseKey; + textInputHint?: string; /** Value for the text input */ textInputValue?: string; diff --git a/src/components/SingleChoiceQuestion.tsx b/src/components/SingleChoiceQuestion.tsx index 3ff844dd80e9..c2dc72438e43 100644 --- a/src/components/SingleChoiceQuestion.tsx +++ b/src/components/SingleChoiceQuestion.tsx @@ -3,14 +3,13 @@ import React, {forwardRef} from 'react'; // eslint-disable-next-line no-restricted-imports import type {Text as RNText} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import type {Choice} from './RadioButtons'; import RadioButtons from './RadioButtons'; import Text from './Text'; type SingleChoiceQuestionProps = { prompt: string; - errorText?: MaybePhraseKey; + errorText?: string; possibleAnswers: Choice[]; currentQuestionIndex: number; onInputChange: (value: string) => void; diff --git a/src/components/StateSelector.tsx b/src/components/StateSelector.tsx index 67ba80c13ef8..2481c29d8123 100644 --- a/src/components/StateSelector.tsx +++ b/src/components/StateSelector.tsx @@ -6,7 +6,6 @@ import type {View} from 'react-native'; import useGeographicalStateFromRoute from '@hooks/useGeographicalStateFromRoute'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {MaybePhraseKey} from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -17,7 +16,7 @@ type State = keyof typeof COMMON_CONST.STATES; type StateSelectorProps = { /** Form error text. e.g when no state is selected */ - errorText?: MaybePhraseKey; + errorText?: string; /** Current selected state */ value?: State | ''; diff --git a/src/components/TextInput/BaseTextInput/types.ts b/src/components/TextInput/BaseTextInput/types.ts index e8e2d5ab352d..7a46cca693e3 100644 --- a/src/components/TextInput/BaseTextInput/types.ts +++ b/src/components/TextInput/BaseTextInput/types.ts @@ -1,6 +1,5 @@ import type {GestureResponderEvent, StyleProp, TextInputProps, TextStyle, ViewStyle} from 'react-native'; import type {AnimatedTextInputRef} from '@components/RNTextInput'; -import type {MaybePhraseKey} from '@libs/Localize'; import type IconAsset from '@src/types/utils/IconAsset'; type CustomBaseTextInputProps = { @@ -20,7 +19,7 @@ type CustomBaseTextInputProps = { placeholder?: string; /** Error text to display */ - errorText?: MaybePhraseKey; + errorText?: string; /** Icon to display in right side of text input */ icon?: IconAsset | null; @@ -68,7 +67,7 @@ type CustomBaseTextInputProps = { hideFocusedState?: boolean; /** Hint text to display below the TextInput */ - hint?: MaybePhraseKey; + hint?: string; /** Prefix character */ prefixCharacter?: string; diff --git a/src/components/TextPicker/types.ts b/src/components/TextPicker/types.ts index 179d16a07262..cbdc1ed21efe 100644 --- a/src/components/TextPicker/types.ts +++ b/src/components/TextPicker/types.ts @@ -1,6 +1,5 @@ import type {MenuItemBaseProps} from '@components/MenuItem'; import type {BaseTextInputProps} from '@components/TextInput/BaseTextInput/types'; -import type {MaybePhraseKey} from '@libs/Localize'; type TextProps = Exclude; @@ -30,7 +29,7 @@ type TextPickerProps = { placeholder?: string; /** Form Error description */ - errorText?: MaybePhraseKey; + errorText?: string; /** Callback to call when the input changes */ onInputChange?: (value: string | undefined) => void; diff --git a/src/components/TimePicker/TimePicker.tsx b/src/components/TimePicker/TimePicker.tsx index aecaf74dc4a3..8905abd370fe 100644 --- a/src/components/TimePicker/TimePicker.tsx +++ b/src/components/TimePicker/TimePicker.tsx @@ -135,15 +135,15 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}}: Tim const hour = parseInt(hourStr, 10); if (hour === 0) { setError(true); - setErrorMessage('common.error.invalidTimeRange'); + setErrorMessage(translate('common.error.invalidTimeRange')); return false; } const isValid = DateUtils.isTimeAtLeastOneMinuteInFuture({timeString, dateTimeString: defaultValue}); setError(!isValid); - setErrorMessage('common.error.invalidTimeShouldBeFuture'); + setErrorMessage(translate('common.error.invalidTimeShouldBeFuture')); return isValid; }, - [hours, minutes, amPmValue, defaultValue], + [hours, minutes, amPmValue, defaultValue, translate], ); const resetHours = () => { diff --git a/src/components/ValuePicker/types.ts b/src/components/ValuePicker/types.ts index b9c2c89948d9..b57c9d32061a 100644 --- a/src/components/ValuePicker/types.ts +++ b/src/components/ValuePicker/types.ts @@ -1,5 +1,4 @@ import type {ListItem} from '@components/SelectionList/types'; -import type {MaybePhraseKey} from '@libs/Localize'; type ValuePickerListItem = ListItem & { value?: string; @@ -51,7 +50,7 @@ type ValuePickerProps = { placeholder?: string; /** Form Error description */ - errorText?: MaybePhraseKey; + errorText?: string; /** Callback to call when the input changes */ onInputChange?: (value: string | undefined) => void; diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index b2817fa46438..fc42ac54a2b4 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -651,7 +651,7 @@ const getDayValidationErrorKey = (inputDate: Date): string => { } if (isAfter(startOfDay(new Date()), startOfDay(inputDate))) { - return 'common.error.invalidDateShouldBeFuture'; + return Localize.translateLocal('common.error.invalidDateShouldBeFuture'); } return ''; }; @@ -665,7 +665,7 @@ const getDayValidationErrorKey = (inputDate: Date): string => { const getTimeValidationErrorKey = (inputTime: Date): string => { const timeNowPlusOneMinute = addMinutes(new Date(), 1); if (isBefore(inputTime, timeNowPlusOneMinute)) { - return 'common.error.invalidTimeShouldBeFuture'; + return Localize.translateLocal('common.error.invalidTimeShouldBeFuture'); } return ''; }; diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts index 8af6b706086e..cf852e533a20 100644 --- a/src/libs/ErrorUtils.ts +++ b/src/libs/ErrorUtils.ts @@ -38,11 +38,19 @@ function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatO } /** - * Method used to get an error object with microsecond as the key. - * @param error - error key or message to be saved + * Creates an error object with a timestamp (in microseconds) as the key and the translated error message as the value. + * @param error - The translation key for the error message. + */ +function getMicroSecondOnyxErrorWithTranslationKey(error: TranslationPaths, errorKey?: number): Errors { + return {[errorKey ?? DateUtils.getMicroseconds()]: Localize.translateLocal(error)}; +} + +/** + * Creates an error object with a timestamp (in microseconds) as the key and the error message as the value. + * @param error - The error message. */ -function getMicroSecondOnyxError(error: string, isTranslated = false, errorKey?: number): Errors { - return {[errorKey ?? DateUtils.getMicroseconds()]: error && [error, {isTranslated}]}; +function getMicroSecondOnyxErrorWithMessage(error: string, errorKey?: number): Errors { + return {[errorKey ?? DateUtils.getMicroseconds()]: error}; } /** @@ -54,15 +62,15 @@ function getMicroSecondOnyxErrorObject(error: Errors, errorKey?: number): ErrorF } // We can assume that if error is a string, it has already been translated because it is server error -function getErrorMessageWithTranslationData(error: Localize.MaybePhraseKey): Localize.MaybePhraseKey { - return typeof error === 'string' ? [error, {isTranslated: true}] : error; +function getErrorMessageWithTranslationData(error: string | null): string { + return error ?? ''; } type OnyxDataWithErrors = { errors?: Errors | null; }; -function getLatestErrorMessage(onyxData: OnyxEntry): Localize.MaybePhraseKey { +function getLatestErrorMessage(onyxData: OnyxEntry | null): string { const errors = onyxData?.errors ?? {}; if (Object.keys(errors).length === 0) { @@ -70,7 +78,7 @@ function getLatestErrorMessage(onyxData: O } const key = Object.keys(errors).sort().reverse()[0]; - return getErrorMessageWithTranslationData(errors[key]); + return getErrorMessageWithTranslationData(errors[key] ?? ''); } function getLatestErrorMessageField(onyxData: OnyxEntry): Errors { @@ -127,16 +135,16 @@ function getLatestErrorFieldForAnyField(errors: Errors, inputID?: string | null, message?: TKey | Localize.MaybePhraseKey) { +function addErrorMessage(errors: Errors, inputID?: string | null, message?: string | null) { if (!message || !inputID) { return; } const errorList = errors; const error = errorList[inputID]; - const translatedMessage = Localize.translateIfPhraseKey(message); if (!error) { - errorList[inputID] = [translatedMessage, {isTranslated: true}]; + errorList[inputID] = message; } else if (typeof error === 'string') { - errorList[inputID] = [`${error}\n${translatedMessage}`, {isTranslated: true}]; - } else if (Array.isArray(error)) { - error[0] = `${error[0]}\n${translatedMessage}`; + errorList[inputID] = `${error}\n${message}`; } } @@ -193,7 +198,8 @@ export { getLatestErrorFieldForAnyField, getLatestErrorMessage, getLatestErrorMessageField, - getMicroSecondOnyxError, + getMicroSecondOnyxErrorWithTranslationKey, + getMicroSecondOnyxErrorWithMessage, getMicroSecondOnyxErrorObject, isReceiptError, }; diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index 8c13e1648d88..c9eef3170245 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -9,7 +9,6 @@ import translations from '@src/languages/translations'; import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Locale} from '@src/types/onyx'; -import type {ReceiptError} from '@src/types/onyx/Transaction'; import LocaleListener from './LocaleListener'; import BaseLocaleListener from './LocaleListener/BaseLocaleListener'; @@ -175,34 +174,6 @@ function translateLocal(phrase: TKey, ...variable return translate(BaseLocaleListener.getPreferredLocale(), phrase, ...variables); } -type MaybePhraseKey = string | null | [string, Record & {isTranslated?: boolean}] | []; - -/** - * Return translated string for given error. - */ -function translateIfPhraseKey(message: MaybePhraseKey): string; -function translateIfPhraseKey(message: ReceiptError): ReceiptError; -function translateIfPhraseKey(message: MaybePhraseKey | ReceiptError): string | ReceiptError; -function translateIfPhraseKey(message: MaybePhraseKey | ReceiptError): string | ReceiptError { - if (!message || (Array.isArray(message) && message.length === 0)) { - return ''; - } - - try { - // check if error message has a variable parameter - const [phrase, variables] = Array.isArray(message) ? message : [message]; - - // This condition checks if the error is already translated. For example, if there are multiple errors per input, we handle translation in ErrorUtils.addErrorMessage due to the inability to concatenate error keys. - if (variables?.isTranslated) { - return phrase; - } - - return translateLocal(phrase as TranslationPaths, variables as never); - } catch (error) { - return Array.isArray(message) ? message[0] : message; - } -} - function getPreferredListFormat(): Intl.ListFormat { if (!CONJUNCTION_LIST_FORMATS_FOR_LOCALES) { init(); @@ -254,5 +225,5 @@ function getDevicePreferredLocale(): Locale { return RNLocalize.findBestAvailableLanguage([CONST.LOCALES.EN, CONST.LOCALES.ES])?.languageTag ?? CONST.LOCALES.DEFAULT; } -export {translate, translateLocal, translateIfPhraseKey, formatList, formatMessageElementList, getDevicePreferredLocale}; -export type {PhraseParameters, Phrase, MaybePhraseKey}; +export {translate, translateLocal, formatList, formatMessageElementList, getDevicePreferredLocale}; +export type {PhraseParameters, Phrase}; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 11a689662ef4..b04d007d0557 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -536,14 +536,14 @@ function getAllReportErrors(report: OnyxEntry, reportActions: OnyxEntry< const transactionID = parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? parentReportAction?.originalMessage?.IOUTransactionID : null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; if (TransactionUtils.hasMissingSmartscanFields(transaction ?? null) && !ReportUtils.isSettled(transaction?.reportID)) { - reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); + reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericSmartscanFailureMessage'); } } else if ((ReportUtils.isIOUReport(report) || ReportUtils.isExpenseReport(report)) && report?.ownerAccountID === currentUserAccountID) { if (ReportUtils.shouldShowRBRForMissingSmartscanFields(report?.reportID ?? '-1') && !ReportUtils.isSettled(report?.reportID)) { - reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); + reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericSmartscanFailureMessage'); } } else if (ReportUtils.hasSmartscanError(Object.values(reportActions ?? {}))) { - reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxError('report.genericSmartscanFailureMessage'); + reportActionErrors.smartscan = ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericSmartscanFailureMessage'); } // All error objects related to the report. Each object in the sources contains error messages keyed by microtime const errorSources = { diff --git a/src/libs/PolicyDistanceRatesUtils.ts b/src/libs/PolicyDistanceRatesUtils.ts index 084356df7449..7e2c0bb83320 100644 --- a/src/libs/PolicyDistanceRatesUtils.ts +++ b/src/libs/PolicyDistanceRatesUtils.ts @@ -4,6 +4,7 @@ import type ONYXKEYS from '@src/ONYXKEYS'; import type {Rate} from '@src/types/onyx/Policy'; import * as CurrencyUtils from './CurrencyUtils'; import getPermittedDecimalSeparator from './getPermittedDecimalSeparator'; +import * as Localize from './Localize'; import * as MoneyRequestUtils from './MoneyRequestUtils'; import * as NumberUtils from './NumberUtils'; @@ -19,9 +20,9 @@ function validateRateValue(values: FormOnyxValues, currency: stri // Allow one more decimal place for accuracy const rateValueRegex = RegExp(String.raw`^-?\d{0,8}([${getPermittedDecimalSeparator(decimalSeparator)}]\d{0,${CurrencyUtils.getCurrencyDecimals(currency) + 1}})?$`, 'i'); if (!rateValueRegex.test(parsedRate) || parsedRate === '') { - errors.rate = 'workspace.reimburse.invalidRateError'; + errors.rate = Localize.translateLocal('workspace.reimburse.invalidRateError'); } else if (NumberUtils.parseFloatAnyLocale(parsedRate) <= 0) { - errors.rate = 'workspace.reimburse.lowRateError'; + errors.rate = Localize.translateLocal('workspace.reimburse.lowRateError'); } return errors; } @@ -30,7 +31,7 @@ function validateTaxClaimableValue(values: FormOnyxValues, r const errors: FormInputErrors = {}; if (rate.rate && Number(values.taxClaimableValue) > rate.rate / 100) { - errors.taxClaimableValue = 'workspace.taxes.error.updateTaxClaimableFailureMessage'; + errors.taxClaimableValue = Localize.translateLocal('workspace.taxes.error.updateTaxClaimableFailureMessage'); } return errors; } diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index d365cd756b68..107cbd8676dc 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -641,7 +641,7 @@ function replaceBaseURLInPolicyChangeLogAction(reportAction: ReportAction): Repo } function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection | OnyxCollectionInputValue = {}): OnyxEntry { - const reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true)) as Array; + const reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true)); const visibleReportActions = Object.values(reportActions ?? {}).filter((action): action is ReportAction => shouldReportActionBeVisibleAsLastAction(action)); const sortedReportActions = getSortedReportActions(visibleReportActions, true); if (sortedReportActions.length === 0) { diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 820444443d78..c96d3c511320 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -108,7 +108,8 @@ function getOrderedReportIDs( const isHidden = report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const isFocused = report.reportID === currentReportId; const allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) ?? {}; - const hasErrorsOtherThanFailedReceipt = doesReportHaveViolations || Object.values(allReportErrors).some((error) => error?.[0] !== 'report.genericSmartscanFailureMessage'); + const hasErrorsOtherThanFailedReceipt = + doesReportHaveViolations || Object.values(allReportErrors).some((error) => error?.[0] !== Localize.translateLocal('iou.error.genericSmartscanFailureMessage')); const isSystemChat = ReportUtils.isSystemChat(report); const shouldOverrideHidden = hasErrorsOtherThanFailedReceipt || isFocused || isSystemChat || report.isPinned; if (isHidden && !shouldOverrideHidden) { diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 7d7d89f21779..bad92b8ece4e 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -10,7 +10,7 @@ import type {OnyxFormKey} from '@src/ONYXKEYS'; import type {Report, TaxRates} from '@src/types/onyx'; import * as CardUtils from './CardUtils'; import DateUtils from './DateUtils'; -import type {MaybePhraseKey} from './Localize'; +import * as Localize from './Localize'; import * as LoginUtils from './LoginUtils'; import {parsePhoneNumber} from './PhoneNumber'; import StringUtils from './StringUtils'; @@ -111,7 +111,7 @@ function getFieldRequiredErrors(values: FormOnyxVal return; } - errors[fieldKey] = 'common.error.fieldRequired'; + errors[fieldKey] = Localize.translateLocal('common.error.fieldRequired'); }); return errors; @@ -190,12 +190,12 @@ function meetsMaximumAgeRequirement(date: string): boolean { /** * Validate that given date is in a specified range of years before now. */ -function getAgeRequirementError(date: string, minimumAge: number, maximumAge: number): MaybePhraseKey { +function getAgeRequirementError(date: string, minimumAge: number, maximumAge: number): string { const currentDate = startOfDay(new Date()); const testDate = parse(date, CONST.DATE.FNS_FORMAT_STRING, currentDate); if (!isValid(testDate)) { - return 'common.error.dateInvalid'; + return Localize.translateLocal('common.error.dateInvalid'); } const maximalDate = subYears(currentDate, minimumAge); @@ -206,10 +206,10 @@ function getAgeRequirementError(date: string, minimumAge: number, maximumAge: nu } if (isSameDay(testDate, maximalDate) || isAfter(testDate, maximalDate)) { - return ['privatePersonalDetails.error.dateShouldBeBefore', {dateString: format(maximalDate, CONST.DATE.FNS_FORMAT_STRING)}]; + return Localize.translateLocal('privatePersonalDetails.error.dateShouldBeBefore', {dateString: format(maximalDate, CONST.DATE.FNS_FORMAT_STRING)}); } - return ['privatePersonalDetails.error.dateShouldBeAfter', {dateString: format(minimalDate, CONST.DATE.FNS_FORMAT_STRING)}]; + return Localize.translateLocal('privatePersonalDetails.error.dateShouldBeAfter', {dateString: format(minimalDate, CONST.DATE.FNS_FORMAT_STRING)}); } /** @@ -221,14 +221,14 @@ function getDatePassedError(inputDate: string): string { // If input date is not valid, return an error if (!isValid(parsedDate)) { - return 'common.error.dateInvalid'; + return Localize.translateLocal('common.error.dateInvalid'); } // Clear time for currentDate so comparison is based solely on the date currentDate.setHours(0, 0, 0, 0); if (parsedDate < currentDate) { - return 'common.error.dateInvalid'; + return Localize.translateLocal('common.error.dateInvalid'); } return ''; diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index 6872e1bf560f..5b2b3d617e58 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -13,6 +13,7 @@ import type { } from '@libs/API/parameters'; import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import * as ErrorUtils from '@libs/ErrorUtils'; +import * as Localize from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -161,7 +162,7 @@ function getVBBADataForOnyx(currentStep?: BankAccountStep): OnyxData { key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, value: { isLoading: false, - errors: ErrorUtils.getMicroSecondOnyxError('walletPage.addBankAccountFailure'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('walletPage.addBankAccountFailure'), }, }, ], @@ -244,7 +245,7 @@ function addPersonalBankAccount(account: PlaidBankAccount) { key: ONYXKEYS.PERSONAL_BANK_ACCOUNT, value: { isLoading: false, - errors: ErrorUtils.getMicroSecondOnyxError('walletPage.addBankAccountFailure'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('walletPage.addBankAccountFailure'), }, }, ], @@ -537,7 +538,7 @@ function validatePlaidSelection(values: FormOnyxValues): Form const errorFields: FormInputErrors = {}; if (!values.selectedPlaidAccountID) { - errorFields.selectedPlaidAccountID = 'bankAccount.error.youNeedToSelectAnOption'; + errorFields.selectedPlaidAccountID = Localize.translateLocal('bankAccount.error.youNeedToSelectAnOption'); } return errorFields; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index c01d7759b9ea..bbc377b780d0 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -444,7 +444,7 @@ function updateDistanceRequestRate(transactionID: string, rateID: string, policy /** Helper function to get the receipt error for expenses, or the generic error if there's no receipt */ function getReceiptError(receipt?: Receipt, filename?: string, isScanRequest = true, errorKey?: number): Errors | ErrorFields { return isEmptyObject(receipt) || !isScanRequest - ? ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage', false, errorKey) + ? ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage', errorKey) : ErrorUtils.getMicroSecondOnyxErrorObject({error: CONST.IOU.RECEIPT_ERROR, source: receipt.source?.toString() ?? '', filename: filename ?? ''}, errorKey); } @@ -741,7 +741,7 @@ function buildOnyxDataForMoneyRequest( ...(isNewChatReport ? { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, } : {}), @@ -753,7 +753,7 @@ function buildOnyxDataForMoneyRequest( value: { pendingFields: null, errorFields: { - ...(shouldCreateNewMoneyRequestReport ? {createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage')} : {}), + ...(shouldCreateNewMoneyRequestReport ? {createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')} : {}), }, }, }, @@ -765,7 +765,7 @@ function buildOnyxDataForMoneyRequest( errorFields: existingTransactionThreadReport ? null : { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -792,7 +792,7 @@ function buildOnyxDataForMoneyRequest( errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest, errorKey), }, [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, } : { @@ -812,7 +812,7 @@ function buildOnyxDataForMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport.reportID}`, value: { [transactionThreadCreatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }); @@ -1081,7 +1081,7 @@ function buildOnyxDataForInvoice( ...(isNewChatReport ? { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, } : {}), @@ -1093,7 +1093,7 @@ function buildOnyxDataForInvoice( value: { pendingFields: null, errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -1102,7 +1102,7 @@ function buildOnyxDataForInvoice( key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -1110,7 +1110,7 @@ function buildOnyxDataForInvoice( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateInvoiceFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage'), pendingAction: null, pendingFields: clearedPendingFields, }, @@ -1125,7 +1125,7 @@ function buildOnyxDataForInvoice( errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, false, errorKey), }, [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateInvoiceFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage'), }, }, }, @@ -1134,7 +1134,7 @@ function buildOnyxDataForInvoice( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport.reportID}`, value: { [transactionThreadCreatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateInvoiceFailureMessage', false, errorKey), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateInvoiceFailureMessage', errorKey), }, }, }, @@ -1430,7 +1430,7 @@ function buildOnyxDataForTrackExpense( value: { pendingFields: null, errorFields: { - ...(shouldCreateNewMoneyRequestReport ? {createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage')} : {}), + ...(shouldCreateNewMoneyRequestReport ? {createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')} : {}), }, }, }, @@ -1446,7 +1446,7 @@ function buildOnyxDataForTrackExpense( errors: getReceiptError(transaction.receipt, transaction.filename || transaction.receipt?.filename, isScanRequest), }, [iouAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, } : { @@ -1491,7 +1491,7 @@ function buildOnyxDataForTrackExpense( errorFields: existingTransactionThreadReport ? null : { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -1511,7 +1511,7 @@ function buildOnyxDataForTrackExpense( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReport.reportID}`, value: { [transactionThreadCreatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -1705,7 +1705,7 @@ function getDeleteTrackExpenseInformation( [reportAction.reportActionID]: { ...reportAction, pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericDeleteFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericDeleteFailureMessage'), }, }, }, @@ -2547,7 +2547,7 @@ function getUpdateMoneyRequestParams( value: { [updatedReportAction.reportActionID]: { ...(updatedReportAction as OnyxTypes.ReportAction), - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), }, }, }); @@ -2832,7 +2832,7 @@ function getUpdateTrackExpenseParams( value: { [updatedReportAction.reportActionID]: { ...(updatedReportAction as OnyxTypes.ReportAction), - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), }, }, }); @@ -3160,7 +3160,7 @@ const getConvertTrackedExpenseInformation = ( value: { [modifiedExpenseReportAction.reportActionID]: { ...(modifiedExpenseReportAction as OnyxTypes.ReportAction), - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), }, }, }); @@ -3954,7 +3954,7 @@ function createSplitsAndOnyxData( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, ]; @@ -3965,7 +3965,7 @@ function createSplitsAndOnyxData( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }); @@ -3976,7 +3976,7 @@ function createSplitsAndOnyxData( key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -3985,7 +3985,7 @@ function createSplitsAndOnyxData( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -4519,7 +4519,7 @@ function startSplitBill({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, ]; @@ -4541,7 +4541,7 @@ function startSplitBill({ key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -4550,7 +4550,7 @@ function startSplitBill({ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`, value: { [splitChatCreatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, [splitIOUReportAction.reportActionID]: { errors: getReceiptError(receipt, filename), @@ -4727,7 +4727,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { ...unmodifiedTransaction, - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, { @@ -4736,7 +4736,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA value: { [reportAction.reportActionID]: { ...reportAction, - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -5107,7 +5107,7 @@ function editRegularMoneyRequest( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThread?.reportID}`, value: { [updatedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericEditFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage'), }, }, }, @@ -5477,7 +5477,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor ...reportAction, pendingAction: null, errors: { - [errorKey]: ['iou.error.genericDeleteFailureMessage', {isTranslated: false}], + [errorKey]: Localize.translateLocal('iou.error.genericDeleteFailureMessage'), }, }, }, @@ -5501,7 +5501,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor ...reportPreviewAction, pendingAction: null, errors: { - [errorKey]: ['iou.error.genericDeleteFailureMessage', {isTranslated: false}], + [errorKey]: Localize.translateLocal('iou.error.genericDeleteFailureMessage'), }, }, }, @@ -5788,7 +5788,7 @@ function getSendMoneyParams( onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${optimisticTransaction.transactionID}`, value: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, { @@ -5796,7 +5796,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticTransactionThread.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -5805,7 +5805,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticTransactionThread.reportID}`, value: { [optimisticCreatedActionForTransactionThread.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -5824,7 +5824,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { errorFields: { - createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + createChat: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -5833,7 +5833,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`, value: { [optimisticIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericCreateFailureMessage'), }, }, }, @@ -5849,7 +5849,7 @@ function getSendMoneyParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${optimisticIOUReport.reportID}`, value: { [optimisticIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }); @@ -6002,7 +6002,7 @@ function getPayMoneyRequestParams( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, value: { [optimisticIOUReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }, @@ -6252,7 +6252,7 @@ function approveMoneyRequest(expenseReport: OnyxTypes.Report | EmptyObject, full key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticApprovedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }, @@ -6406,7 +6406,7 @@ function submitReport(expenseReport: OnyxTypes.Report) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticSubmittedReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }); @@ -6494,7 +6494,7 @@ function cancelPayment(expenseReport: OnyxTypes.Report, chatReport: OnyxTypes.Re key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`, value: { [optimisticReportAction.reportActionID ?? '-1']: { - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.other'), }, }, }, @@ -6585,7 +6585,7 @@ function detachReceipt(transactionID: string) { key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { ...(transaction ?? null), - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.receiptDeleteFailureError'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.receiptDeleteFailureError'), }, }, ]; @@ -6823,7 +6823,7 @@ function putOnHold(transactionID: string, comment: string, reportID: string) { comment: { hold: null, }, - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericHoldExpenseFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericHoldExpenseFailureMessage'), }, }, ]; @@ -6885,7 +6885,7 @@ function unholdRequest(transactionID: string, reportID: string) { key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericUnholdExpenseFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericUnholdExpenseFailureMessage'), }, }, ]; diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index fc90b936e32e..d639c68216df 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -84,7 +84,7 @@ function buildOptimisticPolicyCategories(policyID: string, categories: readonly const failureCategoryMap = categories.reduce>>((acc, category) => { acc[category] = { - errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.createFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.categories.createFailureMessage'), pendingAction: null, }; return acc; @@ -202,7 +202,7 @@ function setWorkspaceCategoryEnabled(policyID: string, categoriesToUpdate: Recor acc[key] = { ...policyCategories[key], ...categoriesToUpdate[key], - errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.updateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.categories.updateFailureMessage'), pendingFields: { enabled: null, }, @@ -315,7 +315,7 @@ function renamePolicyCategory(policyID: string, policyCategory: {oldName: string [policyCategory.oldName]: { ...policyCategoryToUpdate, name: policyCategory.oldName, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.updateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.categories.updateFailureMessage'), pendingAction: null, }, }, @@ -368,7 +368,7 @@ function setWorkspaceRequiresCategory(policyID: string, requiresCategory: boolea key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { requiresCategory: !requiresCategory, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.updateFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.categories.updateFailureMessage'), pendingFields: { requiresCategory: null, }, @@ -434,7 +434,7 @@ function deleteWorkspaceCategories(policyID: string, categoryNamesToDelete: stri value: categoryNamesToDelete.reduce>>((acc, categoryName) => { acc[categoryName] = { pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.deleteFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.categories.deleteFailureMessage'), }; return acc; }, {}), @@ -567,7 +567,7 @@ function setPolicyDistanceRatesDefaultCategory(policyID: string, currentCustomUn customUnits: { [currentCustomUnit.customUnitID]: { ...currentCustomUnit, - errorFields: {defaultCategory: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {defaultCategory: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, pendingFields: {defaultCategory: null}, }, }, diff --git a/src/libs/actions/Policy/DistanceRate.ts b/src/libs/actions/Policy/DistanceRate.ts index 48405a2aa174..d22299e9e2fc 100644 --- a/src/libs/actions/Policy/DistanceRate.ts +++ b/src/libs/actions/Policy/DistanceRate.ts @@ -182,7 +182,7 @@ function createPolicyDistanceRate(policyID: string, customUnitID: string, custom [customUnitID]: { rates: { [customUnitRate.customUnitRateID ?? '']: { - errors: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), }, }, }, @@ -288,7 +288,7 @@ function setPolicyDistanceRatesUnit(policyID: string, currentCustomUnit: CustomU customUnits: { [currentCustomUnit.customUnitID]: { ...currentCustomUnit, - errorFields: {attributes: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {attributes: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, pendingFields: {attributes: null}, }, }, @@ -319,7 +319,7 @@ function updatePolicyDistanceRateValue(policyID: string, customUnit: CustomUnit, failureRates[rateID] = { ...currentRates[rateID], pendingFields: {rate: null}, - errorFields: {rate: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {rate: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }; } } @@ -390,7 +390,7 @@ function setPolicyDistanceRatesEnabled(policyID: string, customUnit: CustomUnit, failureRates[rateID] = { ...currentRates[rateID], pendingFields: {enabled: null}, - errorFields: {enabled: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {enabled: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }; } } @@ -461,7 +461,7 @@ function deletePolicyDistanceRates(policyID: string, customUnit: CustomUnit, rat failureRates[rateID] = { ...currentRates[rateID], pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage'), }; } else { optimisticRates[rateID] = currentRates[rateID]; @@ -535,7 +535,7 @@ function updateDistanceTaxClaimableValue(policyID: string, customUnit: CustomUni failureRates[rateID] = { ...currentRates[rateID], pendingFields: {taxClaimablePercentage: null}, - errorFields: {taxClaimablePercentage: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {taxClaimablePercentage: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }; } } @@ -606,7 +606,7 @@ function updateDistanceTaxRate(policyID: string, customUnit: CustomUnit, customU failureRates[rateID] = { ...currentRates[rateID], pendingFields: {taxRateExternalID: null}, - errorFields: {taxRateExternalID: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {taxRateExternalID: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }; } } diff --git a/src/libs/actions/Policy/Member.ts b/src/libs/actions/Policy/Member.ts index fc28a01b043c..e1c48e4d0522 100644 --- a/src/libs/actions/Policy/Member.ts +++ b/src/libs/actions/Policy/Member.ts @@ -238,7 +238,7 @@ function removeMembers(accountIDs: number[], policyID: string) { emailList.forEach((email) => { optimisticMembersState[email] = {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}; successMembersState[email] = null; - failureMembersState[email] = {errors: ErrorUtils.getMicroSecondOnyxError('workspace.people.error.genericRemove')}; + failureMembersState[email] = {errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.people.error.genericRemove')}; }); const optimisticData: OnyxUpdate[] = [ @@ -414,7 +414,7 @@ function updateWorkspaceMembersRole(policyID: string, accountIDs: number[], newR key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { employeeList: previousEmployeeList, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.editor.genericFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.editor.genericFailureMessage'), }, }, ]; @@ -537,7 +537,7 @@ function addMembersToWorkspace(invitedEmailsToAccountIDs: InvitedEmailsToAccount optimisticMembersState[email] = {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, role: CONST.POLICY.ROLE.USER}; successMembersState[email] = {pendingAction: null}; failureMembersState[email] = { - errors: ErrorUtils.getMicroSecondOnyxError('workspace.people.error.genericAdd'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.people.error.genericAdd'), }; }); @@ -617,7 +617,7 @@ function inviteMemberToWorkspace(policyID: string, inviterEmail: string) { { onyxMethod: Onyx.METHOD.MERGE, key: memberJoinKey, - value: {...failureMembersState, errors: ErrorUtils.getMicroSecondOnyxError('common.genericEditFailureMessage')}, + value: {...failureMembersState, errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericEditFailureMessage')}, }, ]; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 14626af15ecb..eb190d9b1e67 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -366,7 +366,7 @@ function setWorkspaceAutoReporting(policyID: string, enabled: boolean, frequency }, autoReportingFrequency: policy.autoReportingFrequency ?? null, pendingFields: {autoReporting: null}, - errorFields: {autoReporting: ErrorUtils.getMicroSecondOnyxError('workflowsDelayedSubmissionPage.autoReportingErrorMessage')}, + errorFields: {autoReporting: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsDelayedSubmissionPage.autoReportingErrorMessage')}, }, }, ]; @@ -407,7 +407,7 @@ function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf value: { autoReportingFrequency: policy.autoReportingFrequency ?? null, pendingFields: {autoReportingFrequency: null}, - errorFields: {autoReportingFrequency: ErrorUtils.getMicroSecondOnyxError('workflowsDelayedSubmissionPage.autoReportingFrequencyErrorMessage')}, + errorFields: {autoReportingFrequency: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsDelayedSubmissionPage.autoReportingFrequencyErrorMessage')}, }, }, ]; @@ -448,7 +448,7 @@ function setWorkspaceAutoReportingMonthlyOffset(policyID: string, autoReportingO value: { autoReportingOffset: policy.autoReportingOffset ?? null, pendingFields: {autoReportingOffset: null}, - errorFields: {autoReportingOffset: ErrorUtils.getMicroSecondOnyxError('workflowsDelayedSubmissionPage.monthlyOffsetErrorMessage')}, + errorFields: {autoReportingOffset: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsDelayedSubmissionPage.monthlyOffsetErrorMessage')}, }, }, ]; @@ -494,7 +494,7 @@ function setWorkspaceApprovalMode(policyID: string, approver: string, approvalMo approver: policy.approver ?? null, approvalMode: policy.approvalMode ?? null, pendingFields: {approvalMode: null}, - errorFields: {approvalMode: ErrorUtils.getMicroSecondOnyxError('workflowsApprovalPage.genericErrorMessage')}, + errorFields: {approvalMode: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsApprovalPage.genericErrorMessage')}, }, }, ]; @@ -552,7 +552,7 @@ function setWorkspacePayer(policyID: string, reimburserEmail: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { achAccount: {reimburser: policy.achAccount?.reimburser ?? null}, - errorFields: {reimburser: ErrorUtils.getMicroSecondOnyxError('workflowsPayerPage.genericErrorMessage')}, + errorFields: {reimburser: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsPayerPage.genericErrorMessage')}, pendingFields: {reimburser: null}, }, }, @@ -612,7 +612,7 @@ function setWorkspaceReimbursement(policyID: string, reimbursementChoice: ValueO isLoadingWorkspaceReimbursement: false, reimbursementChoice: policy.reimbursementChoice ?? null, achAccount: {reimburser: policy.achAccount?.reimburser ?? null}, - errorFields: {reimbursementChoice: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {reimbursementChoice: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, pendingFields: {reimbursementChoice: null}, }, }, @@ -666,7 +666,7 @@ function leaveWorkspace(policyID: string) { pendingAction: policy?.pendingAction, employeeList: { [sessionEmail]: { - errors: ErrorUtils.getMicroSecondOnyxError('workspace.people.error.genericRemove'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.people.error.genericRemove'), }, }, }, @@ -969,7 +969,7 @@ function deleteWorkspaceAvatar(policyID: string) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { errorFields: { - avatarURL: ErrorUtils.getMicroSecondOnyxError('avatarWithImagePicker.deleteWorkspaceError'), + avatarURL: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('avatarWithImagePicker.deleteWorkspaceError'), }, }, }, @@ -1028,7 +1028,7 @@ function updateGeneralSettings(policyID: string, name: string, currencyValue?: s failureRates[rateID] = { ...currentRates[rateID], pendingFields: {currency: null}, - errorFields: {currency: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {currency: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }; } } @@ -1089,7 +1089,7 @@ function updateGeneralSettings(policyID: string, name: string, currencyValue?: s key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { errorFields: { - generalSettings: ErrorUtils.getMicroSecondOnyxError('workspace.editor.genericFailureMessage'), + generalSettings: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.editor.genericFailureMessage'), }, ...(customUnitID && { customUnits: { @@ -1154,7 +1154,7 @@ function updateWorkspaceDescription(policyID: string, description: string, curre key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { errorFields: { - description: ErrorUtils.getMicroSecondOnyxError('workspace.editor.genericFailureMessage'), + description: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.editor.genericFailureMessage'), }, }, }, @@ -1303,7 +1303,7 @@ function updateWorkspaceCustomUnitAndRate(policyID: string, currentCustomUnit: C rates: { [newCustomUnit.rates.customUnitRateID]: { ...currentCustomUnit.rates, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.reimburse.updateCustomUnitError'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reimburse.updateCustomUnitError'), }, }, }, @@ -2818,7 +2818,7 @@ function setPolicyCustomTaxName(policyID: string, customTaxName: string) { taxRates: { name: originalCustomTaxName, pendingFields: {name: null}, - errorFields: {name: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {name: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }, }, }, @@ -2870,7 +2870,7 @@ function setWorkspaceCurrencyDefault(policyID: string, taxCode: string) { taxRates: { defaultExternalID: originalDefaultExternalID, pendingFields: {defaultExternalID: null}, - errorFields: {defaultExternalID: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {defaultExternalID: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }, }, }, @@ -2922,7 +2922,7 @@ function setForeignCurrencyDefault(policyID: string, taxCode: string) { taxRates: { foreignTaxDefault: originalDefaultForeignCurrencyID, pendingFields: {foreignTaxDefault: null}, - errorFields: {foreignTaxDefault: ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')}, + errorFields: {foreignTaxDefault: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')}, }, }, }, diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts index 7e2fb68ab125..1e5a4650eb1a 100644 --- a/src/libs/actions/Policy/Tag.ts +++ b/src/libs/actions/Policy/Tag.ts @@ -160,7 +160,7 @@ function createPolicyTag(policyID: string, tagName: string) { [policyTag.name]: { tags: { [newTagName]: { - errors: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.tags.genericFailureMessage'), pendingAction: null, }, }, @@ -243,7 +243,7 @@ function setWorkspaceTagEnabled(policyID: string, tagsToUpdate: Record>>>((acc, tagName) => { - acc[tagName] = {pendingAction: null, errors: ErrorUtils.getMicroSecondOnyxError('workspace.tags.deleteFailureMessage')}; + acc[tagName] = {pendingAction: null, errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.tags.deleteFailureMessage')}; return acc; }, {}), }, @@ -437,7 +437,7 @@ function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: pendingFields: { name: null, }, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.tags.genericFailureMessage'), }, }, }, @@ -557,7 +557,7 @@ function renamePolicyTaglist(policyID: string, policyTagListName: {oldName: stri value: { errors: { [oldName]: oldName, - [newName]: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'), + [newName]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.tags.genericFailureMessage'), }, [newName]: null, [oldName]: oldPolicyTags, @@ -610,7 +610,7 @@ function setPolicyRequiresTag(policyID: string, requiresTag: boolean) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { requiresTag: !requiresTag, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.tags.genericFailureMessage'), pendingFields: { requiresTag: null, }, @@ -668,7 +668,7 @@ function setPolicyTagsRequired(policyID: string, requiresTag: boolean, tagListIn required: policyTag.required, pendingFields: {required: null}, errorFields: { - required: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'), + required: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.tags.genericFailureMessage'), }, }, }, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3e0443bed0a0..d11e8a612bc1 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -559,7 +559,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { failureReportActions[actionKey] = { // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style ...(action as OptimisticAddCommentReportAction), - errors: ErrorUtils.getMicroSecondOnyxError('report.genericAddCommentFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), }; }); @@ -1740,7 +1740,7 @@ function updateReportName(reportID: string, value: string, previousValue: string reportName: null, }, errorFields: { - reportName: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReporNameEditFailureMessage'), + reportName: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReporNameEditFailureMessage'), }, }, }, @@ -1822,7 +1822,7 @@ function updateReportField(reportID: string, reportField: PolicyReportField, pre [fieldKey]: null, }, errorFields: { - [fieldKey]: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReportFieldFailureMessage'), + [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), }, }, }, @@ -1891,7 +1891,7 @@ function deleteReportField(reportID: string, reportField: PolicyReportField) { [fieldKey]: null, }, errorFields: { - [fieldKey]: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReportFieldFailureMessage'), + [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericUpdateReportFieldFailureMessage'), }, }, }, @@ -2079,7 +2079,7 @@ function addPolicyReport(policyReport: ReportUtils.OptimisticChatReport) { key: `${ONYXKEYS.COLLECTION.REPORT}${policyReport.reportID}`, value: { errorFields: { - addWorkspaceRoom: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'), + addWorkspaceRoom: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage'), }, }, }, @@ -2765,7 +2765,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails } return { ...pendingChatMember, - errors: ErrorUtils.getMicroSecondOnyxError('roomMembersPage.error.genericAdd'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('roomMembersPage.error.genericAdd'), }; }) ?? null, }, @@ -3057,7 +3057,7 @@ const updatePrivateNotes = (reportID: string, accountID: number, note: string) = value: { privateNotes: { [accountID]: { - errors: ErrorUtils.getMicroSecondOnyxError('privateNotes.error.genericFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('privateNotes.error.genericFailureMessage'), }, }, }, @@ -3280,7 +3280,7 @@ function completeOnboarding( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, value: { [taskReportAction.reportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('report.genericAddCommentFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), } as ReportAction, }, }, @@ -3407,10 +3407,10 @@ function completeOnboarding( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, value: { [introductionCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('report.genericAddCommentFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), } as ReportAction, [textCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('report.genericAddCommentFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), } as ReportAction, }, }, @@ -3448,7 +3448,7 @@ function completeOnboarding( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, value: { [videoCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('report.genericAddCommentFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), } as ReportAction, }, }); diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 85baad7a0f0e..e85fdc9d1531 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -393,7 +393,7 @@ function signInAttemptState(): OnyxData { value: { isLoading: false, loadingForm: null, - errors: ErrorUtils.getMicroSecondOnyxError('loginForm.cannotGetAccountDetails'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('loginForm.cannotGetAccountDetails'), }, }, ], @@ -715,7 +715,7 @@ function clearAccountMessages() { } function setAccountError(error: string) { - Onyx.merge(ONYXKEYS.ACCOUNT, {errors: ErrorUtils.getMicroSecondOnyxError(error, true)}); + Onyx.merge(ONYXKEYS.ACCOUNT, {errors: ErrorUtils.getMicroSecondOnyxErrorWithMessage(error)}); } // It's necessary to throttle requests to reauthenticate since calling this multiple times will cause Pusher to diff --git a/src/libs/actions/SignInRedirect.ts b/src/libs/actions/SignInRedirect.ts index c6d4ffcaa30f..e72a4b011074 100644 --- a/src/libs/actions/SignInRedirect.ts +++ b/src/libs/actions/SignInRedirect.ts @@ -34,7 +34,7 @@ function clearStorageAndRedirect(errorMessage?: string): Promise { } // `Onyx.clear` reinitializes the Onyx instance with initial values so use `Onyx.merge` instead of `Onyx.set` - Onyx.merge(ONYXKEYS.SESSION, {errors: ErrorUtils.getMicroSecondOnyxError(errorMessage)}); + Onyx.merge(ONYXKEYS.SESSION, {errors: ErrorUtils.getMicroSecondOnyxErrorWithMessage(errorMessage)}); }); } diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index c8f8bb17dda6..51fcbb53bc5f 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -269,7 +269,7 @@ function createTaskAndNavigate( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, value: { [optimisticAddCommentReport.reportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('task.genericCreateTaskFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('task.genericCreateTaskFailureMessage'), }, }, }); @@ -347,7 +347,7 @@ function completeTask(taskReport: OnyxEntry) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${taskReportID}`, value: { [completedTaskReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('task.messages.error'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('task.messages.error'), }, }, }, @@ -416,7 +416,7 @@ function reopenTask(taskReport: OnyxEntry) { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${taskReportID}`, value: { [reopenedTaskReportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxError('task.messages.error'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('task.messages.error'), }, }, }, diff --git a/src/libs/actions/TaxRate.ts b/src/libs/actions/TaxRate.ts index 99ce116d1361..4792304cb9ce 100644 --- a/src/libs/actions/TaxRate.ts +++ b/src/libs/actions/TaxRate.ts @@ -4,6 +4,7 @@ import type {FormOnyxValues} from '@components/Form/types'; import * as API from '@libs/API'; import type {CreatePolicyTaxParams, DeletePolicyTaxesParams, RenamePolicyTaxParams, SetPolicyTaxesEnabledParams, UpdatePolicyTaxValueParams} from '@libs/API/parameters'; import {WRITE_COMMANDS} from '@libs/API/types'; +import {translateLocal} from '@libs/Localize'; import * as ValidationUtils from '@libs/ValidationUtils'; import CONST from '@src/CONST'; import * as ErrorUtils from '@src/libs/ErrorUtils'; @@ -39,7 +40,7 @@ const validateTaxName = (policy: Policy, values: FormOnyxValues((acc, taxID) => { acc[taxID] = { pendingAction: null, - errors: ErrorUtils.getMicroSecondOnyxError('workspace.taxes.error.deleteFailureMessage'), + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.taxes.error.deleteFailureMessage'), }; return acc; }, {}), @@ -380,7 +381,7 @@ function updatePolicyTaxValue(policyID: string, taxID: string, taxValue: number) value: originalTaxRate.value, pendingFields: {value: null}, pendingAction: null, - errorFields: {value: ErrorUtils.getMicroSecondOnyxError('workspace.taxes.error.updateFailureMessage')}, + errorFields: {value: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.taxes.error.updateFailureMessage')}, }, }, }, @@ -444,7 +445,7 @@ function renamePolicyTax(policyID: string, taxID: string, newName: string) { name: originalTaxRate.name, pendingFields: {name: null}, pendingAction: null, - errorFields: {name: ErrorUtils.getMicroSecondOnyxError('workspace.taxes.error.updateFailureMessage')}, + errorFields: {name: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.taxes.error.updateFailureMessage')}, }, }, }, diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index c70eb73ec2a5..eb3d56158b0c 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -157,7 +157,7 @@ function requestContactMethodValidateCode(contactMethod: string) { [contactMethod]: { validateCodeSent: false, errorFields: { - validateCodeSent: ErrorUtils.getMicroSecondOnyxError('contacts.genericFailureMessages.requestContactMethodValidateCode'), + validateCodeSent: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('contacts.genericFailureMessages.requestContactMethodValidateCode'), }, pendingFields: { validateCodeSent: null, @@ -240,7 +240,7 @@ function deleteContactMethod(contactMethod: string, loginList: Record [settingName, null])), - errorFields: Object.fromEntries(Object.keys(configUpdate).map((settingName) => [settingName, ErrorUtils.getMicroSecondOnyxError('common.genericErrorMessage')])), + errorFields: Object.fromEntries( + Object.keys(configUpdate).map((settingName) => [settingName, ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('common.genericErrorMessage')]), + ), }, }, }, diff --git a/src/pages/ChatFinderPage/index.tsx b/src/pages/ChatFinderPage/index.tsx index 0ff04deb09f0..8dc4c06650e5 100644 --- a/src/pages/ChatFinderPage/index.tsx +++ b/src/pages/ChatFinderPage/index.tsx @@ -13,7 +13,6 @@ import useDebouncedState from '@hooks/useDebouncedState'; import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import type {MaybePhraseKey} from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; @@ -59,7 +58,7 @@ function ChatFinderPage({betas, isSearchingForReports, navigation}: ChatFinderPa shouldInitialize: isScreenTransitionEnd, }); - const offlineMessage: MaybePhraseKey = isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : ''; + const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); const [, debouncedSearchValueInServer, setSearchValueInServer] = useDebouncedState('', 500); diff --git a/src/pages/EditReportFieldDate.tsx b/src/pages/EditReportFieldDate.tsx index e7021f9123d6..38209ba1083b 100644 --- a/src/pages/EditReportFieldDate.tsx +++ b/src/pages/EditReportFieldDate.tsx @@ -36,11 +36,11 @@ function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, f (value: FormOnyxValues) => { const errors: FormInputErrors = {}; if (isRequired && value[fieldKey].trim() === '') { - errors[fieldKey] = 'common.error.fieldRequired'; + errors[fieldKey] = translate('common.error.fieldRequired'); } return errors; }, - [fieldKey, isRequired], + [fieldKey, isRequired, translate], ); return ( diff --git a/src/pages/EditReportFieldText.tsx b/src/pages/EditReportFieldText.tsx index 0649d59cd2ee..d619eb52b695 100644 --- a/src/pages/EditReportFieldText.tsx +++ b/src/pages/EditReportFieldText.tsx @@ -36,11 +36,11 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, f (values: FormOnyxValues) => { const errors: FormInputErrors = {}; if (isRequired && values[fieldKey].trim() === '') { - errors[fieldKey] = 'common.error.fieldRequired'; + errors[fieldKey] = translate('common.error.fieldRequired'); } return errors; }, - [fieldKey, isRequired], + [fieldKey, isRequired, translate], ); return ( diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.tsx b/src/pages/EnablePayments/AdditionalDetailsStep.tsx index 4756db4d43ec..cc41738fa581 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.tsx +++ b/src/pages/EnablePayments/AdditionalDetailsStep.tsx @@ -76,32 +76,32 @@ function AdditionalDetailsStep({walletAdditionalDetails = DEFAULT_WALLET_ADDITIO if (values.dob) { if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) { - errors.dob = 'bankAccount.error.dob'; + errors.dob = translate('bankAccount.error.dob'); } else if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) { - errors.dob = 'bankAccount.error.age'; + errors.dob = translate('bankAccount.error.age'); } } if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) { - errors.addressStreet = 'bankAccount.error.addressStreet'; + errors.addressStreet = translate('bankAccount.error.addressStreet'); } if (values.addressZipCode && !ValidationUtils.isValidZipCode(values.addressZipCode)) { - errors.addressZipCode = 'bankAccount.error.zipCode'; + errors.addressZipCode = translate('bankAccount.error.zipCode'); } if (values.phoneNumber && !ValidationUtils.isValidUSPhone(values.phoneNumber, true)) { - errors.phoneNumber = 'bankAccount.error.phoneNumber'; + errors.phoneNumber = translate('bankAccount.error.phoneNumber'); } // walletAdditionalDetails stores errors returned by the server. If the server returns an SSN error // then the user needs to provide the full 9 digit SSN. if (walletAdditionalDetails?.errorCode === CONST.WALLET.ERROR.SSN) { if (values.ssn && !ValidationUtils.isValidSSNFullNine(values.ssn)) { - errors.ssn = 'additionalDetailsStep.ssnFull9Error'; + errors.ssn = translate('additionalDetailsStep.ssnFull9Error'); } } else if (values.ssn && !ValidationUtils.isValidSSNLastFour(values.ssn)) { - errors.ssn = 'bankAccount.error.ssnLast4'; + errors.ssn = translate('bankAccount.error.ssnLast4'); } return errors; diff --git a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx index edd01c35b9a7..7998d9511b0d 100644 --- a/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx +++ b/src/pages/EnablePayments/FeesAndTerms/substeps/TermsStep.tsx @@ -49,7 +49,7 @@ function TermsStep({onNext}: SubStepProps) { const [walletTerms] = useOnyx(ONYXKEYS.WALLET_TERMS); - const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(walletTerms ?? {}) ?? ''; + const errorMessage = error ? translate('common.error.acceptTerms') : ErrorUtils.getLatestErrorMessage(walletTerms ?? {}) ?? ''; const toggleDisclosure = () => { setHasAcceptedDisclosure(!hasAcceptedDisclosure); diff --git a/src/pages/EnablePayments/PersonalInfo/substeps/AddressStep.tsx b/src/pages/EnablePayments/PersonalInfo/substeps/AddressStep.tsx index b11fa3e9d725..0f9819f31c66 100644 --- a/src/pages/EnablePayments/PersonalInfo/substeps/AddressStep.tsx +++ b/src/pages/EnablePayments/PersonalInfo/substeps/AddressStep.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -25,20 +25,6 @@ const INPUT_KEYS = { const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.STREET, PERSONAL_INFO_STEP_KEY.CITY, PERSONAL_INFO_STEP_KEY.STATE, PERSONAL_INFO_STEP_KEY.ZIP_CODE]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) { - errors.addressStreet = 'bankAccount.error.addressStreet'; - } - - if (values.addressZipCode && !ValidationUtils.isValidZipCode(values.addressZipCode)) { - errors.addressZipCode = 'bankAccount.error.zipCode'; - } - - return errors; -}; - function AddressStep({onNext, isEditing}: SubStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -52,6 +38,23 @@ function AddressStep({onNext, isEditing}: SubStepProps) { zipCode: walletAdditionalDetails?.[PERSONAL_INFO_STEP_KEY.ZIP_CODE] ?? '', }; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) { + errors.addressStreet = translate('bankAccount.error.addressStreet'); + } + + if (values.addressZipCode && !ValidationUtils.isValidZipCode(values.addressZipCode)) { + errors.addressZipCode = translate('bankAccount.error.zipCode'); + } + + return errors; + }, + [translate], + ); + const handleSubmit = useWalletAdditionalDetailsStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/EnablePayments/PersonalInfo/substeps/DateOfBirthStep.tsx b/src/pages/EnablePayments/PersonalInfo/substeps/DateOfBirthStep.tsx index cfd0f4c5e3f7..d476fdcc5c86 100644 --- a/src/pages/EnablePayments/PersonalInfo/substeps/DateOfBirthStep.tsx +++ b/src/pages/EnablePayments/PersonalInfo/substeps/DateOfBirthStep.tsx @@ -1,5 +1,5 @@ import {subYears} from 'date-fns'; -import React from 'react'; +import React, {useCallback} from 'react'; import {useOnyx} from 'react-native-onyx'; import DatePicker from '@components/DatePicker'; import FormProvider from '@components/Form/FormProvider'; @@ -19,20 +19,6 @@ import INPUT_IDS from '@src/types/form/WalletAdditionalDetailsForm'; const PERSONAL_INFO_DOB_KEY = INPUT_IDS.PERSONAL_INFO_STEP.DOB; const STEP_FIELDS = [PERSONAL_INFO_DOB_KEY]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.dob) { - if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) { - errors.dob = 'bankAccount.error.dob'; - } else if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) { - errors.dob = 'bankAccount.error.age'; - } - } - - return errors; -}; - const minDate = subYears(new Date(), CONST.DATE_BIRTH.MAX_AGE); const maxDate = subYears(new Date(), CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT); @@ -40,6 +26,23 @@ function DateOfBirthStep({onNext, isEditing}: SubStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.dob) { + if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) { + errors.dob = translate('bankAccount.error.dob'); + } else if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) { + errors.dob = translate('bankAccount.error.age'); + } + } + + return errors; + }, + [translate], + ); + const [walletAdditionalDetails] = useOnyx(ONYXKEYS.WALLET_ADDITIONAL_DETAILS); const dobDefaultValue = walletAdditionalDetails?.[PERSONAL_INFO_DOB_KEY] ?? walletAdditionalDetails?.[PERSONAL_INFO_DOB_KEY] ?? ''; diff --git a/src/pages/EnablePayments/PersonalInfo/substeps/FullNameStep.tsx b/src/pages/EnablePayments/PersonalInfo/substeps/FullNameStep.tsx index f63d5ef84879..b40fb2202943 100644 --- a/src/pages/EnablePayments/PersonalInfo/substeps/FullNameStep.tsx +++ b/src/pages/EnablePayments/PersonalInfo/substeps/FullNameStep.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -19,18 +19,6 @@ import INPUT_IDS from '@src/types/form/WalletAdditionalDetailsForm'; const PERSONAL_INFO_STEP_KEY = INPUT_IDS.PERSONAL_INFO_STEP; const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.FIRST_NAME, PERSONAL_INFO_STEP_KEY.LAST_NAME]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - if (values.legalFirstName && !ValidationUtils.isValidLegalName(values.legalFirstName)) { - errors.legalFirstName = 'bankAccount.error.firstName'; - } - - if (values.legalLastName && !ValidationUtils.isValidLegalName(values.legalLastName)) { - errors.legalLastName = 'bankAccount.error.lastName'; - } - return errors; -}; - function FullNameStep({onNext, isEditing}: SubStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -42,6 +30,21 @@ function FullNameStep({onNext, isEditing}: SubStepProps) { lastName: walletAdditionalDetails?.[PERSONAL_INFO_STEP_KEY.LAST_NAME] ?? '', }; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + if (values.legalFirstName && !ValidationUtils.isValidLegalName(values.legalFirstName)) { + errors.legalFirstName = translate('bankAccount.error.firstName'); + } + + if (values.legalLastName && !ValidationUtils.isValidLegalName(values.legalLastName)) { + errors.legalLastName = translate('bankAccount.error.lastName'); + } + return errors; + }, + [translate], + ); + const handleSubmit = useWalletAdditionalDetailsStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/EnablePayments/PersonalInfo/substeps/PhoneNumberStep.tsx b/src/pages/EnablePayments/PersonalInfo/substeps/PhoneNumberStep.tsx index 86b6a40948fc..60bfa431ca78 100644 --- a/src/pages/EnablePayments/PersonalInfo/substeps/PhoneNumberStep.tsx +++ b/src/pages/EnablePayments/PersonalInfo/substeps/PhoneNumberStep.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -19,14 +19,6 @@ import INPUT_IDS from '@src/types/form/WalletAdditionalDetailsForm'; const PERSONAL_INFO_STEP_KEY = INPUT_IDS.PERSONAL_INFO_STEP; const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.PHONE_NUMBER]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.phoneNumber && !ValidationUtils.isValidUSPhone(values.phoneNumber, true)) { - errors.phoneNumber = 'bankAccount.error.phoneNumber'; - } - return errors; -}; function PhoneNumberStep({onNext, isEditing}: SubStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -35,6 +27,18 @@ function PhoneNumberStep({onNext, isEditing}: SubStepProps) { const defaultPhoneNumber = walletAdditionalDetails?.[PERSONAL_INFO_STEP_KEY.PHONE_NUMBER] ?? ''; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.phoneNumber && !ValidationUtils.isValidUSPhone(values.phoneNumber, true)) { + errors.phoneNumber = translate('bankAccount.error.phoneNumber'); + } + return errors; + }, + [translate], + ); + const handleSubmit = useWalletAdditionalDetailsStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/EnablePayments/PersonalInfo/substeps/SocialSecurityNumberStep.tsx b/src/pages/EnablePayments/PersonalInfo/substeps/SocialSecurityNumberStep.tsx index 4c366c5a1873..bdaa3fe98f67 100644 --- a/src/pages/EnablePayments/PersonalInfo/substeps/SocialSecurityNumberStep.tsx +++ b/src/pages/EnablePayments/PersonalInfo/substeps/SocialSecurityNumberStep.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -19,19 +19,23 @@ import INPUT_IDS from '@src/types/form/WalletAdditionalDetailsForm'; const PERSONAL_INFO_STEP_KEY = INPUT_IDS.PERSONAL_INFO_STEP; const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.SSN_LAST_4]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.ssn && !ValidationUtils.isValidSSNLastFour(values.ssn)) { - errors.ssn = 'bankAccount.error.ssnLast4'; - } - - return errors; -}; function SocialSecurityNumberStep({onNext, isEditing}: SubStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.ssn && !ValidationUtils.isValidSSNLastFour(values.ssn)) { + errors.ssn = translate('bankAccount.error.ssnLast4'); + } + + return errors; + }, + [translate], + ); + const [walletAdditionalDetails] = useOnyx(ONYXKEYS.WALLET_ADDITIONAL_DETAILS); const defaultSsnLast4 = walletAdditionalDetails?.[PERSONAL_INFO_STEP_KEY.SSN_LAST_4] ?? ''; diff --git a/src/pages/EnablePayments/TermsStep.tsx b/src/pages/EnablePayments/TermsStep.tsx index f5b05998c061..09bf0da163bc 100644 --- a/src/pages/EnablePayments/TermsStep.tsx +++ b/src/pages/EnablePayments/TermsStep.tsx @@ -58,7 +58,7 @@ function TermsStep(props: TermsStepProps) { const [error, setError] = useState(false); const {translate} = useLocalize(); - const errorMessage = error ? 'common.error.acceptTerms' : ErrorUtils.getLatestErrorMessage(props.walletTerms ?? {}) ?? ''; + const errorMessage = error ? translate('common.error.acceptTerms') : ErrorUtils.getLatestErrorMessage(props.walletTerms ?? {}) ?? ''; const toggleDisclosure = () => { setHasAcceptedDisclosure(!hasAcceptedDisclosure); diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index 54e09d51b2b2..d6449bc2cf44 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -96,25 +96,25 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat // First we validate the first name field if (values.firstName.replace(CONST.REGEX.ANY_SPACE, '').length === 0) { - ErrorUtils.addErrorMessage(errors, 'firstName', 'onboarding.error.requiredFirstName'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('onboarding.error.requiredFirstName')); } if (!ValidationUtils.isValidDisplayName(values.firstName)) { - ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.hasInvalidCharacter'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('personalDetails.error.hasInvalidCharacter')); } else if (values.firstName.length > CONST.DISPLAY_NAME.MAX_LENGTH) { - ErrorUtils.addErrorMessage(errors, 'firstName', ['common.error.characterLimitExceedCounter', {length: values.firstName.length, limit: CONST.DISPLAY_NAME.MAX_LENGTH}]); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('common.error.characterLimitExceedCounter', {length: values.firstName.length, limit: CONST.DISPLAY_NAME.MAX_LENGTH})); } if (ValidationUtils.doesContainReservedWord(values.firstName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.containsReservedWord'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('personalDetails.error.containsReservedWord')); } // Then we validate the last name field if (!ValidationUtils.isValidDisplayName(values.lastName)) { - ErrorUtils.addErrorMessage(errors, 'lastName', 'personalDetails.error.hasInvalidCharacter'); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('personalDetails.error.hasInvalidCharacter')); } else if (values.lastName.length > CONST.DISPLAY_NAME.MAX_LENGTH) { - ErrorUtils.addErrorMessage(errors, 'lastName', ['common.error.characterLimitExceedCounter', {length: values.lastName.length, limit: CONST.DISPLAY_NAME.MAX_LENGTH}]); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('common.error.characterLimitExceedCounter', {length: values.lastName.length, limit: CONST.DISPLAY_NAME.MAX_LENGTH})); } if (ValidationUtils.doesContainReservedWord(values.lastName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'lastName', 'personalDetails.error.containsReservedWord'); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('personalDetails.error.containsReservedWord')); } return errors; diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index 5b186ccbe7a9..244b997f6ec6 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -83,7 +83,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on Navigation.navigate(ROUTES.ONBOARDING_PERSONAL_DETAILS); }, [selectedPurpose]); - const [errorMessage, setErrorMessage] = useState<'onboarding.purpose.errorSelection' | 'onboarding.purpose.errorContinue' | ''>(''); + const [errorMessage, setErrorMessage] = useState(''); const menuItems: MenuItemProps[] = Object.values(CONST.ONBOARDING_CHOICES).map((choice) => { const translationKey = `onboarding.purpose.${choice}` as const; @@ -110,11 +110,11 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on const handleOuterClick = useCallback(() => { if (!selectedPurpose) { - setErrorMessage('onboarding.purpose.errorSelection'); + setErrorMessage(translate('onboarding.purpose.errorSelection')); } else { - setErrorMessage('onboarding.purpose.errorContinue'); + setErrorMessage(translate('onboarding.purpose.errorContinue')); } - }, [selectedPurpose]); + }, [selectedPurpose, setErrorMessage, translate]); const onboardingLocalRef = useRef(null); useImperativeHandle(isFocused ? OnboardingRefManager.ref : onboardingLocalRef, () => ({handleOuterClick}), [handleOuterClick]); @@ -147,7 +147,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on buttonText={translate('common.continue')} onSubmit={() => { if (!selectedPurpose) { - setErrorMessage('onboarding.purpose.errorSelection'); + setErrorMessage(translate('onboarding.purpose.errorSelection')); return; } setErrorMessage(''); diff --git a/src/pages/OnboardingWork/BaseOnboardingWork.tsx b/src/pages/OnboardingWork/BaseOnboardingWork.tsx index b0e01d0c8caa..9b8824300d30 100644 --- a/src/pages/OnboardingWork/BaseOnboardingWork.tsx +++ b/src/pages/OnboardingWork/BaseOnboardingWork.tsx @@ -59,11 +59,11 @@ function BaseOnboardingWork({shouldUseNativeStyles, onboardingPurposeSelected, o const work = values.work.trim(); if (!ValidationUtils.isRequiredFulfilled(work)) { - errors.work = 'workspace.editor.nameIsRequiredError'; + errors.work = translate('workspace.editor.nameIsRequiredError'); } else if ([...work].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. - ErrorUtils.addErrorMessage(errors, 'work', ['common.error.characterLimitExceedCounter', {length: [...work].length, limit: CONST.TITLE_CHARACTER_LIMIT}]); + ErrorUtils.addErrorMessage(errors, 'work', translate('common.error.characterLimitExceedCounter', {length: [...work].length, limit: CONST.TITLE_CHARACTER_LIMIT})); } return errors; diff --git a/src/pages/ReimbursementAccount/AddressFormFields.tsx b/src/pages/ReimbursementAccount/AddressFormFields.tsx index 48af00cd4925..a863d3cc5952 100644 --- a/src/pages/ReimbursementAccount/AddressFormFields.tsx +++ b/src/pages/ReimbursementAccount/AddressFormFields.tsx @@ -52,7 +52,7 @@ function AddressFormFields({shouldSaveDraft = false, defaultValues, values, erro value={values?.street} defaultValue={defaultValues?.street} onInputChange={onFieldChange} - errorText={errors?.street ? 'bankAccount.error.addressStreet' : ''} + errorText={errors?.street ? translate('bankAccount.error.addressStreet') : ''} renamedInputKeys={inputKeys} maxInputLength={CONST.FORM_CHARACTER_LIMIT} isLimitedToUSA @@ -68,7 +68,7 @@ function AddressFormFields({shouldSaveDraft = false, defaultValues, values, erro value={values?.city} defaultValue={defaultValues?.city} onChangeText={(value) => onFieldChange?.({city: value})} - errorText={errors?.city ? 'bankAccount.error.addressCity' : ''} + errorText={errors?.city ? translate('bankAccount.error.addressCity') : ''} containerStyles={styles.mt6} /> @@ -80,7 +80,7 @@ function AddressFormFields({shouldSaveDraft = false, defaultValues, values, erro value={values?.state as State} defaultValue={defaultValues?.state} onInputChange={(value) => onFieldChange?.({state: value})} - errorText={errors?.state ? 'bankAccount.error.addressState' : ''} + errorText={errors?.state ? translate('bankAccount.error.addressState') : ''} /> onFieldChange?.({zipCode: value})} - errorText={errors?.zipCode ? 'bankAccount.error.zipCode' : ''} + errorText={errors?.zipCode ? translate('bankAccount.error.zipCode') : ''} maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.ZIP_CODE} - hint={['common.zipCodeExampleFormat', {zipSampleFormat: CONST.COUNTRY_ZIP_REGEX_DATA.US.samples}]} + hint={translate('common.zipCodeExampleFormat', {zipSampleFormat: CONST.COUNTRY_ZIP_REGEX_DATA.US.samples})} containerStyles={styles.mt3} /> diff --git a/src/pages/ReimbursementAccount/BankInfo/substeps/Manual.tsx b/src/pages/ReimbursementAccount/BankInfo/substeps/Manual.tsx index 079245e15ad0..1111bd8fcc47 100644 --- a/src/pages/ReimbursementAccount/BankInfo/substeps/Manual.tsx +++ b/src/pages/ReimbursementAccount/BankInfo/substeps/Manual.tsx @@ -38,25 +38,28 @@ function Manual({reimbursementAccount, onNext}: ManualProps) { [BANK_INFO_STEP_KEYS.ACCOUNT_NUMBER]: reimbursementAccount?.achData?.[BANK_INFO_STEP_KEYS.ACCOUNT_NUMBER] ?? '', }; - const validate = useCallback((values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - const routingNumber = values.routingNumber?.trim(); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + const routingNumber = values.routingNumber?.trim(); - if ( - values.accountNumber && - !CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(values.accountNumber.trim()) && - !CONST.BANK_ACCOUNT.REGEX.MASKED_US_ACCOUNT_NUMBER.test(values.accountNumber.trim()) - ) { - errors.accountNumber = 'bankAccount.error.accountNumber'; - } else if (values.accountNumber && values.accountNumber === routingNumber) { - errors.accountNumber = 'bankAccount.error.routingAndAccountNumberCannotBeSame'; - } - if (routingNumber && (!CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(routingNumber) || !ValidationUtils.isValidRoutingNumber(routingNumber))) { - errors.routingNumber = 'bankAccount.error.routingNumber'; - } + if ( + values.accountNumber && + !CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(values.accountNumber.trim()) && + !CONST.BANK_ACCOUNT.REGEX.MASKED_US_ACCOUNT_NUMBER.test(values.accountNumber.trim()) + ) { + errors.accountNumber = translate('bankAccount.error.accountNumber'); + } else if (values.accountNumber && values.accountNumber === routingNumber) { + errors.accountNumber = translate('bankAccount.error.routingAndAccountNumberCannotBeSame'); + } + if (routingNumber && (!CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(routingNumber) || !ValidationUtils.isValidRoutingNumber(routingNumber))) { + errors.routingNumber = translate('bankAccount.error.routingNumber'); + } - return errors; - }, []); + return errors; + }, + [translate], + ); const shouldDisableInputs = !!(reimbursementAccount?.achData?.bankAccountID ?? ''); diff --git a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx index c49f26abf80c..284a27108a48 100644 --- a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx +++ b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/AddressUBO.tsx @@ -47,11 +47,11 @@ function AddressUBO({reimbursementAccountDraft, onNext, isEditing, beneficialOwn const errors = ValidationUtils.getFieldRequiredErrors(values, stepFields); if (values[inputKeys.street] && !ValidationUtils.isValidAddress(values[inputKeys.street])) { - errors[inputKeys.street] = 'bankAccount.error.addressStreet'; + errors[inputKeys.street] = translate('bankAccount.error.addressStreet'); } if (values[inputKeys.zipCode] && !ValidationUtils.isValidZipCode(values[inputKeys.zipCode])) { - errors[inputKeys.zipCode] = 'bankAccount.error.zipCode'; + errors[inputKeys.zipCode] = translate('bankAccount.error.zipCode'); } return errors; diff --git a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx index f563692f0ae9..2173d19887ad 100644 --- a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx +++ b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.tsx @@ -40,9 +40,9 @@ function DateOfBirthUBO({reimbursementAccountDraft, onNext, isEditing, beneficia if (values[dobInputID]) { if (!ValidationUtils.isValidPastDate(values[dobInputID]) || !ValidationUtils.meetsMaximumAgeRequirement(values[dobInputID])) { - errors[dobInputID] = 'bankAccount.error.dob'; + errors[dobInputID] = translate('bankAccount.error.dob'); } else if (!ValidationUtils.meetsMinimumAgeRequirement(values[dobInputID])) { - errors[dobInputID] = 'bankAccount.error.age'; + errors[dobInputID] = translate('bankAccount.error.age'); } } diff --git a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/SocialSecurityNumberUBO.tsx b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/SocialSecurityNumberUBO.tsx index 7c0c5ac0c057..d7814816cdb9 100644 --- a/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/SocialSecurityNumberUBO.tsx +++ b/src/pages/ReimbursementAccount/BeneficialOwnerInfo/substeps/BeneficialOwnerDetailsFormSubsteps/SocialSecurityNumberUBO.tsx @@ -36,7 +36,7 @@ function SocialSecurityNumberUBO({reimbursementAccountDraft, onNext, isEditing, const validate = (values: FormOnyxValues): FormInputErrors => { const errors = ValidationUtils.getFieldRequiredErrors(values, stepFields); if (values[ssnLast4InputID] && !ValidationUtils.isValidSSNLastFour(values[ssnLast4InputID])) { - errors[ssnLast4InputID] = 'bankAccount.error.ssnLast4'; + errors[ssnLast4InputID] = translate('bankAccount.error.ssnLast4'); } return errors; }; diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx index cca9e5619d59..bd9524626a14 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/AddressBusiness.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -32,27 +32,30 @@ const INPUT_KEYS = { const STEP_FIELDS = [COMPANY_BUSINESS_INFO_KEY.STREET, COMPANY_BUSINESS_INFO_KEY.CITY, COMPANY_BUSINESS_INFO_KEY.STATE, COMPANY_BUSINESS_INFO_KEY.ZIP_CODE]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); +function AddressBusiness({reimbursementAccount, onNext, isEditing}: AddressBusinessProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); - if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) { - errors.addressStreet = 'bankAccount.error.addressStreet'; - } + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - if (values.addressCity && !ValidationUtils.isValidAddress(values.addressCity)) { - errors.addressCity = 'bankAccount.error.addressCity'; - } + if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) { + errors.addressStreet = translate('bankAccount.error.addressStreet'); + } - if (values.addressZipCode && !ValidationUtils.isValidZipCode(values.addressZipCode)) { - errors.addressZipCode = 'bankAccount.error.zipCode'; - } + if (values.addressCity && !ValidationUtils.isValidAddress(values.addressCity)) { + errors.addressCity = translate('bankAccount.error.addressCity'); + } - return errors; -}; + if (values.addressZipCode && !ValidationUtils.isValidZipCode(values.addressZipCode)) { + errors.addressZipCode = translate('bankAccount.error.zipCode'); + } -function AddressBusiness({reimbursementAccount, onNext, isEditing}: AddressBusinessProps) { - const {translate} = useLocalize(); - const styles = useThemeStyles(); + return errors; + }, + [translate], + ); const defaultValues = { street: reimbursementAccount?.achData?.addressStreet ?? '', diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/ConfirmationBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/ConfirmationBusiness.tsx index 4c8331a23d8f..23b59d76ffa7 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/ConfirmationBusiness.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/ConfirmationBusiness.tsx @@ -1,5 +1,5 @@ import type {CONST as COMMON_CONST} from 'expensify-common'; -import React, {useMemo} from 'react'; +import React, {useCallback, useMemo} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import CheckboxWithLabel from '@components/CheckboxWithLabel'; @@ -37,16 +37,6 @@ type States = keyof typeof COMMON_CONST.STATES; const BUSINESS_INFO_STEP_KEYS = INPUT_IDS.BUSINESS_INFO_STEP; const BUSINESS_INFO_STEP_INDEXES = CONST.REIMBURSEMENT_ACCOUNT.SUBSTEP_INDEX.BUSINESS_INFO; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, [BUSINESS_INFO_STEP_KEYS.HAS_NO_CONNECTION_TO_CANNABIS]); - - if (!values.hasNoConnectionToCannabis) { - errors.hasNoConnectionToCannabis = 'bankAccount.error.restrictedBusiness'; - } - - return errors; -}; - function ConfirmCompanyLabel() { const {translate} = useLocalize(); @@ -62,6 +52,19 @@ function ConfirmationBusiness({reimbursementAccount, reimbursementAccountDraft, const {translate} = useLocalize(); const styles = useThemeStyles(); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, [BUSINESS_INFO_STEP_KEYS.HAS_NO_CONNECTION_TO_CANNABIS]); + + if (!values.hasNoConnectionToCannabis) { + errors.hasNoConnectionToCannabis = translate('bankAccount.error.restrictedBusiness'); + } + + return errors; + }, + [translate], + ); + const values = useMemo(() => getSubstepValues(BUSINESS_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); const defaultCheckboxState = reimbursementAccountDraft?.[BUSINESS_INFO_STEP_KEYS.HAS_NO_CONNECTION_TO_CANNABIS] ?? false; diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx index 8fecbe46164f..274e087cc415 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/IncorporationDateBusiness.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import DatePicker from '@components/DatePicker'; @@ -29,22 +29,25 @@ type IncorporationDateBusinessProps = IncorporationDateBusinessOnyxProps & SubSt const COMPANY_INCORPORATION_DATE_KEY = INPUT_IDS.BUSINESS_INFO_STEP.INCORPORATION_DATE; const STEP_FIELDS = [COMPANY_INCORPORATION_DATE_KEY]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.incorporationDate && !ValidationUtils.isValidDate(values.incorporationDate)) { - errors.incorporationDate = 'common.error.dateInvalid'; - } else if (values.incorporationDate && !ValidationUtils.isValidPastDate(values.incorporationDate)) { - errors.incorporationDate = 'bankAccount.error.incorporationDateFuture'; - } - - return errors; -}; - function IncorporationDateBusiness({reimbursementAccount, reimbursementAccountDraft, onNext, isEditing}: IncorporationDateBusinessProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.incorporationDate && !ValidationUtils.isValidDate(values.incorporationDate)) { + errors.incorporationDate = translate('common.error.dateInvalid'); + } else if (values.incorporationDate && !ValidationUtils.isValidPastDate(values.incorporationDate)) { + errors.incorporationDate = translate('bankAccount.error.incorporationDateFuture'); + } + + return errors; + }, + [translate], + ); + const defaultCompanyIncorporationDate = reimbursementAccount?.achData?.incorporationDate ?? reimbursementAccountDraft?.incorporationDate ?? ''; const handleSubmit = useReimbursementAccountStepFormSubmit({ diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/NameBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/NameBusiness.tsx index e37afae17084..0879607c9566 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/NameBusiness.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/NameBusiness.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -26,16 +26,6 @@ type NameBusinessProps = NameBusinessOnyxProps & SubStepProps; const COMPANY_NAME_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_NAME; const STEP_FIELDS = [COMPANY_NAME_KEY]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.companyName && !ValidationUtils.isValidCompanyName(values.companyName)) { - errors.companyName = 'bankAccount.error.companyName'; - } - - return errors; -}; - function NameBusiness({reimbursementAccount, onNext, isEditing}: NameBusinessProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -45,6 +35,19 @@ function NameBusiness({reimbursementAccount, onNext, isEditing}: NameBusinessPro const shouldDisableCompanyName = !!(bankAccountID && defaultCompanyName && reimbursementAccount?.achData?.state !== 'SETUP'); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.companyName && !ValidationUtils.isValidCompanyName(values.companyName)) { + errors.companyName = translate('bankAccount.error.companyName'); + } + + return errors; + }, + [translate], + ); + const handleSubmit = useReimbursementAccountStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/PhoneNumberBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/PhoneNumberBusiness.tsx index 018922610080..e0c83737b6f8 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/PhoneNumberBusiness.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/PhoneNumberBusiness.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -26,21 +26,24 @@ type PhoneNumberBusinessProps = PhoneNumberBusinessOnyxProps & SubStepProps; const COMPANY_PHONE_NUMBER_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_PHONE; const STEP_FIELDS = [COMPANY_PHONE_NUMBER_KEY]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.companyPhone && !ValidationUtils.isValidUSPhone(values.companyPhone, true)) { - errors.companyPhone = 'bankAccount.error.phoneNumber'; - } - - return errors; -}; - function PhoneNumberBusiness({reimbursementAccount, onNext, isEditing}: PhoneNumberBusinessProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const defaultCompanyPhoneNumber = reimbursementAccount?.achData?.companyPhone ?? ''; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.companyPhone && !ValidationUtils.isValidUSPhone(values.companyPhone, true)) { + errors.companyPhone = translate('bankAccount.error.phoneNumber'); + } + + return errors; + }, + [translate], + ); + const handleSubmit = useReimbursementAccountStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/TaxIdBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/TaxIdBusiness.tsx index 67e77f8127d8..2063211f41f4 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/TaxIdBusiness.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/TaxIdBusiness.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -25,17 +25,6 @@ type TaxIdBusinessProps = TaxIdBusinessOnyxProps & SubStepProps; const COMPANY_TAX_ID_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_TAX_ID; const STEP_FIELDS = [COMPANY_TAX_ID_KEY]; - -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.companyTaxID && !ValidationUtils.isValidTaxID(values.companyTaxID)) { - errors.companyTaxID = 'bankAccount.error.taxID'; - } - - return errors; -}; - function TaxIdBusiness({reimbursementAccount, onNext, isEditing}: TaxIdBusinessProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -43,6 +32,19 @@ function TaxIdBusiness({reimbursementAccount, onNext, isEditing}: TaxIdBusinessP const bankAccountID = reimbursementAccount?.achData?.bankAccountID ?? -1; const shouldDisableCompanyTaxID = !!(bankAccountID && defaultCompanyTaxId && reimbursementAccount?.achData?.state !== 'SETUP'); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.companyTaxID && !ValidationUtils.isValidTaxID(values.companyTaxID)) { + errors.companyTaxID = translate('bankAccount.error.taxID'); + } + + return errors; + }, + [translate], + ); + const handleSubmit = useReimbursementAccountStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx b/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx index e06c4d9d575e..541e47f6cb10 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/substeps/WebsiteBusiness.tsx @@ -1,4 +1,4 @@ -import React, {useEffect, useMemo} from 'react'; +import React, {useCallback, useEffect, useMemo} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; @@ -34,16 +34,6 @@ type WebsiteBusinessProps = WebsiteBusinessOnyxProps & SubStepProps; const COMPANY_WEBSITE_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_WEBSITE; const STEP_FIELDS = [COMPANY_WEBSITE_KEY]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.website && !ValidationUtils.isValidWebsite(values.website)) { - errors.website = 'bankAccount.error.website'; - } - - return errors; -}; - function WebsiteBusiness({reimbursementAccount, user, session, onNext, isEditing}: WebsiteBusinessProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -51,6 +41,18 @@ function WebsiteBusiness({reimbursementAccount, user, session, onNext, isEditing const defaultWebsiteExample = useMemo(() => getDefaultCompanyWebsite(session, user), [session, user]); const defaultCompanyWebsite = reimbursementAccount?.achData?.website ?? defaultWebsiteExample; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.website && !ValidationUtils.isValidWebsite(values.website)) { + errors.website = translate('bankAccount.error.website'); + } + + return errors; + }, + [translate], + ); const handleSubmit = useReimbursementAccountStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx index 03a178f186ee..71d7a80ab58b 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx +++ b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import CheckboxWithLabel from '@components/CheckboxWithLabel'; @@ -30,24 +30,6 @@ const STEP_FIELDS = [ INPUT_IDS.COMPLETE_VERIFICATION.CERTIFY_TRUE_INFORMATION, ]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (!ValidationUtils.isRequiredFulfilled(values.acceptTermsAndConditions)) { - errors.acceptTermsAndConditions = 'common.error.acceptTerms'; - } - - if (!ValidationUtils.isRequiredFulfilled(values.certifyTrueInformation)) { - errors.certifyTrueInformation = 'completeVerificationStep.certifyTrueAndAccurateError'; - } - - if (!ValidationUtils.isRequiredFulfilled(values.isAuthorizedToUseBankAccount)) { - errors.isAuthorizedToUseBankAccount = 'completeVerificationStep.isAuthorizedToUseBankAccountError'; - } - - return errors; -}; - function IsAuthorizedToUseBankAccountLabel() { const {translate} = useLocalize(); return {translate('completeVerificationStep.isAuthorizedToUseBankAccount')}; @@ -76,6 +58,26 @@ function ConfirmAgreements({onNext, reimbursementAccount}: ConfirmAgreementsProp certifyTrueInformation: reimbursementAccount?.achData?.certifyTrueInformation ?? false, acceptTermsAndConditions: reimbursementAccount?.achData?.acceptTermsAndConditions ?? false, }; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (!ValidationUtils.isRequiredFulfilled(values.acceptTermsAndConditions)) { + errors.acceptTermsAndConditions = translate('common.error.acceptTerms'); + } + + if (!ValidationUtils.isRequiredFulfilled(values.certifyTrueInformation)) { + errors.certifyTrueInformation = translate('completeVerificationStep.certifyTrueAndAccurateError'); + } + + if (!ValidationUtils.isRequiredFulfilled(values.isAuthorizedToUseBankAccount)) { + errors.isAuthorizedToUseBankAccount = translate('completeVerificationStep.isAuthorizedToUseBankAccountError'); + } + + return errors; + }, + [translate], + ); return ( ): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.requestorAddressStreet && !ValidationUtils.isValidAddress(values.requestorAddressStreet)) { - errors.requestorAddressStreet = 'bankAccount.error.addressStreet'; - } - - if (values.requestorAddressZipCode && !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) { - errors.requestorAddressZipCode = 'bankAccount.error.zipCode'; - } - - return errors; -}; - function Address({reimbursementAccount, onNext, isEditing}: AddressProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -59,6 +45,23 @@ function Address({reimbursementAccount, onNext, isEditing}: AddressProps) { zipCode: reimbursementAccount?.achData?.[PERSONAL_INFO_STEP_KEY.ZIP_CODE] ?? '', }; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.requestorAddressStreet && !ValidationUtils.isValidAddress(values.requestorAddressStreet)) { + errors.requestorAddressStreet = translate('bankAccount.error.addressStreet'); + } + + if (values.requestorAddressZipCode && !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) { + errors.requestorAddressZipCode = translate('bankAccount.error.zipCode'); + } + + return errors; + }, + [translate], + ); + const handleSubmit = useReimbursementAccountStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx b/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx index 2454331f12a6..6fe391bbe957 100644 --- a/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx +++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.tsx @@ -1,5 +1,5 @@ import {subYears} from 'date-fns'; -import React from 'react'; +import React, {useCallback} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import DatePicker from '@components/DatePicker'; @@ -32,24 +32,27 @@ type DateOfBirthProps = DateOfBirthOnyxProps & SubStepProps; const PERSONAL_INFO_DOB_KEY = INPUT_IDS.PERSONAL_INFO_STEP.DOB; const STEP_FIELDS = [PERSONAL_INFO_DOB_KEY]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.dob) { - if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) { - errors.dob = 'bankAccount.error.dob'; - } else if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) { - errors.dob = 'bankAccount.error.age'; - } - } - - return errors; -}; - function DateOfBirth({reimbursementAccount, reimbursementAccountDraft, onNext, isEditing}: DateOfBirthProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.dob) { + if (!ValidationUtils.isValidPastDate(values.dob) || !ValidationUtils.meetsMaximumAgeRequirement(values.dob)) { + errors.dob = translate('bankAccount.error.dob'); + } else if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) { + errors.dob = translate('bankAccount.error.age'); + } + } + + return errors; + }, + [translate], + ); + const dobDefaultValue = reimbursementAccount?.achData?.[PERSONAL_INFO_DOB_KEY] ?? reimbursementAccountDraft?.[PERSONAL_INFO_DOB_KEY] ?? ''; const minDate = subYears(new Date(), CONST.DATE_BIRTH.MAX_AGE); diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullName.tsx b/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullName.tsx index 1d225c1c32f2..bab467707fd4 100644 --- a/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullName.tsx +++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/FullName.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; @@ -27,19 +27,6 @@ type FullNameProps = FullNameOnyxProps & SubStepProps; const PERSONAL_INFO_STEP_KEY = INPUT_IDS.PERSONAL_INFO_STEP; const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.FIRST_NAME, PERSONAL_INFO_STEP_KEY.LAST_NAME]; - -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - if (values.firstName && !ValidationUtils.isValidLegalName(values.firstName)) { - errors.firstName = 'bankAccount.error.firstName'; - } - - if (values.lastName && !ValidationUtils.isValidLegalName(values.lastName)) { - errors.lastName = 'bankAccount.error.lastName'; - } - return errors; -}; - function FullName({reimbursementAccount, onNext, isEditing}: FullNameProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -49,6 +36,21 @@ function FullName({reimbursementAccount, onNext, isEditing}: FullNameProps) { lastName: reimbursementAccount?.achData?.[PERSONAL_INFO_STEP_KEY.LAST_NAME] ?? '', }; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + if (values.firstName && !ValidationUtils.isValidLegalName(values.firstName)) { + errors.firstName = translate('bankAccount.error.firstName'); + } + + if (values.lastName && !ValidationUtils.isValidLegalName(values.lastName)) { + errors.lastName = translate('bankAccount.error.lastName'); + } + return errors; + }, + [translate], + ); + const handleSubmit = useReimbursementAccountStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx b/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx index e647fd768fb1..390880fa65f2 100644 --- a/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx +++ b/src/pages/ReimbursementAccount/PersonalInfo/substeps/SocialSecurityNumber.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; @@ -28,21 +28,25 @@ type SocialSecurityNumberProps = SocialSecurityNumberOnyxProps & SubStepProps; const PERSONAL_INFO_STEP_KEY = INPUT_IDS.PERSONAL_INFO_STEP; const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.SSN_LAST_4]; -const validate = (values: FormOnyxValues): FormInputErrors => { - const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); - - if (values.ssnLast4 && !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { - errors.ssnLast4 = 'bankAccount.error.ssnLast4'; - } - - return errors; -}; function SocialSecurityNumber({reimbursementAccount, onNext, isEditing}: SocialSecurityNumberProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const defaultSsnLast4 = reimbursementAccount?.achData?.[PERSONAL_INFO_STEP_KEY.SSN_LAST_4] ?? ''; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = ValidationUtils.getFieldRequiredErrors(values, STEP_FIELDS); + + if (values.ssnLast4 && !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { + errors.ssnLast4 = translate('bankAccount.error.ssnLast4'); + } + + return errors; + }, + [translate], + ); + const handleSubmit = useReimbursementAccountStepFormSubmit({ fieldIds: STEP_FIELDS, onNext, diff --git a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx index eabd8642c287..ca48cf807276 100644 --- a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx +++ b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.tsx @@ -50,27 +50,27 @@ function IntroSchoolPrincipalPage(props: IntroSchoolPrincipalPageProps) { const errors: FormInputErrors = {}; if (!values.firstName || !ValidationUtils.isValidPersonName(values.firstName)) { - ErrorUtils.addErrorMessage(errors, 'firstName', 'bankAccount.error.firstName'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('bankAccount.error.firstName')); } if (!values.lastName || !ValidationUtils.isValidPersonName(values.lastName)) { - ErrorUtils.addErrorMessage(errors, 'lastName', 'bankAccount.error.lastName'); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('bankAccount.error.lastName')); } if (!values.partnerUserID) { - ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.enterEmail'); + ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.enterEmail')); } if (values.partnerUserID && props.loginList?.[values.partnerUserID.toLowerCase()]) { - ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.tryDifferentEmail'); + ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.tryDifferentEmail')); } if (values.partnerUserID && !Str.isValidEmail(values.partnerUserID)) { - ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.enterValidEmail'); + ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.enterValidEmail')); } if (values.partnerUserID && LoginUtils.isEmailPublicDomain(values.partnerUserID)) { - ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.tryDifferentEmail'); + ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.tryDifferentEmail')); } return errors; }, - [props.loginList], + [props.loginList, translate], ); return ( diff --git a/src/pages/TeachersUnite/KnowATeacherPage.tsx b/src/pages/TeachersUnite/KnowATeacherPage.tsx index aaca679e49b8..e4bfc16bf24c 100644 --- a/src/pages/TeachersUnite/KnowATeacherPage.tsx +++ b/src/pages/TeachersUnite/KnowATeacherPage.tsx @@ -59,24 +59,24 @@ function KnowATeacherPage(props: KnowATeacherPageProps) { const validateIfNumber = LoginUtils.validateNumber(phoneLogin); if (!values.firstName || !ValidationUtils.isValidPersonName(values.firstName)) { - ErrorUtils.addErrorMessage(errors, 'firstName', 'bankAccount.error.firstName'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('bankAccount.error.firstName')); } if (!values.lastName || !ValidationUtils.isValidPersonName(values.lastName)) { - ErrorUtils.addErrorMessage(errors, 'lastName', 'bankAccount.error.lastName'); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('bankAccount.error.lastName')); } if (!values.partnerUserID) { - ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.enterPhoneEmail'); + ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.enterPhoneEmail')); } if (values.partnerUserID && props.loginList?.[validateIfNumber || values.partnerUserID.toLowerCase()]) { - ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'teachersUnitePage.error.tryDifferentEmail'); + ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('teachersUnitePage.error.tryDifferentEmail')); } if (values.partnerUserID && !(validateIfNumber || Str.isValidEmail(values.partnerUserID))) { - ErrorUtils.addErrorMessage(errors, 'partnerUserID', 'contacts.genericFailureMessages.invalidContactMethod'); + ErrorUtils.addErrorMessage(errors, 'partnerUserID', translate('contacts.genericFailureMessages.invalidContactMethod')); } return errors; }, - [props.loginList], + [props.loginList, translate], ); return ( diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index 50df99d10581..1c22ea51b178 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -23,7 +23,7 @@ function TravelTerms() { const [hasAcceptedTravelTerms, setHasAcceptedTravelTerms] = useState(false); const [error, setError] = useState(false); - const errorMessage = error ? 'travel.termsAndConditions.error' : ''; + const errorMessage = error ? translate('travel.termsAndConditions.error') : ''; const toggleTravelTerms = () => { setHasAcceptedTravelTerms(!hasAcceptedTravelTerms); diff --git a/src/pages/iou/HoldReasonPage.tsx b/src/pages/iou/HoldReasonPage.tsx index 187ac4824b0b..ea88c12059a9 100644 --- a/src/pages/iou/HoldReasonPage.tsx +++ b/src/pages/iou/HoldReasonPage.tsx @@ -73,20 +73,20 @@ function HoldReasonPage({route}: HoldReasonPageProps) { const errors: FormInputErrors = ValidationUtils.getFieldRequiredErrors(values, [INPUT_IDS.COMMENT]); if (!values.comment) { - errors.comment = 'common.error.fieldRequired'; + errors.comment = translate('common.error.fieldRequired'); } // We have extra isWorkspaceRequest condition since, for 1:1 requests, canEditMoneyRequest will rightly return false // as we do not allow requestee to edit fields like description and amount. // But, we still want the requestee to be able to put the request on hold if (!ReportUtils.canEditMoneyRequest(parentReportAction) && isWorkspaceRequest) { const formErrors = {}; - ErrorUtils.addErrorMessage(formErrors, 'reportModified', 'common.error.requestModified'); + ErrorUtils.addErrorMessage(formErrors, 'reportModified', translate('common.error.requestModified')); FormActions.setErrors(ONYXKEYS.FORMS.MONEY_REQUEST_HOLD_FORM, formErrors); } return errors; }, - [parentReportAction, isWorkspaceRequest], + [parentReportAction, isWorkspaceRequest, translate], ); useEffect(() => { diff --git a/src/pages/iou/MoneyRequestAmountForm.tsx b/src/pages/iou/MoneyRequestAmountForm.tsx index 667c27c96a8c..ff061e7382c6 100644 --- a/src/pages/iou/MoneyRequestAmountForm.tsx +++ b/src/pages/iou/MoneyRequestAmountForm.tsx @@ -17,7 +17,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; -import type {MaybePhraseKey} from '@libs/Localize'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {BaseTextInputRef} from '@src/components/TextInput/BaseTextInput/types'; @@ -103,7 +102,7 @@ function MoneyRequestAmountForm( const textInput = useRef(null); const moneyRequestAmountInput = useRef(null); - const [formError, setFormError] = useState(''); + const [formError, setFormError] = useState(''); const [shouldUpdateSelection, setShouldUpdateSelection] = useState(true); const isFocused = useIsFocused(); @@ -215,18 +214,18 @@ function MoneyRequestAmountForm( // Skip the check for tax amount form as 0 is a valid input const currentAmount = moneyRequestAmountInput.current?.getAmount() ?? ''; if (!currentAmount.length || (!isTaxAmountForm && isAmountInvalid(currentAmount))) { - setFormError('iou.error.invalidAmount'); + setFormError(translate('iou.error.invalidAmount')); return; } if (isTaxAmountInvalid(currentAmount, taxAmount, isTaxAmountForm)) { - setFormError(['iou.error.invalidTaxAmount', {amount: formattedTaxAmount}]); + setFormError(translate('iou.error.invalidTaxAmount', {amount: formattedTaxAmount})); return; } onSubmitButtonPress({amount: currentAmount, currency, paymentMethod: iouPaymentType}); }, - [taxAmount, onSubmitButtonPress, currency, formattedTaxAmount], + [taxAmount, onSubmitButtonPress, currency, translate, formattedTaxAmount], ); const buttonText: string = useMemo(() => { diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index f7cd13e14af0..0caa8b6cd7a6 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -19,7 +19,6 @@ import usePermissions from '@hooks/usePermissions'; import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; -import type {MaybePhraseKey} from '@libs/Localize'; import type {Options} from '@libs/OptionsListUtils'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -66,7 +65,7 @@ function MoneyRequestParticipantsSelector({participants = [], onFinish, onPartic shouldInitialize: didScreenTransitionEnd, }); - const offlineMessage: MaybePhraseKey = isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : ''; + const offlineMessage: string = isOffline ? `${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}` : ''; const isIOUSplit = iouType === CONST.IOU.TYPE.SPLIT; const isCategorizeOrShareAction = [CONST.IOU.ACTION.CATEGORIZE, CONST.IOU.ACTION.SHARE].some((option) => option === action); @@ -309,7 +308,7 @@ function MoneyRequestParticipantsSelector({participants = [], onFinish, onPartic )} diff --git a/src/pages/iou/request/step/IOURequestStepDescription.tsx b/src/pages/iou/request/step/IOURequestStepDescription.tsx index 820b7d206fcd..7ccce96bb06c 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.tsx +++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx @@ -94,18 +94,22 @@ function IOURequestStepDescription({ /** * @returns - An object containing the errors for each inputID */ - const validate = useCallback((values: FormOnyxValues): FormInputErrors => { - const errors = {}; - - if (values.moneyRequestComment.length > CONST.DESCRIPTION_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'moneyRequestComment', [ - 'common.error.characterLimitExceedCounter', - {length: values.moneyRequestComment.length, limit: CONST.DESCRIPTION_LIMIT}, - ]); - } + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = {}; + + if (values.moneyRequestComment.length > CONST.DESCRIPTION_LIMIT) { + ErrorUtils.addErrorMessage( + errors, + 'moneyRequestComment', + translate('common.error.characterLimitExceedCounter', {length: values.moneyRequestComment.length, limit: CONST.DESCRIPTION_LIMIT}), + ); + } - return errors; - }, []); + return errors; + }, + [translate], + ); const navigateBack = () => { Navigation.goBack(backTo); diff --git a/src/pages/iou/request/step/IOURequestStepDistance.tsx b/src/pages/iou/request/step/IOURequestStepDistance.tsx index d0d4127f2421..a8fc44ba3947 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistance.tsx @@ -326,7 +326,7 @@ function IOURequestStepDistance({ return {duplicateWaypointsError: translate('iou.error.duplicateWaypointsErrorMessage')} as Errors; } if (atLeastTwoDifferentWaypointsError) { - return {atLeastTwoDifferentWaypointsError: 'iou.error.atLeastTwoDifferentWaypoints'} as Errors; + return {atLeastTwoDifferentWaypointsError: translate('iou.error.atLeastTwoDifferentWaypoints')} as Errors; } return {}; }; diff --git a/src/pages/iou/request/step/IOURequestStepMerchant.tsx b/src/pages/iou/request/step/IOURequestStepMerchant.tsx index 6795de0d91a4..f723c3280400 100644 --- a/src/pages/iou/request/step/IOURequestStepMerchant.tsx +++ b/src/pages/iou/request/step/IOURequestStepMerchant.tsx @@ -75,12 +75,12 @@ function IOURequestStepMerchant({ const errors: FormInputErrors = {}; if (isMerchantRequired && !value.moneyRequestMerchant) { - errors.moneyRequestMerchant = 'common.error.fieldRequired'; + errors.moneyRequestMerchant = translate('common.error.fieldRequired'); } return errors; }, - [isMerchantRequired], + [isMerchantRequired, translate], ); const updateMerchant = (value: FormOnyxValues) => { diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index a1540396f8e5..6df92cf1da4d 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -92,13 +92,13 @@ function IOURequestStepWaypoint({ const errors = {}; const waypointValue = values[`waypoint${pageIndex}`] ?? ''; if (isOffline && waypointValue !== '' && !ValidationUtils.isValidAddress(waypointValue)) { - ErrorUtils.addErrorMessage(errors, `waypoint${pageIndex}`, 'bankAccount.error.address'); + ErrorUtils.addErrorMessage(errors, `waypoint${pageIndex}`, translate('bankAccount.error.address')); } // If the user is online, and they are trying to save a value without using the autocomplete, show an error message instructing them to use a selected address instead. // That enables us to save the address with coordinates when it is selected if (!isOffline && waypointValue !== '' && waypointAddress !== waypointValue) { - ErrorUtils.addErrorMessage(errors, `waypoint${pageIndex}`, 'distance.error.selectSuggestedAddress'); + ErrorUtils.addErrorMessage(errors, `waypoint${pageIndex}`, translate('distance.error.selectSuggestedAddress')); } return errors; @@ -214,7 +214,7 @@ function IOURequestStepWaypoint({ ref={(e: HTMLElement | null) => { textInput.current = e as unknown as TextInput; }} - hint={!isOffline ? 'distance.error.selectSuggestedAddress' : ''} + hint={!isOffline ? translate('distance.error.selectSuggestedAddress') : ''} containerStyles={[styles.mt4]} label={translate('distance.address')} defaultValue={waypointAddress} diff --git a/src/pages/settings/ExitSurvey/ExitSurveyReasonPage.tsx b/src/pages/settings/ExitSurvey/ExitSurveyReasonPage.tsx index dbaf330803c1..d9f53faa62d0 100644 --- a/src/pages/settings/ExitSurvey/ExitSurveyReasonPage.tsx +++ b/src/pages/settings/ExitSurvey/ExitSurveyReasonPage.tsx @@ -60,7 +60,7 @@ function ExitSurveyReasonPage({draftReason}: ExitSurveyReasonPageOnyxProps) { validate={() => { const errors: Errors = {}; if (!reason) { - errors[INPUT_IDS.REASON] = 'common.error.fieldRequired'; + errors[INPUT_IDS.REASON] = translate('common.error.fieldRequired'); } return errors; }} diff --git a/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx b/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx index 62183b0ebc26..64e8159334d9 100644 --- a/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx +++ b/src/pages/settings/ExitSurvey/ExitSurveyResponsePage.tsx @@ -110,7 +110,7 @@ function ExitSurveyResponsePage({draftResponse, route, navigation}: ExitSurveyRe validate={() => { const errors: Errors = {}; if (!draftResponse?.trim()) { - errors[INPUT_IDS.RESPONSE] = 'common.error.fieldRequired'; + errors[INPUT_IDS.RESPONSE] = translate('common.error.fieldRequired'); } return errors; }} diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx index f32c5b14c86b..cf6b58c3eaca 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx +++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.tsx @@ -223,7 +223,7 @@ function ContactMethodDetailsPage({route}: ContactMethodDetailsPageProps) { type="success" style={[themeStyles.mb3]} // eslint-disable-next-line @typescript-eslint/naming-convention - messages={{0: ['contacts.enterMagicCode', {contactMethod: formattedContactMethod}]}} + messages={{0: translate('contacts.enterMagicCode', {contactMethod: formattedContactMethod})}} /> { diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx index fc4ec0220b41..313a5a066496 100644 --- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -206,7 +206,7 @@ function BaseValidateCodeForm({account = {}, contactMethod, hasMagicCodeBeenSent type="success" style={[styles.mt6, styles.flex0]} // eslint-disable-next-line @typescript-eslint/naming-convention - messages={{0: 'resendValidationForm.linkHasBeenResent'}} + messages={{0: translate('resendValidationForm.linkHasBeenResent')}} /> )} diff --git a/src/pages/settings/Profile/DisplayNamePage.tsx b/src/pages/settings/Profile/DisplayNamePage.tsx index 3ab443b23561..e338fc16b0ee 100644 --- a/src/pages/settings/Profile/DisplayNamePage.tsx +++ b/src/pages/settings/Profile/DisplayNamePage.tsx @@ -47,22 +47,22 @@ function DisplayNamePage({isLoadingApp = true, currentUserPersonalDetails}: Disp // First we validate the first name field if (!ValidationUtils.isValidDisplayName(values.firstName)) { - ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.hasInvalidCharacter'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('personalDetails.error.hasInvalidCharacter')); } else if (values.firstName.length > CONST.TITLE_CHARACTER_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'firstName', ['common.error.characterLimitExceedCounter', {length: values.firstName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('common.error.characterLimitExceedCounter', {length: values.firstName.length, limit: CONST.TITLE_CHARACTER_LIMIT})); } if (ValidationUtils.doesContainReservedWord(values.firstName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.containsReservedWord'); + ErrorUtils.addErrorMessage(errors, 'firstName', translate('personalDetails.error.containsReservedWord')); } // Then we validate the last name field if (!ValidationUtils.isValidDisplayName(values.lastName)) { - ErrorUtils.addErrorMessage(errors, 'lastName', 'personalDetails.error.hasInvalidCharacter'); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('personalDetails.error.hasInvalidCharacter')); } else if (values.lastName.length > CONST.TITLE_CHARACTER_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'lastName', ['common.error.characterLimitExceedCounter', {length: values.lastName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('common.error.characterLimitExceedCounter', {length: values.lastName.length, limit: CONST.TITLE_CHARACTER_LIMIT})); } if (ValidationUtils.doesContainReservedWord(values.lastName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'lastName', 'personalDetails.error.containsReservedWord'); + ErrorUtils.addErrorMessage(errors, 'lastName', translate('personalDetails.error.containsReservedWord')); } return errors; }; diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx index 085c70b47937..99e9c910cbdf 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.tsx @@ -40,40 +40,48 @@ function LegalNamePage({privatePersonalDetails, isLoadingApp = true}: LegalNameP const legalFirstName = privatePersonalDetails?.legalFirstName ?? ''; const legalLastName = privatePersonalDetails?.legalLastName ?? ''; - const validate = useCallback((values: FormOnyxValues) => { - const errors: Errors = {}; + const validate = useCallback( + (values: FormOnyxValues) => { + const errors: Errors = {}; - if (typeof values.legalFirstName === 'string') { - if (!ValidationUtils.isValidLegalName(values.legalFirstName)) { - ErrorUtils.addErrorMessage(errors, 'legalFirstName', 'privatePersonalDetails.error.hasInvalidCharacter'); - } else if (!values.legalFirstName) { - errors.legalFirstName = 'common.error.fieldRequired'; - } else 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 (typeof values.legalFirstName === 'string') { + if (!ValidationUtils.isValidLegalName(values.legalFirstName)) { + ErrorUtils.addErrorMessage(errors, 'legalFirstName', translate('privatePersonalDetails.error.hasInvalidCharacter')); + } else if (!values.legalFirstName) { + errors.legalFirstName = translate('common.error.fieldRequired'); + } else if (values.legalFirstName.length > CONST.LEGAL_NAME.MAX_LENGTH) { + ErrorUtils.addErrorMessage( + errors, + 'legalFirstName', + translate('common.error.characterLimitExceedCounter', {length: values.legalFirstName.length, limit: CONST.LEGAL_NAME.MAX_LENGTH}), + ); + } + if (ValidationUtils.doesContainReservedWord(values.legalFirstName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { + ErrorUtils.addErrorMessage(errors, 'legalFirstName', translate('personalDetails.error.containsReservedWord')); + } } - if (ValidationUtils.doesContainReservedWord(values.legalFirstName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'legalFirstName', 'personalDetails.error.containsReservedWord'); - } - } - if (typeof values.legalLastName === 'string') { - if (!ValidationUtils.isValidLegalName(values.legalLastName)) { - ErrorUtils.addErrorMessage(errors, 'legalLastName', 'privatePersonalDetails.error.hasInvalidCharacter'); - } else if (!values.legalLastName) { - errors.legalLastName = 'common.error.fieldRequired'; - } else 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}]); - } - if (ValidationUtils.doesContainReservedWord(values.legalLastName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'legalLastName', 'personalDetails.error.containsReservedWord'); + if (typeof values.legalLastName === 'string') { + if (!ValidationUtils.isValidLegalName(values.legalLastName)) { + ErrorUtils.addErrorMessage(errors, 'legalLastName', translate('privatePersonalDetails.error.hasInvalidCharacter')); + } else if (!values.legalLastName) { + errors.legalLastName = translate('common.error.fieldRequired'); + } else if (values.legalLastName.length > CONST.LEGAL_NAME.MAX_LENGTH) { + ErrorUtils.addErrorMessage( + errors, + 'legalLastName', + translate('common.error.characterLimitExceedCounter', {length: values.legalLastName.length, limit: CONST.LEGAL_NAME.MAX_LENGTH}), + ); + } + if (ValidationUtils.doesContainReservedWord(values.legalLastName, CONST.DISPLAY_NAME.RESERVED_NAMES)) { + ErrorUtils.addErrorMessage(errors, 'legalLastName', translate('personalDetails.error.containsReservedWord')); + } } - } - return errors; - }, []); + return errors; + }, + [translate], + ); return ( CONST.TITLE_CHARACTER_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'roomName', ['common.error.characterLimitExceedCounter', {length: values.roomName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); + ErrorUtils.addErrorMessage(errors, 'roomName', translate('common.error.characterLimitExceedCounter', {length: values.roomName.length, limit: CONST.TITLE_CHARACTER_LIMIT})); } return errors; }, - [report, reports], + [report, reports, translate], ); return ( diff --git a/src/pages/settings/Security/CloseAccountPage.tsx b/src/pages/settings/Security/CloseAccountPage.tsx index c9ad13b17e45..1da4436ca810 100644 --- a/src/pages/settings/Security/CloseAccountPage.tsx +++ b/src/pages/settings/Security/CloseAccountPage.tsx @@ -72,7 +72,7 @@ function CloseAccountPage({session}: CloseAccountPageProps) { const errors = ValidationUtils.getFieldRequiredErrors(values, ['phoneOrEmail']); if (values.phoneOrEmail && userEmailOrPhone && sanitizePhoneOrEmail(userEmailOrPhone) !== sanitizePhoneOrEmail(values.phoneOrEmail)) { - errors.phoneOrEmail = 'closeAccountPage.enterYourDefaultContactMethod'; + errors.phoneOrEmail = translate('closeAccountPage.enterYourDefaultContactMethod'); } return errors; }; diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx index ac896353c789..4d46f18c15ea 100644 --- a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx +++ b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx @@ -135,7 +135,7 @@ function CodesStep({account, backTo}: CodesStepProps) { text={translate('common.next')} onPress={() => { if (!account?.codesAreCopied) { - setError('twoFactorAuth.errorStepCodes'); + setError(translate('twoFactorAuth.errorStepCodes')); return; } setStep(CONST.TWO_FACTOR_AUTH_STEPS.VERIFY); diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.tsx b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.tsx index 33484c2aee35..cf226655ce32 100644 --- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.tsx +++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.tsx @@ -3,6 +3,7 @@ import type {ForwardedRef, RefAttributes} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {AutoCompleteVariant, MagicCodeInputHandle} from '@components/MagicCodeInput'; import MagicCodeInput from '@components/MagicCodeInput'; +import useLocalize from '@hooks/useLocalize'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as ValidationUtils from '@libs/ValidationUtils'; import * as Session from '@userActions/Session'; @@ -14,6 +15,7 @@ type BaseTwoFactorAuthFormProps = BaseTwoFactorAuthFormOnyxProps & { }; function BaseTwoFactorAuthForm({account, autoComplete}: BaseTwoFactorAuthFormProps, ref: ForwardedRef) { + const {translate} = useLocalize(); const [formError, setFormError] = useState<{twoFactorAuthCode?: string}>({}); const [twoFactorAuthCode, setTwoFactorAuthCode] = useState(''); const inputRef = useRef(null); @@ -41,18 +43,18 @@ function BaseTwoFactorAuthForm({account, autoComplete}: BaseTwoFactorAuthFormPro inputRef.current.blur(); } if (!twoFactorAuthCode.trim()) { - setFormError({twoFactorAuthCode: 'twoFactorAuthForm.error.pleaseFillTwoFactorAuth'}); + setFormError({twoFactorAuthCode: translate('twoFactorAuthForm.error.pleaseFillTwoFactorAuth')}); return; } if (!ValidationUtils.isValidTwoFactorCode(twoFactorAuthCode)) { - setFormError({twoFactorAuthCode: 'twoFactorAuthForm.error.incorrect2fa'}); + setFormError({twoFactorAuthCode: translate('twoFactorAuthForm.error.incorrect2fa')}); return; } setFormError({}); Session.validateTwoFactorAuth(twoFactorAuthCode); - }, [twoFactorAuthCode]); + }, [twoFactorAuthCode, translate]); useImperativeHandle(ref, () => ({ validateAndSubmitForm() { diff --git a/src/pages/settings/Subscription/SubscriptionSize/substeps/Size.tsx b/src/pages/settings/Subscription/SubscriptionSize/substeps/Size.tsx index 853e12faf3ba..ed42d604181d 100644 --- a/src/pages/settings/Subscription/SubscriptionSize/substeps/Size.tsx +++ b/src/pages/settings/Subscription/SubscriptionSize/substeps/Size.tsx @@ -39,16 +39,16 @@ function Size({onNext}: SizeProps) { (values: FormOnyxValues): FormInputErrors => { const errors = ValidationUtils.getFieldRequiredErrors(values, [INPUT_IDS.SUBSCRIPTION_SIZE]); if (values[INPUT_IDS.SUBSCRIPTION_SIZE] && !ValidationUtils.isValidSubscriptionSize(values[INPUT_IDS.SUBSCRIPTION_SIZE])) { - errors.subscriptionSize = 'subscription.subscriptionSize.error.size'; + errors.subscriptionSize = translate('subscription.subscriptionSize.error.size'); } if (Number(values[INPUT_IDS.SUBSCRIPTION_SIZE]) === privateSubscription?.userCount) { - errors.subscriptionSize = 'subscription.subscriptionSize.error.sameSize'; + errors.subscriptionSize = translate('subscription.subscriptionSize.error.sameSize'); } return errors; }, - [privateSubscription?.userCount], + [privateSubscription?.userCount, translate], ); return ( diff --git a/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx b/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx index 2710cadf94e4..23b694fe0d40 100644 --- a/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx +++ b/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx @@ -105,7 +105,7 @@ function ActivatePhysicalCardPage({ activateCardCodeInputRef.current?.blur(); if (lastFourDigits.replace(CONST.MAGIC_CODE_EMPTY_CHAR, '').length !== LAST_FOUR_DIGITS_LENGTH) { - setFormError('activateCardPage.error.thatDidntMatch'); + setFormError(translate('activateCardPage.error.thatDidntMatch')); return; } if (inactiveCard?.cardID === undefined) { @@ -113,7 +113,7 @@ function ActivatePhysicalCardPage({ } CardSettings.activatePhysicalExpensifyCard(lastFourDigits, inactiveCard?.cardID); - }, [lastFourDigits, inactiveCard?.cardID]); + }, [lastFourDigits, inactiveCard?.cardID, translate]); if (isEmptyObject(inactiveCard)) { return ; diff --git a/src/pages/settings/Wallet/Card/GetPhysicalCardName.tsx b/src/pages/settings/Wallet/Card/GetPhysicalCardName.tsx index 1667aa8d36d3..deaa05350c7f 100644 --- a/src/pages/settings/Wallet/Card/GetPhysicalCardName.tsx +++ b/src/pages/settings/Wallet/Card/GetPhysicalCardName.tsx @@ -43,15 +43,15 @@ function GetPhysicalCardName({ const errors: OnValidateResult = {}; if (values?.legalFirstName && !ValidationUtils.isValidLegalName(values.legalFirstName)) { - errors.legalFirstName = 'privatePersonalDetails.error.hasInvalidCharacter'; + errors.legalFirstName = translate('privatePersonalDetails.error.hasInvalidCharacter'); } else if (!values?.legalFirstName) { - errors.legalFirstName = 'common.error.fieldRequired'; + errors.legalFirstName = translate('common.error.fieldRequired'); } if (values?.legalLastName && !ValidationUtils.isValidLegalName(values.legalLastName)) { - errors.legalLastName = 'privatePersonalDetails.error.hasInvalidCharacter'; + errors.legalLastName = translate('privatePersonalDetails.error.hasInvalidCharacter'); } else if (!values?.legalLastName) { - errors.legalLastName = 'common.error.fieldRequired'; + errors.legalLastName = translate('common.error.fieldRequired'); } return errors; diff --git a/src/pages/settings/Wallet/Card/GetPhysicalCardPhone.tsx b/src/pages/settings/Wallet/Card/GetPhysicalCardPhone.tsx index f709de4b51c3..56d5a29a3203 100644 --- a/src/pages/settings/Wallet/Card/GetPhysicalCardPhone.tsx +++ b/src/pages/settings/Wallet/Card/GetPhysicalCardPhone.tsx @@ -42,9 +42,9 @@ function GetPhysicalCardPhone({ const errors: OnValidateResult = {}; if (!LoginUtils.validateNumber(phoneNumberToValidate)) { - errors.phoneNumber = 'common.error.phoneNumber'; + errors.phoneNumber = translate('common.error.phoneNumber'); } else if (!phoneNumberToValidate) { - errors.phoneNumber = 'common.error.fieldRequired'; + errors.phoneNumber = translate('common.error.fieldRequired'); } return errors; diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.tsx b/src/pages/settings/Wallet/ExpensifyCardPage.tsx index a9b15cc65a22..02bb5dd99687 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage.tsx +++ b/src/pages/settings/Wallet/ExpensifyCardPage.tsx @@ -173,7 +173,7 @@ function ExpensifyCardPage({ )} diff --git a/src/pages/settings/Wallet/ReportCardLostPage.tsx b/src/pages/settings/Wallet/ReportCardLostPage.tsx index 11790bd44cb6..4a84f0294d78 100644 --- a/src/pages/settings/Wallet/ReportCardLostPage.tsx +++ b/src/pages/settings/Wallet/ReportCardLostPage.tsx @@ -183,7 +183,7 @@ function ReportCardLostPage({ @@ -201,7 +201,7 @@ function ReportCardLostPage({ diff --git a/src/pages/signin/LoginForm/BaseLoginForm.tsx b/src/pages/signin/LoginForm/BaseLoginForm.tsx index 85a79a5056bc..1c8084eb12e2 100644 --- a/src/pages/signin/LoginForm/BaseLoginForm.tsx +++ b/src/pages/signin/LoginForm/BaseLoginForm.tsx @@ -32,7 +32,6 @@ import * as CloseAccount from '@userActions/CloseAccount'; import * as Session from '@userActions/Session'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {CloseAccountForm} from '@src/types/form'; import type {Account, Credentials} from '@src/types/onyx'; @@ -60,7 +59,7 @@ function BaseLoginForm({account, credentials, closeAccount, blurOnSubmit = false const {translate} = useLocalize(); const input = useRef(null); const [login, setLogin] = useState(() => Str.removeSMSDomain(credentials?.login ?? '')); - const [formError, setFormError] = useState(); + const [formError, setFormError] = useState(); const prevIsVisible = usePrevious(isVisible); const firstBlurred = useRef(false); const isFocused = useIsFocused(); @@ -74,7 +73,7 @@ function BaseLoginForm({account, credentials, closeAccount, blurOnSubmit = false (value: string) => { const loginTrim = value.trim(); if (!loginTrim) { - setFormError('common.pleaseEnterEmailOrPhoneNumber'); + setFormError(translate('common.pleaseEnterEmailOrPhoneNumber')); return false; } @@ -83,9 +82,9 @@ function BaseLoginForm({account, credentials, closeAccount, blurOnSubmit = false if (!Str.isValidEmail(loginTrim) && !parsedPhoneNumber.possible) { if (ValidationUtils.isNumericWithSpecialChars(loginTrim)) { - setFormError('common.error.phoneNumber'); + setFormError(translate('common.error.phoneNumber')); } else { - setFormError('loginForm.error.invalidFormatEmailLogin'); + setFormError(translate('loginForm.error.invalidFormatEmailLogin')); } return false; } @@ -93,7 +92,7 @@ function BaseLoginForm({account, credentials, closeAccount, blurOnSubmit = false setFormError(undefined); return true; }, - [setFormError], + [setFormError, translate], ); /** @@ -281,7 +280,7 @@ function BaseLoginForm({account, credentials, closeAccount, blurOnSubmit = false style={[styles.mv2]} type="success" // eslint-disable-next-line @typescript-eslint/naming-convention,@typescript-eslint/prefer-nullish-coalescing - messages={{0: closeAccount?.success ? [closeAccount.success, {isTranslated: true}] : account?.message || ''}} + messages={{0: closeAccount?.success ? closeAccount.success : account?.message || ''}} /> )} { diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx index 488d3d48eae9..523c89874f9c 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -303,7 +303,7 @@ function BaseValidateCodeForm({account, credentials, session, autoComplete, isUs onChangeText={(text) => onTextInput(text, 'recoveryCode')} maxLength={CONST.FORM_CHARACTER_LIMIT} label={translate('recoveryCodeForm.recoveryCode')} - errorText={formError?.recoveryCode ?? ''} + errorText={formError?.recoveryCode ? translate(formError?.recoveryCode) : ''} hasError={hasError} onSubmitEditing={validateAndSubmitForm} autoFocus @@ -323,7 +323,7 @@ function BaseValidateCodeForm({account, credentials, session, autoComplete, isUs onChangeText={(text) => onTextInput(text, 'twoFactorAuthCode')} onFulfill={validateAndSubmitForm} maxLength={CONST.TFA_CODE_LENGTH} - errorText={formError?.twoFactorAuthCode ?? ''} + errorText={formError?.twoFactorAuthCode ? translate(formError?.twoFactorAuthCode) : ''} hasError={hasError} autoFocus key="twoFactorAuthCode" @@ -356,7 +356,7 @@ function BaseValidateCodeForm({account, credentials, session, autoComplete, isUs value={validateCode} onChangeText={(text) => onTextInput(text, 'validateCode')} onFulfill={validateAndSubmitForm} - errorText={formError?.validateCode ?? ''} + errorText={formError?.validateCode ? translate(formError?.validateCode) : ''} hasError={hasError} autoFocus key="validateCode" diff --git a/src/pages/tasks/NewTaskDescriptionPage.tsx b/src/pages/tasks/NewTaskDescriptionPage.tsx index ea0e072c101a..82cf87c5ded1 100644 --- a/src/pages/tasks/NewTaskDescriptionPage.tsx +++ b/src/pages/tasks/NewTaskDescriptionPage.tsx @@ -50,7 +50,11 @@ function NewTaskDescriptionPage({task}: NewTaskDescriptionPageProps) { const errors = {}; if (values.taskDescription.length > CONST.DESCRIPTION_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'taskDescription', ['common.error.characterLimitExceedCounter', {length: values.taskDescription.length, limit: CONST.DESCRIPTION_LIMIT}]); + ErrorUtils.addErrorMessage( + errors, + 'taskDescription', + translate('common.error.characterLimitExceedCounter', {length: values.taskDescription.length, limit: CONST.DESCRIPTION_LIMIT}), + ); } return errors; diff --git a/src/pages/tasks/NewTaskDetailsPage.tsx b/src/pages/tasks/NewTaskDetailsPage.tsx index 821e2fcc1af3..64e1025dd7ae 100644 --- a/src/pages/tasks/NewTaskDetailsPage.tsx +++ b/src/pages/tasks/NewTaskDetailsPage.tsx @@ -57,12 +57,16 @@ function NewTaskDetailsPage({task}: NewTaskDetailsPageProps) { if (!values.taskTitle) { // We error if the user doesn't enter a task name - ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); + ErrorUtils.addErrorMessage(errors, 'taskTitle', translate('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}]); + ErrorUtils.addErrorMessage(errors, 'taskTitle', translate('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}]); + ErrorUtils.addErrorMessage( + errors, + 'taskDescription', + translate('common.error.characterLimitExceedCounter', {length: values.taskDescription.length, limit: CONST.DESCRIPTION_LIMIT}), + ); } return errors; diff --git a/src/pages/tasks/NewTaskPage.tsx b/src/pages/tasks/NewTaskPage.tsx index 96063c8b4381..ceb1670f6cc4 100644 --- a/src/pages/tasks/NewTaskPage.tsx +++ b/src/pages/tasks/NewTaskPage.tsx @@ -99,17 +99,17 @@ function NewTaskPage({task, reports, personalDetails}: NewTaskPageProps) { // the response const onSubmit = () => { if (!task?.title && !task?.shareDestination) { - setErrorMessage('newTaskPage.confirmError'); + setErrorMessage(translate('newTaskPage.confirmError')); return; } if (!task.title) { - setErrorMessage('newTaskPage.pleaseEnterTaskName'); + setErrorMessage(translate('newTaskPage.pleaseEnterTaskName')); return; } if (!task.shareDestination) { - setErrorMessage('newTaskPage.pleaseEnterTaskDestination'); + setErrorMessage(translate('newTaskPage.pleaseEnterTaskDestination')); return; } diff --git a/src/pages/tasks/NewTaskTitlePage.tsx b/src/pages/tasks/NewTaskTitlePage.tsx index 582d2a5c6500..cdc9fc27596a 100644 --- a/src/pages/tasks/NewTaskTitlePage.tsx +++ b/src/pages/tasks/NewTaskTitlePage.tsx @@ -40,9 +40,9 @@ function NewTaskTitlePage({task}: NewTaskTitlePageProps) { if (!values.taskTitle) { // We error if the user doesn't enter a task name - ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); + ErrorUtils.addErrorMessage(errors, 'taskTitle', translate('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}]); + ErrorUtils.addErrorMessage(errors, 'taskTitle', translate('common.error.characterLimitExceedCounter', {length: values.taskTitle.length, limit: CONST.TITLE_CHARACTER_LIMIT})); } return errors; diff --git a/src/pages/tasks/TaskDescriptionPage.tsx b/src/pages/tasks/TaskDescriptionPage.tsx index 7b3dd8813540..bfed61c805e0 100644 --- a/src/pages/tasks/TaskDescriptionPage.tsx +++ b/src/pages/tasks/TaskDescriptionPage.tsx @@ -33,15 +33,18 @@ function TaskDescriptionPage({report, currentUserPersonalDetails}: TaskDescripti const styles = useThemeStyles(); const {translate} = useLocalize(); - const validate = useCallback((values: FormOnyxValues): FormInputErrors => { - const errors = {}; + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors = {}; - if (values?.description && values.description?.length > CONST.DESCRIPTION_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'description', ['common.error.characterLimitExceedCounter', {length: values.description.length, limit: CONST.DESCRIPTION_LIMIT}]); - } + if (values?.description && values.description?.length > CONST.DESCRIPTION_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'description', translate('common.error.characterLimitExceedCounter', {length: values.description.length, limit: CONST.DESCRIPTION_LIMIT})); + } - return errors; - }, []); + return errors; + }, + [translate], + ); const submit = useCallback( (values: FormOnyxValues) => { diff --git a/src/pages/tasks/TaskTitlePage.tsx b/src/pages/tasks/TaskTitlePage.tsx index 99558efaeb03..e99b0b3da67a 100644 --- a/src/pages/tasks/TaskTitlePage.tsx +++ b/src/pages/tasks/TaskTitlePage.tsx @@ -29,17 +29,20 @@ function TaskTitlePage({report, currentUserPersonalDetails}: TaskTitlePageProps) const styles = useThemeStyles(); const {translate} = useLocalize(); - const validate = useCallback(({title}: FormOnyxValues): FormInputErrors => { - const errors: FormInputErrors = {}; + const validate = useCallback( + ({title}: FormOnyxValues): FormInputErrors => { + const errors: FormInputErrors = {}; - if (!title) { - ErrorUtils.addErrorMessage(errors, INPUT_IDS.TITLE, 'newTaskPage.pleaseEnterTaskName'); - } else if (title.length > CONST.TITLE_CHARACTER_LIMIT) { - ErrorUtils.addErrorMessage(errors, INPUT_IDS.TITLE, ['common.error.characterLimitExceedCounter', {length: title.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); - } + if (!title) { + ErrorUtils.addErrorMessage(errors, INPUT_IDS.TITLE, translate('newTaskPage.pleaseEnterTaskName')); + } else if (title.length > CONST.TITLE_CHARACTER_LIMIT) { + ErrorUtils.addErrorMessage(errors, INPUT_IDS.TITLE, translate('common.error.characterLimitExceedCounter', {length: title.length, limit: CONST.TITLE_CHARACTER_LIMIT})); + } - return errors; - }, []); + return errors; + }, + [translate], + ); const submit = useCallback( (values: FormOnyxValues) => { diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index 9805248994f9..9bab92bc38b0 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -127,7 +127,7 @@ function WorkspaceInviteMessagePage({ const validate = (): FormInputErrors => { const errorFields: FormInputErrors = {}; if (isEmptyObject(invitedEmailsToAccountIDsDraft)) { - errorFields.welcomeMessage = 'workspace.inviteMessage.inviteNoMembersError'; + errorFields.welcomeMessage = translate('workspace.inviteMessage.inviteNoMembersError'); } return errorFields; }; diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index 6da5d220504f..29875b0da811 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -278,7 +278,7 @@ function WorkspaceInvitePage({route, betas, invitedEmailsToAccountIDsDraft, poli isAlertVisible={shouldShowAlertPrompt} buttonText={translate('common.next')} onSubmit={inviteUser} - message={[policy?.alertMessage ?? '', {isTranslated: true}]} + message={policy?.alertMessage ?? ''} containerStyles={[styles.flexReset, styles.flexGrow0, styles.flexShrink0, styles.flexBasisAuto]} enabledWhenOffline disablePressOnEnter diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 96f5a9eb461f..6ed851c70f4e 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -409,7 +409,7 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft, Policy.dismissAddedWithPrimaryLoginMessages(policyID)} /> diff --git a/src/pages/workspace/WorkspaceNamePage.tsx b/src/pages/workspace/WorkspaceNamePage.tsx index b68b2ca2f944..d9632a1a2ae8 100644 --- a/src/pages/workspace/WorkspaceNamePage.tsx +++ b/src/pages/workspace/WorkspaceNamePage.tsx @@ -38,20 +38,23 @@ function WorkspaceNamePage({policy}: Props) { [policy], ); - const validate = useCallback((values: FormOnyxValues) => { - const errors: FormInputErrors = {}; - const name = values.name.trim(); + const validate = useCallback( + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; + const name = values.name.trim(); - if (!ValidationUtils.isRequiredFulfilled(name)) { - errors.name = 'workspace.editor.nameIsRequiredError'; - } 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. - ErrorUtils.addErrorMessage(errors, 'name', ['common.error.characterLimitExceedCounter', {length: [...name].length, limit: CONST.TITLE_CHARACTER_LIMIT}]); - } + if (!ValidationUtils.isRequiredFulfilled(name)) { + errors.name = translate('workspace.editor.nameIsRequiredError'); + } 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. + ErrorUtils.addErrorMessage(errors, 'name', translate('common.error.characterLimitExceedCounter', {length: [...name].length, limit: CONST.TITLE_CHARACTER_LIMIT})); + } - return errors; - }, []); + return errors; + }, + [translate], + ); return ( CONST.TITLE_CHARACTER_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'roomName', ['common.error.characterLimitExceedCounter', {length: values.roomName.length, limit: CONST.TITLE_CHARACTER_LIMIT}]); + ErrorUtils.addErrorMessage(errors, 'roomName', translate('common.error.characterLimitExceedCounter', {length: values.roomName.length, limit: CONST.TITLE_CHARACTER_LIMIT})); } const descriptionLength = ReportUtils.getCommentLength(values.reportDescription); if (descriptionLength > CONST.REPORT_DESCRIPTION.MAX_LENGTH) { - ErrorUtils.addErrorMessage(errors, 'reportDescription', [ - 'common.error.characterLimitExceedCounter', - {length: descriptionLength, limit: CONST.REPORT_DESCRIPTION.MAX_LENGTH}, - ]); + ErrorUtils.addErrorMessage( + errors, + 'reportDescription', + translate('common.error.characterLimitExceedCounter', {length: descriptionLength, limit: CONST.REPORT_DESCRIPTION.MAX_LENGTH}), + ); } if (!values.policyID) { - errors.policyID = 'newRoomPage.pleaseSelectWorkspace'; + errors.policyID = translate('newRoomPage.pleaseSelectWorkspace'); } return errors; }, - [reports], + [reports, translate], ); const writeCapabilityOptions = useMemo( diff --git a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx index 4c3311b079b0..54dcfd62ac44 100644 --- a/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx +++ b/src/pages/workspace/WorkspaceProfileDescriptionPage.tsx @@ -46,15 +46,18 @@ function WorkspaceProfileDescriptionPage({policy}: Props) { * @param {Object} values - form input values passed by the Form component * @returns {Boolean} */ - const validate = useCallback((values: FormOnyxValues) => { - const errors = {}; + const validate = useCallback( + (values: FormOnyxValues) => { + const errors = {}; - if (values.description.length > CONST.DESCRIPTION_LIMIT) { - ErrorUtils.addErrorMessage(errors, 'description', ['common.error.characterLimitExceedCounter', {length: values.description.length, limit: CONST.DESCRIPTION_LIMIT}]); - } + if (values.description.length > CONST.DESCRIPTION_LIMIT) { + ErrorUtils.addErrorMessage(errors, 'description', translate('common.error.characterLimitExceedCounter', {length: values.description.length, limit: CONST.DESCRIPTION_LIMIT})); + } - return errors; - }, []); + return errors; + }, + [translate], + ); const submit = useCallback( (values: FormOnyxValues) => { diff --git a/src/pages/workspace/categories/CategoryForm.tsx b/src/pages/workspace/categories/CategoryForm.tsx index dc372dd3540f..efe457729e36 100644 --- a/src/pages/workspace/categories/CategoryForm.tsx +++ b/src/pages/workspace/categories/CategoryForm.tsx @@ -40,19 +40,23 @@ function CategoryForm({onSubmit, policyCategories, categoryName, validateEdit}: const newCategoryName = values.categoryName.trim(); if (!ValidationUtils.isRequiredFulfilled(newCategoryName)) { - errors.categoryName = 'workspace.categories.categoryRequiredError'; + errors.categoryName = translate('workspace.categories.categoryRequiredError'); } else if (policyCategories?.[newCategoryName]) { - errors.categoryName = 'workspace.categories.existingCategoryError'; + errors.categoryName = translate('workspace.categories.existingCategoryError'); } else if (newCategoryName === CONST.INVALID_CATEGORY_NAME) { - errors.categoryName = 'workspace.categories.invalidCategoryName'; + errors.categoryName = translate('workspace.categories.invalidCategoryName'); } else if ([...newCategoryName].length > CONST.CATEGORY_NAME_LIMIT) { // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 code units. - ErrorUtils.addErrorMessage(errors, 'categoryName', ['common.error.characterLimitExceedCounter', {length: [...newCategoryName].length, limit: CONST.CATEGORY_NAME_LIMIT}]); + ErrorUtils.addErrorMessage( + errors, + 'categoryName', + translate('common.error.characterLimitExceedCounter', {length: [...newCategoryName].length, limit: CONST.CATEGORY_NAME_LIMIT}), + ); } return errors; }, - [policyCategories], + [policyCategories, translate], ); const submit = useCallback( diff --git a/src/pages/workspace/categories/EditCategoryPage.tsx b/src/pages/workspace/categories/EditCategoryPage.tsx index 7b37375272d2..224233fff318 100644 --- a/src/pages/workspace/categories/EditCategoryPage.tsx +++ b/src/pages/workspace/categories/EditCategoryPage.tsx @@ -37,14 +37,14 @@ function EditCategoryPage({route, policyCategories}: EditCategoryPageProps) { const newCategoryName = values.categoryName.trim(); if (!newCategoryName) { - errors.categoryName = 'workspace.categories.categoryRequiredError'; + errors.categoryName = translate('workspace.categories.categoryRequiredError'); } else if (policyCategories?.[newCategoryName] && currentCategoryName !== newCategoryName) { - errors.categoryName = 'workspace.categories.existingCategoryError'; + errors.categoryName = translate('workspace.categories.existingCategoryError'); } return errors; }, - [policyCategories, currentCategoryName], + [policyCategories, currentCategoryName, translate], ); const editCategory = useCallback( diff --git a/src/pages/workspace/tags/EditTagPage.tsx b/src/pages/workspace/tags/EditTagPage.tsx index 06f8f5853aa5..bdeaa4ec2b21 100644 --- a/src/pages/workspace/tags/EditTagPage.tsx +++ b/src/pages/workspace/tags/EditTagPage.tsx @@ -43,14 +43,14 @@ function EditTagPage({route, policyTags}: EditTagPageProps) { const tagName = values.tagName.trim(); const {tags} = PolicyUtils.getTagList(policyTags, route.params.orderWeight); if (!ValidationUtils.isRequiredFulfilled(tagName)) { - errors.tagName = 'workspace.tags.tagRequiredError'; + errors.tagName = translate('workspace.tags.tagRequiredError'); } else if (tags?.[tagName] && currentTagName !== tagName) { - errors.tagName = 'workspace.tags.existingTagError'; + errors.tagName = translate('workspace.tags.existingTagError'); } return errors; }, - [route.params.orderWeight, currentTagName, policyTags], + [policyTags, route.params.orderWeight, currentTagName, translate], ); const editTag = useCallback( diff --git a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx index 0ed373f135e4..1214507480ae 100644 --- a/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx +++ b/src/pages/workspace/tags/WorkspaceCreateTagPage.tsx @@ -44,17 +44,17 @@ function CreateTagPage({route, policyTags}: CreateTagPageProps) { const {tags} = PolicyUtils.getTagList(policyTags, 0); if (!ValidationUtils.isRequiredFulfilled(tagName)) { - errors.tagName = 'workspace.tags.tagRequiredError'; + errors.tagName = translate('workspace.tags.tagRequiredError'); } else if (tags?.[tagName]) { - errors.tagName = 'workspace.tags.existingTagError'; + errors.tagName = translate('workspace.tags.existingTagError'); } else if ([...tagName].length > CONST.TAG_NAME_LIMIT) { // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 code units. - ErrorUtils.addErrorMessage(errors, 'tagName', ['common.error.characterLimitExceedCounter', {length: [...tagName].length, limit: CONST.TAG_NAME_LIMIT}]); + ErrorUtils.addErrorMessage(errors, 'tagName', translate('common.error.characterLimitExceedCounter', {length: [...tagName].length, limit: CONST.TAG_NAME_LIMIT})); } return errors; }, - [policyTags], + [policyTags, translate], ); const createTag = useCallback( diff --git a/src/pages/workspace/tags/WorkspaceEditTagsPage.tsx b/src/pages/workspace/tags/WorkspaceEditTagsPage.tsx index 6adf42c2376b..c081095783df 100644 --- a/src/pages/workspace/tags/WorkspaceEditTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceEditTagsPage.tsx @@ -30,20 +30,23 @@ type WorkspaceEditTagsPageOnyxProps = { type WorkspaceEditTagsPageProps = WorkspaceEditTagsPageOnyxProps & StackScreenProps; -const validateTagName = (values: FormOnyxValues) => { - const errors: FormInputErrors = {}; - if (!values[INPUT_IDS.POLICY_TAGS_NAME] && values[INPUT_IDS.POLICY_TAGS_NAME].trim() === '') { - errors[INPUT_IDS.POLICY_TAGS_NAME] = 'common.error.fieldRequired'; - } - return errors; -}; - function WorkspaceEditTagsPage({route, policyTags}: WorkspaceEditTagsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const taglistName = useMemo(() => PolicyUtils.getTagListName(policyTags, route.params.orderWeight), [policyTags, route.params.orderWeight]); const {inputCallbackRef} = useAutoFocusInput(); + const validateTagName = useCallback( + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; + if (!values[INPUT_IDS.POLICY_TAGS_NAME] && values[INPUT_IDS.POLICY_TAGS_NAME].trim() === '') { + errors[INPUT_IDS.POLICY_TAGS_NAME] = translate('common.error.fieldRequired'); + } + return errors; + }, + [translate], + ); + const updateTaglistName = useCallback( (values: FormOnyxValues) => { if (values[INPUT_IDS.POLICY_TAGS_NAME] !== taglistName) { diff --git a/src/pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName.tsx b/src/pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName.tsx index dbade9a82aa2..f24a388011ab 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesSettingsCustomTaxName.tsx @@ -36,16 +36,19 @@ function WorkspaceTaxesSettingsCustomTaxName({ const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); - const validate = useCallback((values: FormOnyxValues) => { - const errors: FormInputErrors = {}; - const customTaxName = values[INPUT_IDS.NAME]; + const validate = useCallback( + (values: FormOnyxValues) => { + const errors: FormInputErrors = {}; + const customTaxName = values[INPUT_IDS.NAME]; - if (!ValidationUtils.isRequiredFulfilled(customTaxName)) { - errors.name = 'workspace.taxes.error.customNameRequired'; - } + if (!ValidationUtils.isRequiredFulfilled(customTaxName)) { + errors.name = translate('workspace.taxes.error.customNameRequired'); + } - return errors; - }, []); + return errors; + }, + [translate], + ); const submit = ({name}: WorkspaceTaxCustomName) => { setPolicyCustomTaxName(policyID, name); diff --git a/src/stories/Form.stories.tsx b/src/stories/Form.stories.tsx index f4e89f6766f0..ab29612b0556 100644 --- a/src/stories/Form.stories.tsx +++ b/src/stories/Form.stories.tsx @@ -12,7 +12,6 @@ import Picker from '@components/Picker'; import StateSelector from '@components/StateSelector'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; -import type {MaybePhraseKey} from '@libs/Localize'; import NetworkConnection from '@libs/NetworkConnection'; import * as ValidationUtils from '@libs/ValidationUtils'; import * as FormActions from '@userActions/FormActions'; @@ -58,7 +57,7 @@ function Template(props: FormProviderProps) { FormActions.setDraftValues(props.formID, props.draftValues); if (props.formState?.error) { - FormActions.setErrors(props.formID, {error: props.formState.error as MaybePhraseKey}); + FormActions.setErrors(props.formID, {error: props.formState.error as string}); } else { FormActions.clearErrors(props.formID); } @@ -172,7 +171,7 @@ function WithNativeEventHandler(props: FormProviderProps) { FormActions.setDraftValues(props.formID, props.draftValues); if (props.formState?.error) { - FormActions.setErrors(props.formID, {error: props.formState.error as MaybePhraseKey}); + FormActions.setErrors(props.formID, {error: props.formState.error as string}); } else { FormActions.clearErrors(props.formID); } diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts index 688e2ef73ff8..ee60b6dbf1fd 100644 --- a/src/types/onyx/OnyxCommon.ts +++ b/src/types/onyx/OnyxCommon.ts @@ -1,5 +1,4 @@ import type {ValueOf} from 'type-fest'; -import type {MaybePhraseKey} from '@libs/Localize'; import type {AvatarSource} from '@libs/UserUtils'; import type CONST from '@src/CONST'; @@ -25,7 +24,7 @@ type OnyxValueWithOfflineFeedback = keyof TO type ErrorFields = Record; /** Mapping of form fields with error translation keys and variables */ -type Errors = Record; +type Errors = Record; /** * Types of avatars diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index fd5b7c62e6bb..4167d247a953 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -10,6 +10,7 @@ import * as Report from '@src/libs/actions/Report'; import * as ReportActions from '@src/libs/actions/ReportActions'; import * as User from '@src/libs/actions/User'; import DateUtils from '@src/libs/DateUtils'; +import * as Localize from '@src/libs/Localize'; import * as NumberUtils from '@src/libs/NumberUtils'; import * as PersonalDetailsUtils from '@src/libs/PersonalDetailsUtils'; import * as ReportActionsUtils from '@src/libs/ReportActionsUtils'; @@ -765,7 +766,7 @@ describe('actions/IOU', () => { Onyx.disconnect(connectionID); expect(transaction?.pendingAction).toBeFalsy(); expect(transaction?.errors).toBeTruthy(); - expect(Object.values(transaction?.errors ?? {})[0]).toEqual(expect.arrayContaining(['iou.error.genericCreateFailureMessage', {isTranslated: false}])); + expect(Object.values(transaction?.errors ?? {})[0]).toEqual(Localize.translateLocal('iou.error.genericCreateFailureMessage')); resolve(); }, }); @@ -1838,7 +1839,7 @@ describe('actions/IOU', () => { Onyx.disconnect(connectionID); const updatedAction = Object.values(allActions ?? {}).find((reportAction) => !isEmptyObject(reportAction)); expect(updatedAction?.actionName).toEqual('MODIFIEDEXPENSE'); - expect(Object.values(updatedAction?.errors ?? {})).toEqual(expect.arrayContaining([['iou.error.genericEditFailureMessage', {isTranslated: false}]])); + expect(Object.values(updatedAction?.errors ?? {})[0]).toEqual(Localize.translateLocal('iou.error.genericEditFailureMessage')); resolve(); }, }); @@ -2060,7 +2061,7 @@ describe('actions/IOU', () => { callback: (allActions) => { Onyx.disconnect(connectionID); const erroredAction = Object.values(allActions ?? {}).find((action) => !isEmptyObject(action?.errors)); - expect(Object.values(erroredAction?.errors ?? {})).toEqual(expect.arrayContaining([['iou.error.other', {isTranslated: false}]])); + expect(Object.values(erroredAction?.errors ?? {})[0]).toEqual(Localize.translateLocal('iou.error.other')); resolve(); }, }); diff --git a/tests/unit/ErrorUtilsTest.ts b/tests/unit/ErrorUtilsTest.ts index 9168c1ca12a5..f5517c56156a 100644 --- a/tests/unit/ErrorUtilsTest.ts +++ b/tests/unit/ErrorUtilsTest.ts @@ -6,21 +6,21 @@ describe('ErrorUtils', () => { const errors: Errors = {}; ErrorUtils.addErrorMessage(errors, 'username', 'Username cannot be empty'); - expect(errors).toEqual({username: ['Username cannot be empty', {isTranslated: true}]}); + expect(errors).toEqual({username: 'Username cannot be empty'}); }); test('should append an error message to an existing error message for a given inputID', () => { const errors: Errors = {username: 'Username cannot be empty'}; ErrorUtils.addErrorMessage(errors, 'username', 'Username must be at least 6 characters long'); - expect(errors).toEqual({username: ['Username cannot be empty\nUsername must be at least 6 characters long', {isTranslated: true}]}); + expect(errors).toEqual({username: 'Username cannot be empty\nUsername must be at least 6 characters long'}); }); test('should add an error to input which does not contain any errors yet', () => { const errors: Errors = {username: 'Username cannot be empty'}; ErrorUtils.addErrorMessage(errors, 'password', 'Password cannot be empty'); - expect(errors).toEqual({username: 'Username cannot be empty', password: ['Password cannot be empty', {isTranslated: true}]}); + expect(errors).toEqual({username: 'Username cannot be empty', password: 'Password cannot be empty'}); }); test('should not mutate the errors object when message is empty', () => { @@ -50,7 +50,7 @@ describe('ErrorUtils', () => { ErrorUtils.addErrorMessage(errors, 'username', 'Username must be at least 6 characters long'); ErrorUtils.addErrorMessage(errors, 'username', 'Username must contain at least one letter'); - expect(errors).toEqual({username: ['Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter', {isTranslated: true}]}); + expect(errors).toEqual({username: 'Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter'}); }); test('should append multiple error messages to an existing error message for the same inputID', () => { @@ -59,10 +59,7 @@ describe('ErrorUtils', () => { ErrorUtils.addErrorMessage(errors, 'username', 'Username must not contain special characters'); expect(errors).toEqual({ - username: [ - 'Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter\nUsername must not contain special characters', - {isTranslated: true}, - ], + username: 'Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter\nUsername must not contain special characters', }); }); }); diff --git a/tests/unit/ValidationUtilsTest.ts b/tests/unit/ValidationUtilsTest.ts index fc5dacee2cf2..3bd083bc07e4 100644 --- a/tests/unit/ValidationUtilsTest.ts +++ b/tests/unit/ValidationUtilsTest.ts @@ -1,4 +1,5 @@ import {addDays, format, startOfDay, subYears} from 'date-fns'; +import * as Localize from '@libs/Localize'; import CONST from '@src/CONST'; import * as ValidationUtils from '@src/libs/ValidationUtils'; @@ -186,19 +187,23 @@ describe('ValidationUtils', () => { test('Should return an error message for a date before the minimum age requirement', () => { const invalidDate: string = format(subYears(new Date(), 17), CONST.DATE.FNS_FORMAT_STRING); // Date of birth 17 years ago const error = ValidationUtils.getAgeRequirementError(invalidDate, 18, 150); - expect(error).toEqual(['privatePersonalDetails.error.dateShouldBeBefore', {dateString: format(startOfDay(subYears(new Date(), 18)), CONST.DATE.FNS_FORMAT_STRING)}]); + expect(error).toEqual( + Localize.translateLocal('privatePersonalDetails.error.dateShouldBeBefore', {dateString: format(startOfDay(subYears(new Date(), 18)), CONST.DATE.FNS_FORMAT_STRING)}), + ); }); test('Should return an error message for a date after the maximum age requirement', () => { const invalidDate: string = format(subYears(new Date(), 160), CONST.DATE.FNS_FORMAT_STRING); // Date of birth 160 years ago const error = ValidationUtils.getAgeRequirementError(invalidDate, 18, 150); - expect(error).toEqual(['privatePersonalDetails.error.dateShouldBeAfter', {dateString: format(startOfDay(subYears(new Date(), 150)), CONST.DATE.FNS_FORMAT_STRING)}]); + expect(error).toEqual( + Localize.translateLocal('privatePersonalDetails.error.dateShouldBeAfter', {dateString: format(startOfDay(subYears(new Date(), 150)), CONST.DATE.FNS_FORMAT_STRING)}), + ); }); test('Should return an error message for an invalid date', () => { const invalidDate = '2023-07-32'; // Invalid date const error = ValidationUtils.getAgeRequirementError(invalidDate, 18, 150); - expect(error).toBe('common.error.dateInvalid'); + expect(error).toBe(Localize.translateLocal('common.error.dateInvalid')); }); });