diff --git a/src/libs/ErrorUtils.js b/src/libs/ErrorUtils.js deleted file mode 100644 index 95bbad5f5409..000000000000 --- a/src/libs/ErrorUtils.js +++ /dev/null @@ -1,135 +0,0 @@ -import _ from 'underscore'; -import lodashGet from 'lodash/get'; -import CONST from '../CONST'; -import DateUtils from './DateUtils'; -import * as Localize from './Localize'; - -/** - * @param {Object} response - * @param {Number} response.jsonCode - * @param {String} response.message - * @returns {String} - */ -function getAuthenticateErrorMessage(response) { - switch (response.jsonCode) { - case CONST.JSON_CODE.UNABLE_TO_RETRY: - return 'session.offlineMessageRetry'; - case 401: - return 'passwordForm.error.incorrectLoginOrPassword'; - case 402: - // If too few characters are passed as the password, the WAF will pass it to the API as an empty - // string, which results in a 402 error from Auth. - if (response.message === '402 Missing partnerUserSecret') { - return 'passwordForm.error.incorrectLoginOrPassword'; - } - return 'passwordForm.error.twoFactorAuthenticationEnabled'; - case 403: - if (response.message === 'Invalid code') { - return 'passwordForm.error.incorrect2fa'; - } - return 'passwordForm.error.invalidLoginOrPassword'; - case 404: - return 'passwordForm.error.unableToResetPassword'; - case 405: - return 'passwordForm.error.noAccess'; - case 413: - return 'passwordForm.error.accountLocked'; - default: - return 'passwordForm.error.fallback'; - } -} - -/** - * Method used to get an error object with microsecond as the key. - * @param {String} error - error key or message to be saved - * @return {Object} - * - */ -function getMicroSecondOnyxError(error) { - return {[DateUtils.getMicroseconds()]: error}; -} - -/** - * @param {Object} onyxData - * @param {Object} onyxData.errors - * @returns {String} - */ -function getLatestErrorMessage(onyxData) { - if (_.isEmpty(onyxData.errors)) { - return ''; - } - return _.chain(onyxData.errors || []) - .keys() - .sortBy() - .reverse() - .map((key) => onyxData.errors[key]) - .first() - .value(); -} - -/** - * @param {Object} onyxData - * @param {Object} onyxData.errorFields - * @param {String} fieldName - * @returns {Object} - */ -function getLatestErrorField(onyxData, fieldName) { - const errorsForField = lodashGet(onyxData, ['errorFields', fieldName], {}); - - if (_.isEmpty(errorsForField)) { - return {}; - } - return _.chain(errorsForField) - .keys() - .sortBy() - .reverse() - .map((key) => ({[key]: errorsForField[key]})) - .first() - .value(); -} - -/** - * @param {Object} onyxData - * @param {Object} onyxData.errorFields - * @param {String} fieldName - * @returns {Object} - */ -function getEarliestErrorField(onyxData, fieldName) { - const errorsForField = lodashGet(onyxData, ['errorFields', fieldName], {}); - - if (_.isEmpty(errorsForField)) { - return {}; - } - return _.chain(errorsForField) - .keys() - .sortBy() - .map((key) => ({[key]: errorsForField[key]})) - .first() - .value(); -} - -/** - * Method used to generate error message for given inputID - * @param {Object} errors - An object containing current errors in the form - * @param {String} inputID - * @param {String|Array} message - Message to assign to the inputID errors - * - */ -function addErrorMessage(errors, inputID, message) { - if (!message || !inputID) { - return; - } - - const errorList = errors; - const translatedMessage = Localize.translateIfPhraseKey(message); - - if (_.isEmpty(errorList[inputID])) { - errorList[inputID] = [translatedMessage, {isTranslated: true}]; - } else if (_.isString(errorList[inputID])) { - errorList[inputID] = [`${errorList[inputID]}\n${translatedMessage}`, {isTranslated: true}]; - } else { - errorList[inputID][0] = `${errorList[inputID][0]}\n${translatedMessage}`; - } -} - -export {getAuthenticateErrorMessage, getMicroSecondOnyxError, getLatestErrorMessage, getLatestErrorField, getEarliestErrorField, addErrorMessage}; diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts new file mode 100644 index 000000000000..bf4fc0d810a4 --- /dev/null +++ b/src/libs/ErrorUtils.ts @@ -0,0 +1,114 @@ +import CONST from '../CONST'; +import DateUtils from './DateUtils'; +import * as Localize from './Localize'; +import Response from '../types/onyx/Response'; +import {ErrorFields, Errors} from '../types/onyx/OnyxCommon'; +import {TranslationFlatObject} from '../languages/types'; + +function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatObject { + switch (response.jsonCode) { + case CONST.JSON_CODE.UNABLE_TO_RETRY: + return 'session.offlineMessageRetry'; + case 401: + return 'passwordForm.error.incorrectLoginOrPassword'; + case 402: + // If too few characters are passed as the password, the WAF will pass it to the API as an empty + // string, which results in a 402 error from Auth. + if (response.message === '402 Missing partnerUserSecret') { + return 'passwordForm.error.incorrectLoginOrPassword'; + } + return 'passwordForm.error.twoFactorAuthenticationEnabled'; + case 403: + if (response.message === 'Invalid code') { + return 'passwordForm.error.incorrect2fa'; + } + return 'passwordForm.error.invalidLoginOrPassword'; + case 404: + return 'passwordForm.error.unableToResetPassword'; + case 405: + return 'passwordForm.error.noAccess'; + case 413: + return 'passwordForm.error.accountLocked'; + default: + return 'passwordForm.error.fallback'; + } +} + +/** + * Method used to get an error object with microsecond as the key. + * @param error - error key or message to be saved + */ +function getMicroSecondOnyxError(error: string): Record { + return {[DateUtils.getMicroseconds()]: error}; +} + +type OnyxDataWithErrors = { + errors?: Errors; +}; + +function getLatestErrorMessage(onyxData: TOnyxData): string { + const errors = onyxData.errors ?? {}; + + if (Object.keys(errors).length === 0) { + return ''; + } + + const key = Object.keys(errors).sort().reverse()[0]; + + return errors[key]; +} + +type OnyxDataWithErrorFields = { + errorFields?: ErrorFields; +}; + +function getLatestErrorField(onyxData: TOnyxData, fieldName: string): Record { + const errorsForField = onyxData.errorFields?.[fieldName] ?? {}; + + if (Object.keys(errorsForField).length === 0) { + return {}; + } + + const key = Object.keys(errorsForField).sort().reverse()[0]; + + return {[key]: errorsForField[key]}; +} + +function getEarliestErrorField(onyxData: TOnyxData, fieldName: string): Record { + const errorsForField = onyxData.errorFields?.[fieldName] ?? {}; + + if (Object.keys(errorsForField).length === 0) { + return {}; + } + + const key = Object.keys(errorsForField).sort()[0]; + + return {[key]: errorsForField[key]}; +} + +type ErrorsList = Record; + +/** + * Method used to generate error message for given inputID + * @param errorList - An object containing current errors in the form + * @param message - Message to assign to the inputID errors + */ +function addErrorMessage(errors: ErrorsList, inputID?: string, message?: string) { + if (!message || !inputID) { + return; + } + + const errorList = errors; + const error = errorList[inputID]; + const translatedMessage = Localize.translateIfPhraseKey(message); + + if (!error) { + errorList[inputID] = [translatedMessage, {isTranslated: true}]; + } else if (typeof error === 'string') { + errorList[inputID] = [`${error}\n${translatedMessage}`, {isTranslated: true}]; + } else if (Array.isArray(error)) { + error[0] = `${error[0]}\n${translatedMessage}`; + } +} + +export {getAuthenticateErrorMessage, getMicroSecondOnyxError, getLatestErrorMessage, getLatestErrorField, getEarliestErrorField, addErrorMessage}; diff --git a/src/types/onyx/Response.ts b/src/types/onyx/Response.ts index c501034e971c..255ac6d9bae4 100644 --- a/src/types/onyx/Response.ts +++ b/src/types/onyx/Response.ts @@ -3,9 +3,10 @@ import {OnyxUpdate} from 'react-native-onyx'; type Response = { previousUpdateID?: number | string; lastUpdateID?: number | string; - jsonCode?: number; + jsonCode?: number | string; onyxData?: OnyxUpdate[]; requestID?: string; + message?: string; }; export default Response;