From 894f2327aa121034a7891e316c18cfa6c8f94278 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Thu, 21 Sep 2023 09:27:17 +0200 Subject: [PATCH 01/15] [TS migration] Migrate 'PersonalDetailsUtils.js' lib to TypeScript --- ...etailsUtils.js => PersonalDetailsUtils.ts} | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) rename src/libs/{PersonalDetailsUtils.js => PersonalDetailsUtils.ts} (84%) diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.ts similarity index 84% rename from src/libs/PersonalDetailsUtils.js rename to src/libs/PersonalDetailsUtils.ts index a401dea4b911..76d966ecf027 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.ts @@ -5,6 +5,9 @@ import ONYXKEYS from '../ONYXKEYS'; import * as Localize from './Localize'; import * as UserUtils from './UserUtils'; import * as LocalePhoneNumber from './LocalePhoneNumber'; +import * as OnyxTypes from '../types/onyx'; + +type PersonalDetailsList = Record; let personalDetails = []; let allPersonalDetails = {}; @@ -17,12 +20,9 @@ Onyx.connect({ }); /** - * @param {Object} passedPersonalDetails - * @param {Array} pathToDisplayName - * @param {String} [defaultValue] optional default display name value - * @returns {String} + * @param [defaultValue] optional default display name value */ -function getDisplayNameOrDefault(passedPersonalDetails, pathToDisplayName, defaultValue) { +function getDisplayNameOrDefault(passedPersonalDetails: unknown, pathToDisplayName: string[], defaultValue: string): string { const displayName = lodashGet(passedPersonalDetails, pathToDisplayName); return displayName || defaultValue || Localize.translateLocal('common.hidden'); @@ -35,8 +35,8 @@ function getDisplayNameOrDefault(passedPersonalDetails, pathToDisplayName, defau * @param {Boolean} shouldChangeUserDisplayName - It will replace the current user's personal detail object's displayName with 'You'. * @returns {Array} - Array of personal detail objects */ -function getPersonalDetailsByIDs(accountIDs, currentUserAccountID, shouldChangeUserDisplayName = false) { - const result = []; +function getPersonalDetailsByIDs(accountIDs: number[], currentUserAccountID: number, shouldChangeUserDisplayName = false): OnyxTypes.PersonalDetails[] { + const result: OnyxTypes.PersonalDetails[] = []; _.each( _.filter(personalDetails, (detail) => accountIDs.includes(detail.accountID)), (detail) => { @@ -59,7 +59,7 @@ function getPersonalDetailsByIDs(accountIDs, currentUserAccountID, shouldChangeU * @param {Array} logins Array of user logins * @returns {Array} - Array of accountIDs according to passed logins */ -function getAccountIDsByLogins(logins) { +function getAccountIDsByLogins(logins: string[]): string[] { return _.reduce( logins, (foundAccountIDs, login) => { @@ -82,7 +82,7 @@ function getAccountIDsByLogins(logins) { * @param {Array} accountIDs Array of user accountIDs * @returns {Array} - Array of logins according to passed accountIDs */ -function getLoginsByAccountIDs(accountIDs) { +function getLoginsByAccountIDs(accountIDs: number[]): number[] { return _.reduce( accountIDs, (foundLogins, accountID) => { @@ -103,10 +103,10 @@ function getLoginsByAccountIDs(accountIDs) { * @param {Array} accountIDs Array of user accountIDs * @returns {Object} - Object with optimisticData, successData and failureData (object of personal details objects) */ -function getNewPersonalDetailsOnyxData(logins, accountIDs) { - const optimisticData = {}; - const successData = {}; - const failureData = {}; +function getNewPersonalDetailsOnyxData(logins: string[], accountIDs: number[]) { + const optimisticData: PersonalDetailsList = {}; + const successData: PersonalDetailsList = {}; + const failureData: PersonalDetailsList = {}; _.each(logins, (login, index) => { const accountID = accountIDs[index]; From 9510a4e1bdf47b41a915e786e4e1ffde90b355d0 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 27 Sep 2023 00:19:09 +0200 Subject: [PATCH 02/15] Migrate personal details utils to TS --- src/components/ArchivedReportFooter.js | 6 +- src/libs/OptionsListUtils.js | 2 +- src/libs/PersonalDetailsUtils.ts | 96 ++++++++++------------- src/libs/SidebarUtils.js | 2 +- src/pages/home/report/ReportActionItem.js | 5 +- 5 files changed, 50 insertions(+), 61 deletions(-) diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index 71d331b68db0..4fb968dd1e3b 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -51,14 +51,14 @@ const defaultProps = { function ArchivedReportFooter(props) { const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT); - let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [props.report.ownerAccountID, 'displayName']); + let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(lodashGet(props.personalDetails, [props.report.ownerAccountID, 'displayName'])); let oldDisplayName; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) { const newAccountID = props.reportClosedAction.originalMessage.newAccountID; const oldAccountID = props.reportClosedAction.originalMessage.oldAccountID; - displayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [newAccountID, 'displayName']); - oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [oldAccountID, 'displayName']); + displayName = PersonalDetailsUtils.getDisplayNameOrDefault(lodashGet(props.personalDetails, [newAccountID, 'displayName'])); + oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(lodashGet(props.personalDetails, [oldAccountID, 'displayName'])); } const shouldRenderHTML = archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT; diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 7629a1acc0a6..6b5b1b03eee0 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -512,7 +512,7 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { (lastReportActions[report.reportID] && lastReportActions[report.reportID].originalMessage && lastReportActions[report.reportID].originalMessage.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { - displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), + displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lodashGet(lastActorDetails, 'displayName')), policyName: ReportUtils.getPolicyName(report), }); } diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 76d966ecf027..b0369f32ea2d 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -1,6 +1,4 @@ -import lodashGet from 'lodash/get'; -import Onyx from 'react-native-onyx'; -import _ from 'underscore'; +import Onyx, {OnyxEntry} from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; import * as Localize from './Localize'; import * as UserUtils from './UserUtils'; @@ -9,12 +7,12 @@ import * as OnyxTypes from '../types/onyx'; type PersonalDetailsList = Record; -let personalDetails = []; -let allPersonalDetails = {}; +let personalDetails: OnyxTypes.PersonalDetails[] = []; +let allPersonalDetails: OnyxEntry> = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { - personalDetails = _.values(val); + personalDetails = Object.values(val ?? {}); allPersonalDetails = val; }, }); @@ -22,24 +20,21 @@ Onyx.connect({ /** * @param [defaultValue] optional default display name value */ -function getDisplayNameOrDefault(passedPersonalDetails: unknown, pathToDisplayName: string[], defaultValue: string): string { - const displayName = lodashGet(passedPersonalDetails, pathToDisplayName); - - return displayName || defaultValue || Localize.translateLocal('common.hidden'); +function getDisplayNameOrDefault(displayName: string, defaultValue?: string): string { + return displayName ?? defaultValue ?? Localize.translateLocal('common.hidden'); } /** * Given a list of account IDs (as number) it will return an array of personal details objects. - * @param {Array} accountIDs - Array of accountIDs - * @param {Number} currentUserAccountID - * @param {Boolean} shouldChangeUserDisplayName - It will replace the current user's personal detail object's displayName with 'You'. - * @returns {Array} - Array of personal detail objects + * @param accountIDs - Array of accountIDs + * @param shouldChangeUserDisplayName - It will replace the current user's personal detail object's displayName with 'You'. + * @returns Array of personal detail objects */ function getPersonalDetailsByIDs(accountIDs: number[], currentUserAccountID: number, shouldChangeUserDisplayName = false): OnyxTypes.PersonalDetails[] { const result: OnyxTypes.PersonalDetails[] = []; - _.each( - _.filter(personalDetails, (detail) => accountIDs.includes(detail.accountID)), - (detail) => { + personalDetails + .filter((detail) => accountIDs.includes(detail.accountID)) + .forEach((detail) => { if (shouldChangeUserDisplayName && currentUserAccountID === detail.accountID) { result.push({ ...detail, @@ -48,70 +43,61 @@ function getPersonalDetailsByIDs(accountIDs: number[], currentUserAccountID: num } else { result.push(detail); } - }, - ); + }); return result; } /** * Given a list of logins, find the associated personal detail and return related accountIDs. * - * @param {Array} logins Array of user logins - * @returns {Array} - Array of accountIDs according to passed logins + * @param logins Array of user logins + * @returns Array of accountIDs according to passed logins */ -function getAccountIDsByLogins(logins: string[]): string[] { - return _.reduce( - logins, - (foundAccountIDs, login) => { - const currentDetail = _.find(personalDetails, (detail) => detail.login === login); - if (!currentDetail) { - // generate an account ID because in this case the detail is probably new, so we don't have a real accountID yet - foundAccountIDs.push(UserUtils.generateAccountID(login)); - } else { - foundAccountIDs.push(Number(currentDetail.accountID)); - } - return foundAccountIDs; - }, - [], - ); +function getAccountIDsByLogins(logins: string[]): number[] { + return logins.reduce((foundAccountIDs: number[], login) => { + const currentDetail = personalDetails.find((detail) => detail.login === login); + if (!currentDetail) { + // generate an account ID because in this case the detail is probably new, so we don't have a real accountID yet + foundAccountIDs.push(UserUtils.generateAccountID(login)); + } else { + foundAccountIDs.push(Number(currentDetail.accountID)); + } + return foundAccountIDs; + }, []); } /** * Given a list of accountIDs, find the associated personal detail and return related logins. * - * @param {Array} accountIDs Array of user accountIDs - * @returns {Array} - Array of logins according to passed accountIDs + * @param accountIDs Array of user accountIDs + * @returns Array of logins according to passed accountIDs */ -function getLoginsByAccountIDs(accountIDs: number[]): number[] { - return _.reduce( - accountIDs, - (foundLogins, accountID) => { - const currentDetail = _.find(personalDetails, (detail) => Number(detail.accountID) === Number(accountID)) || {}; - if (currentDetail.login) { - foundLogins.push(currentDetail.login); - } - return foundLogins; - }, - [], - ); +function getLoginsByAccountIDs(accountIDs: number[]): string[] { + return accountIDs.reduce((foundLogins: string[], accountID) => { + const currentDetail: Partial = personalDetails.find((detail) => Number(detail.accountID) === Number(accountID)) ?? {}; + if (currentDetail.login) { + foundLogins.push(currentDetail.login); + } + return foundLogins; + }, []); } /** * Given a list of logins and accountIDs, return Onyx data for users with no existing personal details stored * - * @param {Array} logins Array of user logins - * @param {Array} accountIDs Array of user accountIDs - * @returns {Object} - Object with optimisticData, successData and failureData (object of personal details objects) + * @param logins Array of user logins + * @param accountIDs Array of user accountIDs + * @returns Object with optimisticData, successData and failureData (object of personal details objects) */ function getNewPersonalDetailsOnyxData(logins: string[], accountIDs: number[]) { const optimisticData: PersonalDetailsList = {}; const successData: PersonalDetailsList = {}; const failureData: PersonalDetailsList = {}; - _.each(logins, (login, index) => { + logins.forEach((login, index) => { const accountID = accountIDs[index]; - if (_.isEmpty(allPersonalDetails[accountID])) { + if (allPersonalDetails && Object.keys(allPersonalDetails[accountID]).length === 0) { optimisticData[accountID] = { login, accountID, diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 118035f9f605..cbbe2a9a4267 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -297,7 +297,7 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, (lastReportActions[report.reportID] && lastReportActions[report.reportID].originalMessage && lastReportActions[report.reportID].originalMessage.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT; lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, { - displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'), + displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lodashGet(lastActorDetails, 'displayName')), policyName: ReportUtils.getPolicyName(report, false, policy), }); } diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index fae5c518bbfe..f40e9069744f 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -332,7 +332,10 @@ function ReportActionItem(props) { /> ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTQUEUED) { - const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault( + lodashGet(props.personalDetailsList, [props.report.ownerAccountID, 'displayName']), + props.report.ownerEmail, + ); const shouldShowAddCreditBankAccountButton = ReportUtils.isCurrentUserSubmitter(props.report.reportID) && !store.hasCreditBankAccount() && !ReportUtils.isSettled(props.report.reportID); From 1caa40d989e3a51fc9eeb4f6938656a693f2a6dc Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Mon, 23 Oct 2023 13:03:39 +0200 Subject: [PATCH 03/15] Rename personal details --- src/libs/{PersonalDetailsUtils.js => PersonalDetailsUtils.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/libs/{PersonalDetailsUtils.js => PersonalDetailsUtils.ts} (100%) diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.ts similarity index 100% rename from src/libs/PersonalDetailsUtils.js rename to src/libs/PersonalDetailsUtils.ts From ed764e4fc5a793f30386a9a36a05ce9a7c9cfd70 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Mon, 23 Oct 2023 13:43:23 +0200 Subject: [PATCH 04/15] [TS migration] Migrate 'PersonalDetailsUtils.js' lib to TypeScript --- src/libs/PersonalDetailsUtils.ts | 134 ++++++++++++++----------------- 1 file changed, 62 insertions(+), 72 deletions(-) diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 29c49427bc81..3c4a8c18adcb 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -1,45 +1,41 @@ -import lodashGet from 'lodash/get'; -import Onyx from 'react-native-onyx'; -import _ from 'underscore'; +import Onyx, {OnyxEntry} from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; import * as Localize from './Localize'; import * as UserUtils from './UserUtils'; import * as LocalePhoneNumber from './LocalePhoneNumber'; +import * as OnyxTypes from '../types/onyx'; -let personalDetails = []; -let allPersonalDetails = {}; +type PersonalDetailsList = Record; + +let personalDetails: OnyxTypes.PersonalDetails[] = []; +let allPersonalDetails: OnyxEntry> = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { - personalDetails = _.values(val); + personalDetails = Object.values(val ?? {}); allPersonalDetails = val; }, }); /** - * @param {Object} passedPersonalDetails - * @param {Array} pathToDisplayName - * @param {String} [defaultValue] optional default display name value - * @returns {String} + * @param [defaultValue] optional default display name value */ -function getDisplayNameOrDefault(passedPersonalDetails, pathToDisplayName, defaultValue) { - const displayName = lodashGet(passedPersonalDetails, pathToDisplayName); - - return displayName || defaultValue || Localize.translateLocal('common.hidden'); +function getDisplayNameOrDefault(displayName: string, defaultValue?: string): string { + return displayName ?? defaultValue ?? Localize.translateLocal('common.hidden'); } /** * Given a list of account IDs (as number) it will return an array of personal details objects. - * @param {Array} accountIDs - Array of accountIDs - * @param {Number} currentUserAccountID - * @param {Boolean} shouldChangeUserDisplayName - It will replace the current user's personal detail object's displayName with 'You'. - * @returns {Array} - Array of personal detail objects + * @param accountIDs - Array of accountIDs + * @param currentUserAccountID + * @param shouldChangeUserDisplayName - It will replace the current user's personal detail object's displayName with 'You'. + * @returns - Array of personal detail objects */ -function getPersonalDetailsByIDs(accountIDs, currentUserAccountID, shouldChangeUserDisplayName = false) { - return _.chain(accountIDs) - .filter((accountID) => !!allPersonalDetails[accountID]) +function getPersonalDetailsByIDs(accountIDs: number[], currentUserAccountID: number, shouldChangeUserDisplayName = false): OnyxTypes.PersonalDetails[] { + const result: OnyxTypes.PersonalDetails[] = accountIDs + .filter((accountID) => !!allPersonalDetails?.[accountID]) .map((accountID) => { - const detail = allPersonalDetails[accountID]; + const detail = (allPersonalDetails?.[accountID] ?? {}) as OnyxTypes.PersonalDetails; if (shouldChangeUserDisplayName && currentUserAccountID === detail.accountID) { return { @@ -49,69 +45,62 @@ function getPersonalDetailsByIDs(accountIDs, currentUserAccountID, shouldChangeU } return detail; - }) - .value(); + }); + + return result; } /** * Given a list of logins, find the associated personal detail and return related accountIDs. * - * @param {Array} logins Array of user logins - * @returns {Array} - Array of accountIDs according to passed logins + * @param logins Array of user logins + * @returns Array of accountIDs according to passed logins */ -function getAccountIDsByLogins(logins) { - return _.reduce( - logins, - (foundAccountIDs, login) => { - const currentDetail = _.find(personalDetails, (detail) => detail.login === login); - if (!currentDetail) { - // generate an account ID because in this case the detail is probably new, so we don't have a real accountID yet - foundAccountIDs.push(UserUtils.generateAccountID(login)); - } else { - foundAccountIDs.push(Number(currentDetail.accountID)); - } - return foundAccountIDs; - }, - [], - ); +function getAccountIDsByLogins(logins: string[]): number[] { + return logins.reduce((foundAccountIDs: number[], login) => { + const currentDetail = personalDetails.find((detail) => detail.login === login); + if (!currentDetail) { + // generate an account ID because in this case the detail is probably new, so we don't have a real accountID yet + foundAccountIDs.push(UserUtils.generateAccountID(login)); + } else { + foundAccountIDs.push(Number(currentDetail.accountID)); + } + return foundAccountIDs; + }, []); } /** * Given a list of accountIDs, find the associated personal detail and return related logins. * - * @param {Array} accountIDs Array of user accountIDs - * @returns {Array} - Array of logins according to passed accountIDs + * @param accountIDs Array of user accountIDs + * @returns Array of logins according to passed accountIDs */ -function getLoginsByAccountIDs(accountIDs) { - return _.reduce( - accountIDs, - (foundLogins, accountID) => { - const currentDetail = _.find(personalDetails, (detail) => Number(detail.accountID) === Number(accountID)) || {}; - if (currentDetail.login) { - foundLogins.push(currentDetail.login); - } - return foundLogins; - }, - [], - ); +function getLoginsByAccountIDs(accountIDs: number[]): string[] { + return accountIDs.reduce((foundLogins: string[], accountID) => { + const currentDetail: Partial = personalDetails.find((detail) => Number(detail.accountID) === Number(accountID)) ?? {}; + if (currentDetail.login) { + foundLogins.push(currentDetail.login); + } + return foundLogins; + }, []); } /** * Given a list of logins and accountIDs, return Onyx data for users with no existing personal details stored * - * @param {Array} logins Array of user logins - * @param {Array} accountIDs Array of user accountIDs - * @returns {Object} - Object with optimisticData, successData and failureData (object of personal details objects) + * @param logins Array of user logins + * @param accountIDs Array of user accountIDs + * @returns Object with optimisticData, successData and failureData (object of personal details objects) */ -function getNewPersonalDetailsOnyxData(logins, accountIDs) { - const optimisticData = {}; - const successData = {}; - const failureData = {}; +function getNewPersonalDetailsOnyxData(logins: string[], accountIDs: number[]) { + const optimisticData: PersonalDetailsList = {}; + const successData: PersonalDetailsList = {}; + const failureData: PersonalDetailsList = {}; - _.each(logins, (login, index) => { + logins.forEach((login, index) => { const accountID = accountIDs[index]; - if (_.isEmpty(allPersonalDetails[accountID])) { + if (allPersonalDetails && Object.keys(allPersonalDetails[accountID]).length === 0) { optimisticData[accountID] = { login, accountID, @@ -155,23 +144,24 @@ function getNewPersonalDetailsOnyxData(logins, accountIDs) { /** * Applies common formatting to each piece of an address * - * @param {String} piece - address piece to format - * @returns {String} - formatted piece + * @param piece - address piece to format + * @returns - formatted piece */ -function formatPiece(piece) { +function formatPiece(piece?: string): string { return piece ? `${piece}, ` : ''; } /** * Formats an address object into an easily readable string * - * @param {OnyxTypes.PrivatePersonalDetails} privatePersonalDetails - details object - * @returns {String} - formatted address + * @param privatePersonalDetails - details object + * @returns - formatted address */ -function getFormattedAddress(privatePersonalDetails) { +function getFormattedAddress(privatePersonalDetails: OnyxTypes.PrivatePersonalDetails): string { const {address} = privatePersonalDetails; - const [street1, street2] = (address.street || '').split('\n'); - const formattedAddress = formatPiece(street1) + formatPiece(street2) + formatPiece(address.city) + formatPiece(address.state) + formatPiece(address.zip) + formatPiece(address.country); + const [street1, street2] = (address?.street ?? '').split('\n'); + const formattedAddress = + formatPiece(street1) + formatPiece(street2) + formatPiece(address?.city) + formatPiece(address?.state) + formatPiece(address?.zip) + formatPiece(address?.country); // Remove the last comma of the address return formattedAddress.trim().replace(/,$/, ''); From 209f33cdde295c7e8230ca05741f5d793514c9bb Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Mon, 23 Oct 2023 14:58:41 +0200 Subject: [PATCH 05/15] Tweak getDisplayNameOrDefault usages --- src/pages/home/report/ReportActionItem.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 42bcfd49f207..da16916c975c 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -362,7 +362,10 @@ function ReportActionItem(props) { /> ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTQUEUED) { - const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetailsList, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail); + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault( + lodashGet(props.personalDetailsList, [props.report.ownerAccountID, 'displayName']), + props.report.ownerEmail, + ); const paymentType = lodashGet(props.action, 'originalMessage.paymentType', ''); const isSubmitterOfUnsettledReport = ReportUtils.isCurrentUserSubmitter(props.report.reportID) && !ReportUtils.isSettled(props.report.reportID); From 7d00e4b5ce6dbc80d501784b48ef54022e34bafb Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Thu, 26 Oct 2023 12:42:04 +0200 Subject: [PATCH 06/15] Fix: review of personalDetailsUtils.ts --- src/ONYXKEYS.ts | 2 +- src/libs/PersonalDetailsUtils.ts | 13 ++++++------- src/types/onyx/PersonalDetails.ts | 4 +++- src/types/onyx/index.ts | 3 ++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 68b3bd047ad8..bc280c8aaa0e 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -324,7 +324,7 @@ type OnyxValues = { [ONYXKEYS.NETWORK]: OnyxTypes.Network; [ONYXKEYS.CUSTOM_STATUS_DRAFT]: OnyxTypes.CustomStatusDraft; [ONYXKEYS.INPUT_FOCUSED]: boolean; - [ONYXKEYS.PERSONAL_DETAILS_LIST]: Record; + [ONYXKEYS.PERSONAL_DETAILS_LIST]: OnyxTypes.PersonalDetailsList; [ONYXKEYS.PRIVATE_PERSONAL_DETAILS]: OnyxTypes.PrivatePersonalDetails; [ONYXKEYS.TASK]: OnyxTypes.Task; [ONYXKEYS.CURRENCY_LIST]: Record; diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 7ac8b5c10204..f01b46631b88 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -4,11 +4,10 @@ import * as Localize from './Localize'; import * as UserUtils from './UserUtils'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as OnyxTypes from '../types/onyx'; +import {PersonalDetailsList} from '../types/onyx'; -type PersonalDetailsList = Record>; - -let personalDetails: OnyxTypes.PersonalDetails[] = []; -let allPersonalDetails: OnyxEntry> = {}; +let personalDetails: Array = []; +let allPersonalDetails: OnyxEntry = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { @@ -58,7 +57,7 @@ function getPersonalDetailsByIDs(accountIDs: number[], currentUserAccountID: num */ function getAccountIDsByLogins(logins: string[]): number[] { return logins.reduce((foundAccountIDs, login) => { - const currentDetail = personalDetails.find((detail) => detail.login === login); + const currentDetail = personalDetails.find((detail) => detail?.login === login); if (!currentDetail) { // generate an account ID because in this case the detail is probably new, so we don't have a real accountID yet foundAccountIDs.push(UserUtils.generateAccountID(login)); @@ -77,7 +76,7 @@ function getAccountIDsByLogins(logins: string[]): number[] { */ function getLoginsByAccountIDs(accountIDs: number[]): string[] { return accountIDs.reduce((foundLogins: string[], accountID) => { - const currentDetail: Partial = personalDetails.find((detail) => Number(detail.accountID) === Number(accountID)) ?? {}; + const currentDetail: Partial = personalDetails.find((detail) => Number(detail?.accountID) === Number(accountID)) ?? {}; if (currentDetail.login) { foundLogins.push(currentDetail.login); } @@ -100,7 +99,7 @@ function getNewPersonalDetailsOnyxData(logins: string[], accountIDs: number[]) { logins.forEach((login, index) => { const accountID = accountIDs[index]; - if (allPersonalDetails && Object.keys(allPersonalDetails[accountID]).length === 0) { + if (allPersonalDetails && Object.keys(allPersonalDetails?.[accountID] ?? {}).length === 0) { optimisticData[accountID] = { login, accountID, diff --git a/src/types/onyx/PersonalDetails.ts b/src/types/onyx/PersonalDetails.ts index 201273beac63..537600eab1e0 100644 --- a/src/types/onyx/PersonalDetails.ts +++ b/src/types/onyx/PersonalDetails.ts @@ -44,6 +44,8 @@ type PersonalDetails = { timezone?: Timezone; }; -export type {Timezone}; +type PersonalDetailsList = Record; + +export type {Timezone, PersonalDetailsList}; export default PersonalDetails; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 4603c4579343..59a811a65334 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -5,7 +5,7 @@ import IOU from './IOU'; import Modal from './Modal'; import Network from './Network'; import CustomStatusDraft from './CustomStatusDraft'; -import PersonalDetails from './PersonalDetails'; +import PersonalDetails, {PersonalDetailsList} from './PersonalDetails'; import PrivatePersonalDetails from './PrivatePersonalDetails'; import Task from './Task'; import Currency from './Currency'; @@ -90,6 +90,7 @@ export type { ReportAction, ReportActions, ReportActionReactions, + PersonalDetailsList, SecurityGroup, Transaction, Form, From ada39cf377b56a72a393a3ddc0e2d027402f3fbf Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Mon, 30 Oct 2023 11:18:41 +0100 Subject: [PATCH 07/15] Fix typecheck errors PersonalDetailsUtils --- src/components/withCurrentUserPersonalDetails.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index ed580b4dbe4a..4320797eb3b0 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -3,13 +3,13 @@ import {OnyxEntry, withOnyx} from 'react-native-onyx'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import personalDetailsPropType from '@pages/personalDetailsPropType'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalDetails, Session} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, Session} from '@src/types/onyx'; type CurrentUserPersonalDetails = PersonalDetails | Record; type OnyxProps = { /** Personal details of all the users, including current user */ - personalDetails: OnyxEntry>; + personalDetails: OnyxEntry; /** Session of the current user */ session: OnyxEntry; @@ -37,7 +37,7 @@ export default function ( const accountID = props.session?.accountID ?? 0; const accountPersonalDetails = props.personalDetails?.[accountID]; const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( - () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}), + () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}) as CurrentUserPersonalDetails, [accountPersonalDetails, accountID], ); return ( From 5e717fe8ce935d19918f50ddb4b7c43a20e1b1cb Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 15 Nov 2023 12:47:33 +0100 Subject: [PATCH 08/15] fix: typecheck errors --- src/libs/GroupChatUtils.ts | 4 ++-- src/libs/actions/PersonalDetails.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/GroupChatUtils.ts b/src/libs/GroupChatUtils.ts index dcb2b13f092c..2d25b23154c3 100644 --- a/src/libs/GroupChatUtils.ts +++ b/src/libs/GroupChatUtils.ts @@ -1,10 +1,10 @@ import Onyx, {OnyxEntry} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import {PersonalDetails, Report} from '@src/types/onyx'; +import {PersonalDetails, PersonalDetailsList, Report} from '@src/types/onyx'; import * as OptionsListUtils from './OptionsListUtils'; import * as ReportUtils from './ReportUtils'; -let allPersonalDetails: OnyxEntry> = {}; +let allPersonalDetails: OnyxEntry = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => (allPersonalDetails = val), diff --git a/src/libs/actions/PersonalDetails.ts b/src/libs/actions/PersonalDetails.ts index db024e8db4cc..82ec604179bb 100644 --- a/src/libs/actions/PersonalDetails.ts +++ b/src/libs/actions/PersonalDetails.ts @@ -8,7 +8,7 @@ import * as UserUtils from '@libs/UserUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {DateOfBirthForm, PersonalDetails, PrivatePersonalDetails} from '@src/types/onyx'; +import {DateOfBirthForm, PersonalDetails, PersonalDetailsList, PrivatePersonalDetails} from '@src/types/onyx'; import {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; type FirstAndLastName = { @@ -26,7 +26,7 @@ Onyx.connect({ }, }); -let allPersonalDetails: OnyxEntry> = null; +let allPersonalDetails: OnyxEntry = null; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => (allPersonalDetails = val), From 9ddcc2fc9a2cecd23abc8281d60e305faf7cbeb3 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Thu, 23 Nov 2023 14:44:35 +0100 Subject: [PATCH 09/15] fix: lint --- src/libs/GroupChatUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/GroupChatUtils.ts b/src/libs/GroupChatUtils.ts index 2d25b23154c3..8bf6cab7481a 100644 --- a/src/libs/GroupChatUtils.ts +++ b/src/libs/GroupChatUtils.ts @@ -1,6 +1,6 @@ import Onyx, {OnyxEntry} from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; -import {PersonalDetails, PersonalDetailsList, Report} from '@src/types/onyx'; +import {PersonalDetailsList, Report} from '@src/types/onyx'; import * as OptionsListUtils from './OptionsListUtils'; import * as ReportUtils from './ReportUtils'; From 1e4eaafbbebb874798c415379e77953666a0cb1d Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Thu, 7 Dec 2023 20:33:43 +0100 Subject: [PATCH 10/15] fix: handle PersonalDetailsUtils.getDisplayNameOrDefault properly --- src/pages/ReportParticipantsPage.js | 2 +- src/pages/home/report/ReportActionItem.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index ceaa53a41a6b..20d32a815d78 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -60,7 +60,7 @@ const getAllParticipants = (report, personalDetails, translate) => .map((accountID, index) => { const userPersonalDetail = lodashGet(personalDetails, accountID, {displayName: personalDetails.displayName || translate('common.hidden'), avatar: ''}); const userLogin = LocalePhoneNumber.formatPhoneNumber(userPersonalDetail.login || '') || translate('common.hidden'); - const displayName = PersonalDetailsUtils.getDisplayNameOrDefault(userPersonalDetail, 'displayName'); + const displayName = PersonalDetailsUtils.getDisplayNameOrDefault(userPersonalDetail.displayName); return { alternateText: userLogin, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 0e2f37504bcb..c06a37270ab9 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -417,7 +417,7 @@ function ReportActionItem(props) { ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED) { - const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails, [props.report.ownerAccountID, 'displayName']); + const submitterDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(lodashGet(personalDetails, [props.report.ownerAccountID, 'displayName'])); const amount = CurrencyUtils.convertToDisplayString(props.report.total, props.report.currency); children = ; From 866ef5c885e908521a4e51aa4d5c34d4fdbd0993 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Fri, 15 Dec 2023 12:40:29 +0100 Subject: [PATCH 11/15] change default value for owner account --- src/components/ArchivedReportFooter.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ArchivedReportFooter.tsx b/src/components/ArchivedReportFooter.tsx index d810142f9deb..8604d20130c7 100644 --- a/src/components/ArchivedReportFooter.tsx +++ b/src/components/ArchivedReportFooter.tsx @@ -30,14 +30,14 @@ function ArchivedReportFooter({report, reportClosedAction, personalDetails = {}} const originalMessage = reportClosedAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED ? reportClosedAction.originalMessage : null; const archiveReason = originalMessage?.reason ?? CONST.REPORT.ARCHIVE_REASON.DEFAULT; - let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails?.[report?.ownerAccountID ?? '']?.displayName); + let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails?.[report?.ownerAccountID ?? 0]?.displayName); let oldDisplayName: string | undefined; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) { const newAccountID = originalMessage?.newAccountID; const oldAccountID = originalMessage?.oldAccountID; - displayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails?.[newAccountID ?? '']?.displayName); - oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails?.[oldAccountID ?? '']?.displayName); + displayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails?.[newAccountID ?? 0]?.displayName); + oldDisplayName = PersonalDetailsUtils.getDisplayNameOrDefault(personalDetails?.[oldAccountID ?? 0]?.displayName); } const shouldRenderHTML = archiveReason !== CONST.REPORT.ARCHIVE_REASON.DEFAULT; From d63f975f7c33099bdf49845418a0d38c01dc39f0 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Fri, 15 Dec 2023 12:41:49 +0100 Subject: [PATCH 12/15] Resolve merge conflict --- src/types/onyx/PersonalDetails.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/types/onyx/PersonalDetails.ts b/src/types/onyx/PersonalDetails.ts index 16be53180e72..9f613cbf4f1e 100644 --- a/src/types/onyx/PersonalDetails.ts +++ b/src/types/onyx/PersonalDetails.ts @@ -73,11 +73,7 @@ type PersonalDetails = { status?: string; }; -<<<<<<< HEAD type PersonalDetailsList = Record; -======= -type PersonalDetailsList = Record; ->>>>>>> origin/main export default PersonalDetails; From 65dda0dd590d8109a12914a79f3732c1427b1363 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Mon, 18 Dec 2023 11:30:25 +0100 Subject: [PATCH 13/15] Fix: typecheck --- src/libs/PersonalDetailsUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 4ae67f7a2a85..8bb4ac0aea3e 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -190,7 +190,7 @@ function getFormattedAddress(privatePersonalDetails: OnyxTypes.PrivatePersonalDe * @param personalDetail - details object * @returns - The effective display name */ -function getEffectiveDisplayName(personalDetail: PersonalDetails): string | undefined { +function getEffectiveDisplayName(personalDetail?: PersonalDetails): string | undefined { if (personalDetail) { return LocalePhoneNumber.formatPhoneNumber(personalDetail?.login ?? '') || personalDetail.displayName; } From 40d82046c6e528b0ed7b9274aa08fa6655b63ed6 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Mon, 18 Dec 2023 11:35:41 +0100 Subject: [PATCH 14/15] fix: types in util files --- src/libs/ReportUtils.ts | 8 ++++---- src/libs/UserUtils.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 24e795919649..0041cdabae6d 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1458,12 +1458,12 @@ function getDisplayNamesWithTooltips( return personalDetailsListArray .map((user) => { - const accountID = Number(user.accountID); + const accountID = Number(user?.accountID); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const displayName = getDisplayNameForParticipant(accountID, isMultipleParticipantReport, shouldFallbackToHidden) || user.login || ''; + const displayName = getDisplayNameForParticipant(accountID, isMultipleParticipantReport, shouldFallbackToHidden) || user?.login || ''; const avatar = UserUtils.getDefaultAvatar(accountID); - let pronouns = user.pronouns; + let pronouns = user?.pronouns ?? ''; if (pronouns?.startsWith(CONST.PRONOUNS.PREFIX)) { const pronounTranslationKey = pronouns.replace(CONST.PRONOUNS.PREFIX, ''); pronouns = Localize.translateLocal(`pronouns.${pronounTranslationKey}` as TranslationPaths); @@ -1472,7 +1472,7 @@ function getDisplayNamesWithTooltips( return { displayName, avatar, - login: user.login ?? '', + login: user?.login ?? '', accountID, pronouns, }; diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts index e95b62cc2437..0fad9c2c2a75 100644 --- a/src/libs/UserUtils.ts +++ b/src/libs/UserUtils.ts @@ -7,7 +7,7 @@ import * as defaultAvatars from '@components/Icon/DefaultAvatars'; import {ConciergeAvatar, FallbackAvatar} from '@components/Icon/Expensicons'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {PersonalDetails} from '@src/types/onyx'; +import {PersonalDetailsList} from '@src/types/onyx'; import Login from '@src/types/onyx/Login'; import hashCode from './hashCode'; @@ -17,7 +17,7 @@ type AvatarSource = React.FC | string; type LoginListIndicator = ValueOf | ''; -let allPersonalDetails: OnyxEntry>; +let allPersonalDetails: OnyxEntry; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => (allPersonalDetails = _.isEmpty(val) ? {} : val), From d2dfec69846f4f4fc856a4f39c8f55a7cb1fa490 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Mon, 18 Dec 2023 11:45:50 +0100 Subject: [PATCH 15/15] fix: unit test --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0041cdabae6d..fce158c309b8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1463,7 +1463,7 @@ function getDisplayNamesWithTooltips( const displayName = getDisplayNameForParticipant(accountID, isMultipleParticipantReport, shouldFallbackToHidden) || user?.login || ''; const avatar = UserUtils.getDefaultAvatar(accountID); - let pronouns = user?.pronouns ?? ''; + let pronouns = user?.pronouns ?? undefined; if (pronouns?.startsWith(CONST.PRONOUNS.PREFIX)) { const pronounTranslationKey = pronouns.replace(CONST.PRONOUNS.PREFIX, ''); pronouns = Localize.translateLocal(`pronouns.${pronounTranslationKey}` as TranslationPaths);