From b94183a91f83da125dbf6f5291bd7a51cab552dd Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 6 Jun 2023 18:22:03 -0400 Subject: [PATCH 01/60] Remove all uses of old personalDetails onyx key --- src/ONYXKEYS.js | 3 -- src/components/ArchivedReportFooter.js | 2 +- src/components/OnyxProvider.js | 2 +- src/components/ReportActionItem/IOUPreview.js | 2 +- src/components/ReportWelcomeText.js | 2 +- .../Navigation/AppNavigator/AuthScreens.js | 2 +- src/libs/ReportUtils.js | 4 +-- src/libs/SidebarUtils.js | 2 +- src/libs/actions/PersonalDetails.js | 22 ++++++------- src/libs/actions/Report.js | 2 +- src/libs/actions/User.js | 6 ++-- src/pages/DetailsPage.js | 2 +- src/pages/NewChatPage.js | 2 +- src/pages/ReportDetailsPage.js | 2 +- src/pages/ReportParticipantsPage.js | 2 +- src/pages/SearchPage.js | 2 +- src/pages/home/ReportScreen.js | 2 +- src/pages/home/report/ReportActionCompose.js | 2 +- .../home/report/ReportActionItemCreated.js | 2 +- src/pages/home/sidebar/SidebarLinks.js | 2 +- src/pages/iou/MoneyRequestModal.js | 2 +- src/pages/iou/SplitBillDetailsPage.js | 2 +- .../MoneyRequestParticipantsSelector.js | 2 +- .../MoneyRequestParticipantsSplitSelector.js | 2 +- src/pages/tasks/NewTaskPage.js | 2 +- src/pages/tasks/TaskAssigneeSelectorModal.js | 2 +- .../TaskShareDestinationSelectorModal.js | 2 +- .../workspace/WorkspaceInviteMessagePage.js | 2 +- src/pages/workspace/WorkspaceInvitePage.js | 2 +- src/pages/workspace/WorkspaceMembersPage.js | 2 +- tests/perf-test/SidebarLinks.perf-test.js | 2 +- tests/ui/UnreadIndicatorsTest.js | 4 +-- tests/unit/OptionsListUtilsTest.js | 4 +-- tests/unit/ReportUtilsTest.js | 4 +-- tests/unit/SidebarFilterTest.js | 28 ++++++++-------- tests/unit/SidebarOrderTest.js | 32 +++++++++---------- tests/unit/SidebarTest.js | 4 +-- tests/utils/TestHelper.js | 4 +-- 38 files changed, 83 insertions(+), 86 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 0b8e27463f05..db87ddb76979 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -42,9 +42,6 @@ export default { // Has information about the network status (offline/online) NETWORK: 'network', - // Contains all the personalDetails the user has access to - PERSONAL_DETAILS: 'personalDetails', - // Contains all the personalDetails the user has access to, keyed by accountID PERSONAL_DETAILS_LIST: 'personalDetailsList', diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index 75117cd4cb42..a59b5f1dd189 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -81,7 +81,7 @@ export default compose( withLocalize, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, reportClosedAction: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, diff --git a/src/components/OnyxProvider.js b/src/components/OnyxProvider.js index 6cee7e5b7a62..4047ba60aea4 100644 --- a/src/components/OnyxProvider.js +++ b/src/components/OnyxProvider.js @@ -7,7 +7,7 @@ import ComposeProviders from './ComposeProviders'; // Set up any providers for individual keys. This should only be used in cases where many components will subscribe to // the same key (e.g. FlatList renderItem components) const [withNetwork, NetworkProvider, NetworkContext] = createOnyxContext(ONYXKEYS.NETWORK, {}); -const [withPersonalDetails, PersonalDetailsProvider] = createOnyxContext(ONYXKEYS.PERSONAL_DETAILS); +const [withPersonalDetails, PersonalDetailsProvider] = createOnyxContext(ONYXKEYS.PERSONAL_DETAILS_LIST); const [withCurrentDate, CurrentDateProvider] = createOnyxContext(ONYXKEYS.CURRENT_DATE); const [withReportActionsDrafts, ReportActionsDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS); const [withBlockedFromConcierge, BlockedFromConciergeProvider] = createOnyxContext(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE); diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 1b9a95a1ef08..4defeb177b70 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -264,7 +264,7 @@ export default compose( withLocalize, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, iouReport: { key: ({iouReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`, diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js index a954fe3d8730..9ca3d672bee0 100644 --- a/src/components/ReportWelcomeText.js +++ b/src/components/ReportWelcomeText.js @@ -129,7 +129,7 @@ export default compose( key: ONYXKEYS.BETAS, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, }), )(ReportWelcomeText); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 8539f384504c..df8fef55331c 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -47,7 +47,7 @@ Onyx.connect({ let timezone; Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { if (!val || timezone) { return; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 21886511df30..ba3ba2e76598 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -57,7 +57,7 @@ Onyx.connect({ let allPersonalDetails; let currentUserPersonalDetails; Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { currentUserPersonalDetails = lodashGet(val, currentUserEmail, {}); allPersonalDetails = val; @@ -827,7 +827,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) } /** - * Gets the personal details for a login by looking in the ONYXKEYS.PERSONAL_DETAILS Onyx key (stored in the local variable, allPersonalDetails). If it doesn't exist in Onyx, + * Gets the personal details for a login by looking in the ONYXKEYS.PERSONAL_DETAILS_LIST Onyx key (stored in the local variable, allPersonalDetails). If it doesn't exist in Onyx, * then a default object is constructed. * @param {String} login * @returns {Object} diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 87e8b97d0bd0..25c21d1b3060 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -29,7 +29,7 @@ Onyx.connect({ let personalDetails; Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => (personalDetails = val), }); diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index fc47ca5142f6..9726b62b3bf6 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -18,7 +18,7 @@ Onyx.connect({ let personalDetails; Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => (personalDetails = val), }); @@ -102,7 +102,7 @@ function updatePronouns(pronouns) { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { pronouns, @@ -127,7 +127,7 @@ function updateDisplayName(firstName, lastName) { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { firstName, @@ -252,7 +252,7 @@ function updateAutomaticTimezone(timezone) { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { timezone, @@ -283,7 +283,7 @@ function updateSelectedTimezone(selectedTimezone) { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { timezone, @@ -319,7 +319,7 @@ function updateAvatar(file) { const optimisticData = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { avatar: file.uri, @@ -339,7 +339,7 @@ function updateAvatar(file) { const successData = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { pendingFields: { @@ -352,7 +352,7 @@ function updateAvatar(file) { const failureData = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { avatar: personalDetails[currentUserEmail].avatar, @@ -382,7 +382,7 @@ function deleteAvatar() { optimisticData: [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { avatar: defaultAvatar, @@ -393,7 +393,7 @@ function deleteAvatar() { failureData: [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserEmail]: { avatar: personalDetails[currentUserEmail].avatar, @@ -409,7 +409,7 @@ function deleteAvatar() { * Clear error and pending fields for the current user's avatar */ function clearAvatarErrors() { - Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, { + Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [currentUserEmail]: { errorFields: { avatar: null, diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 43b52ea431a8..cdac8665fa32 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -280,7 +280,7 @@ function addActions(reportID, text = '', file) { parameters.timezone = JSON.stringify(timezone); optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: {[currentUserEmail]: {timezone}}, }); DateUtils.setTimezoneUpdated(); diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index b90a22ceac8a..d3959be7497e 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -31,7 +31,7 @@ Onyx.connect({ let myPersonalDetails = {}; Onyx.connect({ - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { if (!val || !currentEmail) { return; @@ -785,7 +785,7 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [newDefaultContactMethod]: { ...myPersonalDetails, @@ -833,7 +833,7 @@ function setContactMethodAsDefault(newDefaultContactMethod) { }, { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [newDefaultContactMethod]: null, [oldDefaultContactMethod]: {...myPersonalDetails}, diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index 909b52da89b3..540f85f33cfe 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -212,7 +212,7 @@ export default compose( withLocalize, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, loginList: { key: ONYXKEYS.LOGIN_LIST, diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js index a5b9d8f39f2f..374c99780b50 100755 --- a/src/pages/NewChatPage.js +++ b/src/pages/NewChatPage.js @@ -270,7 +270,7 @@ export default compose( key: ONYXKEYS.COLLECTION.REPORT, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, betas: { key: ONYXKEYS.BETAS, diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index 1baf0b6151d9..eb350257efea 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -200,7 +200,7 @@ export default compose( withReportOrNotFound, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, policies: { key: ONYXKEYS.COLLECTION.POLICY, diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index 3e5717bc15b8..4f7b9f1a4045 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -135,7 +135,7 @@ export default compose( withReportOrNotFound, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, }), )(ReportParticipantsPage); diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index 713cba5ad665..17ca3a0c0be4 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -206,7 +206,7 @@ export default compose( key: ONYXKEYS.COLLECTION.REPORT, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, betas: { key: ONYXKEYS.BETAS, diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 652ea5eb5d2c..9eb907fb18e6 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -393,7 +393,7 @@ export default compose( key: ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, }), )(ReportScreen); diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index a7542d69d213..8b1c0513dc9d 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -1252,7 +1252,7 @@ export default compose( selector: EmojiUtils.getPreferredSkinToneIndex, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, shouldShowComposeInput: { key: ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, diff --git a/src/pages/home/report/ReportActionItemCreated.js b/src/pages/home/report/ReportActionItemCreated.js index a00e557ea613..5f8455d25495 100644 --- a/src/pages/home/report/ReportActionItemCreated.js +++ b/src/pages/home/report/ReportActionItemCreated.js @@ -89,7 +89,7 @@ export default compose( key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, }), )(ReportActionItemCreated); diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index a072402a4ca3..bb790aad74fe 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -315,7 +315,7 @@ export default compose( selector: chatReportSelector, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, selector: personalDetailsSelector, }, priorityMode: { diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 729a4ed27227..249d1f48e9b3 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -411,7 +411,7 @@ export default compose( key: ONYXKEYS.IOU, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, }), )(MoneyRequestModal); diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index a3104a72dce1..807c9179f531 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -107,7 +107,7 @@ export default compose( withReportOrNotFound, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, reportActions: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getReportID(route)}`, diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 90613ef78b86..49f569925692 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -175,7 +175,7 @@ export default compose( withLocalize, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, reports: { key: ONYXKEYS.COLLECTION.REPORT, diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 28bdc2365622..813a8740c5b9 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -241,7 +241,7 @@ export default compose( withLocalize, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, reports: { key: ONYXKEYS.COLLECTION.REPORT, diff --git a/src/pages/tasks/NewTaskPage.js b/src/pages/tasks/NewTaskPage.js index 59fb729a4771..32f700eba16e 100644 --- a/src/pages/tasks/NewTaskPage.js +++ b/src/pages/tasks/NewTaskPage.js @@ -192,7 +192,7 @@ export default compose( key: ONYXKEYS.COLLECTION.REPORT, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, session: { key: ONYXKEYS.SESSION, diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 63a79c6ce1d1..76a4e86e0a67 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -229,7 +229,7 @@ export default compose( key: ONYXKEYS.COLLECTION.REPORT, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, betas: { key: ONYXKEYS.BETAS, diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.js b/src/pages/tasks/TaskShareDestinationSelectorModal.js index ed4fadd906d9..f41ccfd69521 100644 --- a/src/pages/tasks/TaskShareDestinationSelectorModal.js +++ b/src/pages/tasks/TaskShareDestinationSelectorModal.js @@ -182,7 +182,7 @@ export default compose( key: ONYXKEYS.COLLECTION.REPORT, }, personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, betas: { key: ONYXKEYS.BETAS, diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.js b/src/pages/workspace/WorkspaceInviteMessagePage.js index bf0bad6710e6..327e387c9d2e 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.js +++ b/src/pages/workspace/WorkspaceInviteMessagePage.js @@ -216,7 +216,7 @@ export default compose( withPolicyAndFullscreenLoading, withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, betas: { key: ONYXKEYS.BETAS, diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index 60eb0a4c4dcc..f724485ed3ca 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -318,7 +318,7 @@ export default compose( withNetwork(), withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, betas: { key: ONYXKEYS.BETAS, diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 5206c34c1a49..e65510ba7ed4 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -505,7 +505,7 @@ export default compose( withNetwork(), withOnyx({ personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, session: { key: ONYXKEYS.SESSION, diff --git a/tests/perf-test/SidebarLinks.perf-test.js b/tests/perf-test/SidebarLinks.perf-test.js index eb2a243d1c06..4600f42bfd1d 100644 --- a/tests/perf-test/SidebarLinks.perf-test.js +++ b/tests/perf-test/SidebarLinks.perf-test.js @@ -49,7 +49,7 @@ test('simple Sidebar render with hundred of reports', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, ...mockOnyxReports, }), ) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index aac173d7e1e4..1e7a0c217562 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -185,7 +185,7 @@ function signInAndGetAppWithUnreadChat() { 8: TestHelper.buildTestReportComment(USER_B_EMAIL, MOMENT_TEN_MINUTES_AGO.clone().add(80, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '8'), 9: TestHelper.buildTestReportComment(USER_B_EMAIL, reportAction9CreatedDate, USER_B_ACCOUNT_ID, '9'), }); - Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, { + Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [USER_B_EMAIL]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'), }); @@ -331,7 +331,7 @@ describe('Unread Indicators', () => { }, { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [USER_C_EMAIL]: TestHelper.buildPersonalDetails(USER_C_EMAIL, USER_C_ACCOUNT_ID, 'C'), }, diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 7e6fb4146ca6..610b523d5bec 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -261,7 +261,7 @@ describe('OptionsListUtils', () => { }, }); Onyx.registerLogger(() => {}); - return waitForPromisesToResolve().then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS, PERSONAL_DETAILS)); + return waitForPromisesToResolve().then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, PERSONAL_DETAILS)); }); it('getSearchOptions()', () => { @@ -290,7 +290,7 @@ describe('OptionsListUtils', () => { expect(results.recentReports[1].text).toBe('Mister Fantastic'); return waitForPromisesToResolve() - .then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS, PERSONAL_DETAILS_WITH_PERIODS)) + .then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, PERSONAL_DETAILS_WITH_PERIODS)) .then(() => { // When we filter again but provide a searchValue that should match with periods results = OptionsListUtils.getSearchOptions(REPORTS, PERSONAL_DETAILS_WITH_PERIODS, 'barryallen@expensify.com'); diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index f0f4cc85b8f2..2fbbcaae07e4 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -41,7 +41,7 @@ Onyx.init({keys: ONYXKEYS}); describe('ReportUtils', () => { beforeAll(() => { Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS]: participantsPersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: participantsPersonalDetails, [ONYXKEYS.SESSION]: {email: currentUserEmail}, [ONYXKEYS.COUNTRY_CODE]: 1, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, @@ -329,7 +329,7 @@ describe('ReportUtils', () => { const participants = _.keys(participantsPersonalDetails); beforeAll(() => { - Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, { + Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [currentUserEmail]: { login: currentUserEmail, }, diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 0c6bc75f5e68..1cdaf9881c6e 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -81,7 +81,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.BETAS]: [], - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -125,7 +125,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.BETAS]: [], - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -177,7 +177,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.BETAS]: [], - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -228,7 +228,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.BETAS]: [], - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, }), @@ -315,7 +315,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, @@ -359,7 +359,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -429,7 +429,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${draftReport.reportID}`]: draftReport, [`${ONYXKEYS.COLLECTION.REPORT}${pinnedReport.reportID}`]: pinnedReport, }), @@ -476,7 +476,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${archivedReport.reportID}`]: archivedReport, [`${ONYXKEYS.COLLECTION.REPORT}${archivedPolicyRoomReport.reportID}`]: archivedPolicyRoomReport, [`${ONYXKEYS.COLLECTION.REPORT}${archivedUserCreatedPolicyRoomReport.reportID}`]: archivedUserCreatedPolicyRoomReport, @@ -538,7 +538,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${policyRoomReport.reportID}`]: policyRoomReport, [`${ONYXKEYS.COLLECTION.REPORT}${userCreatedPolicyRoomReport.reportID}`]: userCreatedPolicyRoomReport, }), @@ -636,7 +636,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, @@ -687,7 +687,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -737,7 +737,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -785,7 +785,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -829,7 +829,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, [ONYXKEYS.BETAS]: betas, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index 2f929cb4e1a6..c5287b1883df 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -60,7 +60,7 @@ describe('Sidebar', () => { // When Onyx is updated with some personal details .then(() => Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, }), ) @@ -84,7 +84,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -116,7 +116,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -153,7 +153,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -190,7 +190,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -236,7 +236,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -280,7 +280,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -316,7 +316,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -377,7 +377,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.SESSION]: {email: currentlyLoggedInUserEmail}, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, @@ -429,7 +429,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -488,7 +488,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -542,7 +542,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.BETAS]: betas, [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -578,7 +578,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -632,7 +632,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.BETAS]: betas, [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -717,7 +717,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.SESSION]: {email: currentlyLoggedInUserEmail}, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, @@ -765,7 +765,7 @@ describe('Sidebar', () => { .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index ceff6b0d106f..566ba8ba2734 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -58,7 +58,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.BETAS]: betas, [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, }), ) @@ -100,7 +100,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.BETAS]: betas, [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`]: report, [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`]: {[action.reportActionId]: action}, }), diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js index 65bc2c631aae..a73b50d1f957 100644 --- a/tests/utils/TestHelper.js +++ b/tests/utils/TestHelper.js @@ -62,7 +62,7 @@ function signInWithTestUser(accountID = 1, login = 'test@user.com', password = ' }, { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [login]: buildPersonalDetails(login, accountID, firstName), }, @@ -189,7 +189,7 @@ function getGlobalFetchMock() { * @returns {Promise} */ function setPersonalDetails(login, accountID) { - Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, { + Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { [login]: buildPersonalDetails(login, accountID), }); return waitForPromisesToResolve(); From 7a95a3a6e29ce0b8523079e46700a4e76fc2ff84 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 6 Jun 2023 18:39:47 -0400 Subject: [PATCH 02/60] Use accountID to get avatars --- src/libs/UserUtils.js | 56 +++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/libs/UserUtils.js b/src/libs/UserUtils.js index e7d8235f0004..776ff45318ec 100644 --- a/src/libs/UserUtils.js +++ b/src/libs/UserUtils.js @@ -66,32 +66,32 @@ function getLoginListBrickRoadIndicator(loginList) { /** * Hashes provided string and returns a value between [0, range) - * @param {String} login + * @param {String} text * @param {Number} range * @returns {Number} */ -function hashLogin(login, range) { - return Math.abs(hashCode(login.toLowerCase())) % range; +function hashText(text, range) { + return Math.abs(hashCode(text.toLowerCase())) % range; } /** - * Helper method to return the default avatar associated with the given login - * @param {String} [login] + * Helper method to return the default avatar associated with the given accountID + * @param {Number} [accountID] * @returns {String} */ -function getDefaultAvatar(login = '') { - if (!login) { +function getDefaultAvatar(accountID = -1) { + if (accountID <= 0) { return Expensicons.FallbackAvatar; } - if (login === CONST.EMAIL.CONCIERGE) { + if (accountID === CONST.EMAIL.CONCIERGE) { return Expensicons.ConciergeAvatar; } // There are 24 possible default avatars, so we choose which one this user has based // on a simple hash of their login. Note that Avatar count starts at 1. - const loginHashBucket = hashLogin(login, CONST.DEFAULT_AVATAR_COUNT) + 1; + const accountIDHashBucket = hashText(accountID.toString(), CONST.DEFAULT_AVATAR_COUNT) + 1; - return defaultAvatars[`Avatar${loginHashBucket}`]; + return defaultAvatars[`Avatar${accountIDHashBucket}`]; } /** @@ -101,17 +101,17 @@ function getDefaultAvatar(login = '') { * @param {Boolean} [isNewDot] * @returns {String} */ -function getDefaultAvatarURL(login = '', isNewDot = false) { - if (login === CONST.EMAIL.CONCIERGE) { +function getDefaultAvatarURL(accountID = '', isNewDot = false) { + if (accountID === CONST.EMAIL.CONCIERGE) { return CONST.CONCIERGE_ICON_URL; } - // The default avatar for a user is based on a simple hash of their login. + // The default avatar for a user is based on a simple hash of their accountID. // Note that Avatar count starts at 1 which is why 1 has to be added to the result (or else 0 would result in a broken avatar link) - const loginHashBucket = hashLogin(login, isNewDot ? CONST.DEFAULT_AVATAR_COUNT : CONST.OLD_DEFAULT_AVATAR_COUNT) + 1; + const accountIDHashBucket = hashText(accountID, isNewDot ? CONST.DEFAULT_AVATAR_COUNT : CONST.OLD_DEFAULT_AVATAR_COUNT) + 1; const avatarPrefix = isNewDot ? `default-avatar` : `avatar`; - return `${CONST.CLOUDFRONT_URL}/images/avatars/${avatarPrefix}_${loginHashBucket}.png`; + return `${CONST.CLOUDFRONT_URL}/images/avatars/${avatarPrefix}_${accountIDHashBucket}.png`; } /** @@ -139,11 +139,11 @@ function isDefaultAvatar(avatarURL) { * Otherwise, return the URL pointing to a user-uploaded avatar. * * @param {String} avatarURL - the avatar source from user's personalDetails - * @param {String} login - the email of the user + * @param {Number} accountID - the accountID of the user * @returns {String|Function} */ -function getAvatar(avatarURL, login) { - return isDefaultAvatar(avatarURL) ? getDefaultAvatar(login) : avatarURL; +function getAvatar(avatarURL, accountID) { + return isDefaultAvatar(avatarURL) ? getDefaultAvatar(accountID) : avatarURL; } /** @@ -151,11 +151,11 @@ function getAvatar(avatarURL, login) { * Otherwise, return the URL pointing to a user-uploaded avatar. * * @param {String} avatarURL - the avatar source from user's personalDetails - * @param {String} login - the email of the user + * @param {Number} accountID - the accountID of the user * @returns {String} */ -function getAvatarUrl(avatarURL, login) { - return isDefaultAvatar(avatarURL) ? getDefaultAvatarURL(login, true) : avatarURL; +function getAvatarUrl(avatarURL, accountID) { + return isDefaultAvatar(avatarURL) ? getDefaultAvatarURL(accountID, true) : avatarURL; } /** @@ -163,11 +163,11 @@ function getAvatarUrl(avatarURL, login) { * This removes that part of the URL so the full version of the image can load. * * @param {String} [avatarURL] - * @param {String} [login] + * @param {Number} [accountID] * @returns {String|Function} */ -function getFullSizeAvatar(avatarURL, login) { - const source = getAvatar(avatarURL, login); +function getFullSizeAvatar(avatarURL, accountID) { + const source = getAvatar(avatarURL, accountID); if (!_.isString(source)) { return source; } @@ -179,11 +179,11 @@ function getFullSizeAvatar(avatarURL, login) { * source URL (before the file type) if it doesn't exist there already. * * @param {String} avatarURL - * @param {String} login + * @param {Number} accountID * @returns {String|Function} */ -function getSmallSizeAvatar(avatarURL, login) { - const source = getAvatar(avatarURL, login); +function getSmallSizeAvatar(avatarURL, accountID) { + const source = getAvatar(avatarURL, accountID); if (!_.isString(source)) { return source; } @@ -202,7 +202,7 @@ function getSmallSizeAvatar(avatarURL, login) { } export { - hashLogin, + hashText, hasLoginListError, hasLoginListInfo, getLoginListBrickRoadIndicator, From 410cb62d2f8beefeec6a0b955d82d3242c7513db Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 6 Jun 2023 18:40:03 -0400 Subject: [PATCH 03/60] Update to new function name --- src/styles/StyleUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index fa3209b1f2da..09a0e9b76154 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -187,7 +187,7 @@ function getAvatarBorderStyle(size, type) { * @returns {Object} */ function getDefaultWorkspaceAvatarColor(workspaceName) { - const colorHash = UserUtils.hashLogin(workspaceName.trim(), workspaceColorOptions.length); + const colorHash = UserUtils.hashText(workspaceName.trim(), workspaceColorOptions.length); return workspaceColorOptions[colorHash]; } From 7f0a66d0ec2d3855d40a74bcc33b3cb1c0230c99 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 6 Jun 2023 18:46:59 -0400 Subject: [PATCH 04/60] Migrate email to accountID where possible --- src/libs/ReportUtils.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index ba3ba2e76598..3d9b2bf20104 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -59,7 +59,7 @@ let currentUserPersonalDetails; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { - currentUserPersonalDetails = lodashGet(val, currentUserEmail, {}); + currentUserPersonalDetails = lodashGet(val, currentUserAccountID, {}); allPersonalDetails = val; }, }); @@ -1129,12 +1129,12 @@ function buildOptimisticAddCommentReportAction(text, file) { person: [ { style: 'strong', - text: lodashGet(allPersonalDetails, [currentUserEmail, 'displayName'], currentUserEmail), + text: lodashGet(allPersonalDetails, [currentUserAccountID, 'displayName'], currentUserEmail), type: 'TEXT', }, ], automatic: false, - avatar: lodashGet(allPersonalDetails, [currentUserEmail, 'avatar'], UserUtils.getDefaultAvatar(currentUserEmail)), + avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatar(currentUserAccountID)), created: DateUtils.getDBTime(), message: [ { @@ -1350,7 +1350,7 @@ function buildOptimisticIOUReportAction(type, amount, currency, comment, partici actorAccountID: currentUserAccountID, actorEmail: currentUserEmail, automatic: false, - avatar: lodashGet(currentUserPersonalDetails, 'avatar', UserUtils.getDefaultAvatar(currentUserEmail)), + avatar: lodashGet(currentUserPersonalDetails, 'avatar', UserUtils.getDefaultAvatar(currentUserAccountID)), isAttachment: false, originalMessage, message: getIOUReportActionMessage(type, amount, comment, currency, paymentType, isSettlingUp), @@ -1388,6 +1388,7 @@ function buildOptimisticReportPreview(reportID, iouReportID, payeeAccountID) { linkedReportID: iouReportID, }, actorEmail: currentUserEmail, + actorAccountID: currentUserAccountID, }; } @@ -1403,7 +1404,7 @@ function buildOptimisticTaskReportAction(taskReportID, actionName, message = '') actorAccountID: currentUserAccountID, actorEmail: currentUserEmail, automatic: false, - avatar: lodashGet(currentUserPersonalDetails, 'avatar', UserUtils.getDefaultAvatar(currentUserEmail)), + avatar: lodashGet(currentUserPersonalDetails, 'avatar', UserUtils.getDefaultAvatar(currentUserAccountID)), isAttachment: false, originalMessage, message: [ @@ -1416,7 +1417,7 @@ function buildOptimisticTaskReportAction(taskReportID, actionName, message = '') person: [ { style: 'strong', - text: lodashGet(currentUserPersonalDetails, 'displayName', currentUserEmail), + text: lodashGet(currentUserPersonalDetails, 'displayName', currentUserAccountID), type: 'TEXT', }, ], @@ -1513,11 +1514,11 @@ function buildOptimisticCreatedReportAction(ownerEmail) { { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'strong', - text: lodashGet(allPersonalDetails, [currentUserEmail, 'displayName'], currentUserEmail), + text: lodashGet(allPersonalDetails, [currentUserAccountID, 'displayName'], currentUserEmail), }, ], automatic: false, - avatar: lodashGet(allPersonalDetails, [currentUserEmail, 'avatar'], UserUtils.getDefaultAvatar(currentUserEmail)), + avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatar(currentUserAccountID)), created: DateUtils.getDBTime(), shouldShow: true, }; @@ -1553,11 +1554,11 @@ function buildOptimisticEditedTaskReportAction(ownerEmail) { { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'strong', - text: lodashGet(allPersonalDetails, [currentUserEmail, 'displayName'], currentUserEmail), + text: lodashGet(allPersonalDetails, [currentUserAccountID, 'displayName'], currentUserEmail), }, ], automatic: false, - avatar: lodashGet(allPersonalDetails, [currentUserEmail, 'avatar'], UserUtils.getDefaultAvatar(currentUserEmail)), + avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatar(currentUserAccountID)), created: DateUtils.getDBTime(), shouldShow: false, }; @@ -1576,7 +1577,7 @@ function buildOptimisticClosedReportAction(ownerEmail, policyName, reason = CONS actionName: CONST.REPORT.ACTIONS.TYPE.CLOSED, actorAccountID: currentUserAccountID, automatic: false, - avatar: lodashGet(allPersonalDetails, [currentUserEmail, 'avatar'], UserUtils.getDefaultAvatar(currentUserEmail)), + avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatar(currentUserAccountID)), created: DateUtils.getDBTime(), message: [ { @@ -1599,7 +1600,7 @@ function buildOptimisticClosedReportAction(ownerEmail, policyName, reason = CONS { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'strong', - text: lodashGet(allPersonalDetails, [currentUserEmail, 'displayName'], currentUserEmail), + text: lodashGet(allPersonalDetails, [currentUserAccountID, 'displayName'], currentUserEmail), }, ], reportActionID: NumberUtils.rand64(), From 54ecbcb238dae7bf9914b46e5fcac6dba6a4afdc Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 6 Jun 2023 18:51:16 -0400 Subject: [PATCH 05/60] Update a few tests with accountID-keyed details --- tests/unit/SidebarOrderTest.js | 2 +- tests/utils/LHNTestUtils.js | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index c5287b1883df..544a04e2a793 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -12,7 +12,7 @@ jest.mock('../../src/libs/Permissions'); jest.mock('../../src/components/Icon/Expensicons'); const ONYXKEYS = { - PERSONAL_DETAILS: 'personalDetails', + PERSONAL_DETAILS_LIST: 'personalDetailsList', NVP_PRIORITY_MODE: 'nvp_priorityMode', SESSION: 'session', BETAS: 'betas', diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index 1540964fcb46..fbb273d76c5e 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -26,55 +26,64 @@ jest.mock('@react-navigation/native', () => { }); const fakePersonalDetails = { - 'email1@test.com': { + 1: { + accountID: 1, login: 'email1@test.com', displayName: 'Email One', avatar: 'none', firstName: 'One', }, - 'email2@test.com': { + 2: { + accountID: 2, login: 'email2@test.com', displayName: 'Email Two', avatar: 'none', firstName: 'Two', }, - 'email3@test.com': { + 3: { + accountID: 3, login: 'email3@test.com', displayName: 'Email Three', avatar: 'none', firstName: 'Three', }, - 'email4@test.com': { + 4: { + accountID: 4, login: 'email4@test.com', displayName: 'Email Four', avatar: 'none', firstName: 'Four', }, - 'email5@test.com': { + 5: { + accountID: 5, login: 'email5@test.com', displayName: 'Email Five', avatar: 'none', firstName: 'Five', }, - 'email6@test.com': { + 6: { + accountID: 6, login: 'email6@test.com', displayName: 'Email Six', avatar: 'none', firstName: 'Six', }, - 'email7@test.com': { + 7: { + accountID: 7, login: 'email7@test.com', displayName: 'Email Seven', avatar: 'none', firstName: 'Seven', }, - 'email8@test.com': { + 8: { + accountID: 8, login: 'email8@test.com', displayName: 'Email Eight', avatar: 'none', firstName: 'Eight', }, - 'email9@test.com': { + 9: { + accountID: 9, login: 'email9@test.com', displayName: 'Email Nine', avatar: 'none', From b9d30ef21f84480a6f36a208b3597aa8b7073aa0 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Tue, 6 Jun 2023 18:58:16 -0400 Subject: [PATCH 06/60] Fix lots of accountID tests --- tests/ui/UnreadIndicatorsTest.js | 4 +-- tests/unit/OptionsListUtilsTest.js | 42 ++++++++++++++++++++---------- tests/unit/ReportUtilsTest.js | 18 ++++++++----- tests/utils/TestHelper.js | 4 +-- 4 files changed, 44 insertions(+), 24 deletions(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 1e7a0c217562..ba5b6c2e823c 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -186,7 +186,7 @@ function signInAndGetAppWithUnreadChat() { 9: TestHelper.buildTestReportComment(USER_B_EMAIL, reportAction9CreatedDate, USER_B_ACCOUNT_ID, '9'), }); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { - [USER_B_EMAIL]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'), + [USER_B_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'), }); // We manually setting the sidebar as loaded since the onLayout event does not fire in tests @@ -333,7 +333,7 @@ describe('Unread Indicators', () => { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [USER_C_EMAIL]: TestHelper.buildPersonalDetails(USER_C_EMAIL, USER_C_ACCOUNT_ID, 'C'), + [USER_C_ACCOUNT_ID]: TestHelper.buildPersonalDetails(USER_C_EMAIL, USER_C_ACCOUNT_ID, 'C'), }, }, ]); diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 610b523d5bec..95986953610a 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -109,45 +109,55 @@ describe('OptionsListUtils', () => { // And a set of personalDetails some with existing reports and some without const PERSONAL_DETAILS = { // These exist in our reports - 'reedrichards@expensify.com': { + 1: { + accountID: 1, displayName: 'Mister Fantastic', login: 'reedrichards@expensify.com', }, - 'tonystark@expensify.com': { + 2: { + accountID: 2, displayName: 'Iron Man', login: 'tonystark@expensify.com', }, - 'peterparker@expensify.com': { + 3: { + accountID: 3, displayName: 'Spider-Man', login: 'peterparker@expensify.com', }, - 'tchalla@expensify.com': { + 4: { + accountID: 4, displayName: 'Black Panther', login: 'tchalla@expensify.com', }, - 'suestorm@expensify.com': { + 5: { + accountID: 5, displayName: 'Invisible Woman', login: 'suestorm@expensify.com', }, - 'thor@expensify.com': { + 6: { + accountID: 6, displayName: 'Thor', login: 'thor@expensify.com', }, - 'steverogers@expensify.com': { + 7: { + accountID: 7, displayName: 'Captain America', login: 'steverogers@expensify.com', }, - 'mistersinister@marauders.com': { + 8: { + accountID: 8, displayName: 'Mr Sinister', login: 'mistersinister@marauders.com', }, // These do not exist in reports at all - 'natasharomanoff@expensify.com': { + 9: { + accountID: 9, displayName: 'Black Widow', login: 'natasharomanoff@expensify.com', }, - 'brucebanner@expensify.com': { + 10: { + accountID: 10, displayName: 'The Incredible Hulk', login: 'brucebanner@expensify.com', }, @@ -209,7 +219,8 @@ describe('OptionsListUtils', () => { const PERSONAL_DETAILS_WITH_CONCIERGE = { ...PERSONAL_DETAILS, - 'concierge@expensify.com': { + 999: { + accountID: 999, displayName: 'Concierge', login: 'concierge@expensify.com', }, @@ -218,7 +229,8 @@ describe('OptionsListUtils', () => { const PERSONAL_DETAILS_WITH_CHRONOS = { ...PERSONAL_DETAILS, - 'chronos@expensify.com': { + 1000: { + accountID: 1000, displayName: 'Chronos', login: 'chronos@expensify.com', }, @@ -227,7 +239,8 @@ describe('OptionsListUtils', () => { const PERSONAL_DETAILS_WITH_RECEIPTS = { ...PERSONAL_DETAILS, - 'receipts@expensify.com': { + 1001: { + accountID: 1001, displayName: 'Receipts', login: 'receipts@expensify.com', }, @@ -236,7 +249,8 @@ describe('OptionsListUtils', () => { const PERSONAL_DETAILS_WITH_PERIODS = { ...PERSONAL_DETAILS, - 'barry.allen@expensify.com': { + 1002: { + accountID: 1002, displayName: 'The Flash', login: 'barry.allen@expensify.com', }, diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index 2fbbcaae07e4..d56e1fdf6b25 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -10,23 +10,28 @@ import * as LHNTestUtils from '../utils/LHNTestUtils'; jest.mock('../../src/libs/Permissions'); const currentUserEmail = 'bjorn@vikings.net'; +const currentUserAccountID = 5; const participantsPersonalDetails = { - 'ragnar@vikings.net': { + 1: { + accountID: 1, displayName: 'Ragnar Lothbrok', firstName: 'Ragnar', login: 'ragnar@vikings.net', }, - 'floki@vikings.net': { + 2: { + accountID: 2, login: 'floki@vikings.net', displayName: 'floki@vikings.net', }, - 'lagertha@vikings.net': { + 3: { + accountID: 3, displayName: 'Lagertha Lothbrok', firstName: 'Lagertha', login: 'lagertha@vikings.net', pronouns: 'She/her', }, - '+18332403627@expensify.sms': { + 4: { + accountID: 4, login: '+18332403627@expensify.sms', displayName: '(833) 240-3627', }, @@ -42,7 +47,7 @@ describe('ReportUtils', () => { beforeAll(() => { Onyx.multiSet({ [ONYXKEYS.PERSONAL_DETAILS_LIST]: participantsPersonalDetails, - [ONYXKEYS.SESSION]: {email: currentUserEmail}, + [ONYXKEYS.SESSION]: {email: currentUserEmail, accountID: currentUserAccountID}, [ONYXKEYS.COUNTRY_CODE]: 1, [`${ONYXKEYS.COLLECTION.POLICY}${policy.policyID}`]: policy, }); @@ -330,7 +335,8 @@ describe('ReportUtils', () => { beforeAll(() => { Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { - [currentUserEmail]: { + [currentUserAccountID]: { + accountID: currentUserAccountID, login: currentUserEmail, }, }); diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js index a73b50d1f957..4f3cf2d61aa6 100644 --- a/tests/utils/TestHelper.js +++ b/tests/utils/TestHelper.js @@ -64,7 +64,7 @@ function signInWithTestUser(accountID = 1, login = 'test@user.com', password = ' onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [login]: buildPersonalDetails(login, accountID, firstName), + [accountID]: buildPersonalDetails(login, accountID, firstName), }, }, ], @@ -190,7 +190,7 @@ function getGlobalFetchMock() { */ function setPersonalDetails(login, accountID) { Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { - [login]: buildPersonalDetails(login, accountID), + [accountID]: buildPersonalDetails(login, accountID), }); return waitForPromisesToResolve(); } From e5bc39bd6970a6313e41acbd194134333682fcbb Mon Sep 17 00:00:00 2001 From: burczu Date: Wed, 7 Jun 2023 12:47:30 +0200 Subject: [PATCH 07/60] SidebarFilterTest fixed --- src/pages/home/sidebar/SidebarLinks.js | 4 ++-- tests/unit/SidebarFilterTest.js | 2 +- tests/unit/SidebarTest.js | 2 +- tests/utils/LHNTestUtils.js | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index bb790aad74fe..eb5f9efb85a2 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -262,10 +262,10 @@ const chatReportSelector = (report) => const personalDetailsSelector = (personalDetails) => _.reduce( personalDetails, - (finalPersonalDetails, personalData, login) => { + (finalPersonalDetails, personalData, accountID) => { // It's OK to do param-reassignment in _.reduce() because we absolutely know the starting state of finalPersonalDetails // eslint-disable-next-line no-param-reassign - finalPersonalDetails[login] = { + finalPersonalDetails[accountID] = { login: personalData.login, displayName: personalData.displayName, firstName: personalData.firstName, diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 1cdaf9881c6e..f79b5e2f2ddd 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -11,7 +11,7 @@ import * as Localize from '../../src/libs/Localize'; jest.mock('../../src/libs/Permissions'); const ONYXKEYS = { - PERSONAL_DETAILS: 'personalDetails', + PERSONAL_DETAILS_LIST: 'personalDetailsList', NVP_PRIORITY_MODE: 'nvp_priorityMode', SESSION: 'session', BETAS: 'betas', diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index 566ba8ba2734..9b5b021341ac 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -11,7 +11,7 @@ jest.mock('../../src/libs/Permissions'); jest.mock('../../src/components/Icon/Expensicons'); const ONYXKEYS = { - PERSONAL_DETAILS: 'personalDetails', + PERSONAL_DETAILS_LIST: 'personalDetailsList', NVP_PRIORITY_MODE: 'nvp_priorityMode', SESSION: 'session', BETAS: 'betas', diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index fbb273d76c5e..601b14487b4c 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -95,12 +95,12 @@ let lastFakeReportID = 0; let lastFakeReportActionID = 0; /** - * @param {String[]} participants + * @param {Number[]} participants * @param {Number} millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages) * @param {boolean} isUnread * @returns {Object} */ -function getFakeReport(participants = ['email1@test.com', 'email2@test.com'], millisecondsInThePast = 0, isUnread = false) { +function getFakeReport(participants = [1, 2], millisecondsInThePast = 0, isUnread = false) { const lastVisibleActionCreated = DateUtils.getDBTime(Date.now() - millisecondsInThePast); return { type: CONST.REPORT.TYPE.CHAT, From d547dab2f763890197ee37ba031ca26de401189b Mon Sep 17 00:00:00 2001 From: burczu Date: Wed, 7 Jun 2023 13:02:55 +0200 Subject: [PATCH 08/60] SidebarOrderTest fixed --- tests/unit/SidebarOrderTest.js | 92 +++++++++++++++++----------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index 544a04e2a793..b2072f66ed03 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -75,7 +75,7 @@ describe('Sidebar', () => { it('contains one report when a report is in Onyx', () => { // Given a single report - const report = LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']); + const report = LHNTestUtils.getFakeReport([1, 2]); LHNTestUtils.getDefaultRenderedSidebarLinks(report.reportID); return ( @@ -101,13 +101,13 @@ describe('Sidebar', () => { // Given three unread reports in the recently updated order of 3, 2, 1 const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3), + ...LHNTestUtils.getFakeReport([1, 2], 3), }; const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2), + ...LHNTestUtils.getFakeReport([3, 4], 2), }; const report3 = { - ...LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1), + ...LHNTestUtils.getFakeReport([5, 6], 1), }; return ( @@ -140,11 +140,11 @@ describe('Sidebar', () => { // And the first report has a draft // And the currently viewed report is the first report const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3), + ...LHNTestUtils.getFakeReport([1, 2], 3), hasDraft: true, }; - const report2 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2); - const report3 = LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1); + const report2 = LHNTestUtils.getFakeReport([3, 4], 2); + const report3 = LHNTestUtils.getFakeReport([5, 6], 1); const reportIDFromRoute = report1.reportID; LHNTestUtils.getDefaultRenderedSidebarLinks(reportIDFromRoute); return ( @@ -180,9 +180,9 @@ describe('Sidebar', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); // Given three reports in the recently updated order of 3, 2, 1 - const report1 = LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3); - const report2 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2); - const report3 = LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1); + const report1 = LHNTestUtils.getFakeReport([1, 2], 3); + const report2 = LHNTestUtils.getFakeReport([3, 4], 2); + const report3 = LHNTestUtils.getFakeReport([5, 6], 1); return ( waitForPromisesToResolve() @@ -221,12 +221,12 @@ describe('Sidebar', () => { // Given three reports in the recently updated order of 3, 2, 1 // And the second report has a draft // And the currently viewed report is the second report - const report1 = LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3); + const report1 = LHNTestUtils.getFakeReport([1, 2], 3); const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2), + ...LHNTestUtils.getFakeReport([3, 4], 2), hasDraft: true, }; - const report3 = LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1); + const report3 = LHNTestUtils.getFakeReport([5, 6], 1); const reportIDFromRoute = report2.reportID; LHNTestUtils.getDefaultRenderedSidebarLinks(reportIDFromRoute); @@ -270,7 +270,7 @@ describe('Sidebar', () => { // Given a single report // And the report has a draft const report = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), hasDraft: true, }; @@ -306,7 +306,7 @@ describe('Sidebar', () => { // Given a single report // And the report is pinned const report = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), isPinned: true, }; @@ -342,22 +342,22 @@ describe('Sidebar', () => { // with a report that has a draft, a report that is pinned, and // an outstanding IOU report that doesn't belong to the current user const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3), + ...LHNTestUtils.getFakeReport([1, 2], 3), isPinned: true, }; const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2), + ...LHNTestUtils.getFakeReport([3, 4], 2), hasDraft: true, }; const report3 = { - ...LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1), + ...LHNTestUtils.getFakeReport([5, 6], 1), hasOutstandingIOU: true, // This has to be added after the IOU report is generated iouReportID: null, }; const iouReport = { - ...LHNTestUtils.getFakeReport(['email7@test.com', 'email8@test.com']), + ...LHNTestUtils.getFakeReport([7, 8]), type: CONST.REPORT.TYPE.IOU, ownerEmail: 'email2@test.com', managerEmail: 'email2@test.com', @@ -407,19 +407,19 @@ describe('Sidebar', () => { // Given three reports in the recently updated order of 3, 2, 1 // and they are all pinned const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3), + ...LHNTestUtils.getFakeReport([1, 2], 3), isPinned: true, }; const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2), + ...LHNTestUtils.getFakeReport([3, 4], 2), isPinned: true, }; const report3 = { - ...LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1), + ...LHNTestUtils.getFakeReport([5, 6], 1), isPinned: true, }; const report4 = { - ...LHNTestUtils.getFakeReport(['email7@test.com', 'email8@test.com'], 0), + ...LHNTestUtils.getFakeReport([7, 8], 0), isPinned: true, }; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); @@ -466,19 +466,19 @@ describe('Sidebar', () => { // Given three reports in the recently updated order of 3, 2, 1 // and they all have drafts const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3), + ...LHNTestUtils.getFakeReport([1, 2], 3), hasDraft: true, }; const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2), + ...LHNTestUtils.getFakeReport([3, 4], 2), hasDraft: true, }; const report3 = { - ...LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1), + ...LHNTestUtils.getFakeReport([5, 6], 1), hasDraft: true, }; const report4 = { - ...LHNTestUtils.getFakeReport(['email7@test.com', 'email8@test.com'], 0), + ...LHNTestUtils.getFakeReport([7, 8], 0), hasDraft: true, }; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); @@ -524,13 +524,13 @@ describe('Sidebar', () => { it('puts archived chats last', () => { // Given three reports, with the first report being archived const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }; - const report2 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']); - const report3 = LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com']); + const report2 = LHNTestUtils.getFakeReport([3, 4]); + const report3 = LHNTestUtils.getFakeReport([5, 6]); // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS, CONST.BETAS.POLICY_EXPENSE_CHAT]; @@ -566,10 +566,10 @@ describe('Sidebar', () => { it('alphabetizes chats', () => { LHNTestUtils.getDefaultRenderedSidebarLinks(); - const report1 = LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3, true); - const report2 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2, true); - const report3 = LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1, true); - const report4 = LHNTestUtils.getFakeReport(['email7@test.com', 'email8@test.com'], 0, true); + const report1 = LHNTestUtils.getFakeReport([1, 2], 3, true); + const report2 = LHNTestUtils.getFakeReport([3, 4], 2, true); + const report3 = LHNTestUtils.getFakeReport([5, 6], 1, true); + const report4 = LHNTestUtils.getFakeReport([7, 8], 0, true); return ( waitForPromisesToResolve() @@ -614,13 +614,13 @@ describe('Sidebar', () => { it('puts archived chats last', () => { // Given three unread reports, with the first report being archived const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3, true), + ...LHNTestUtils.getFakeReport([1, 2], 3, true), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }; - const report2 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 2, true); - const report3 = LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com'], 1, true); + const report2 = LHNTestUtils.getFakeReport([3, 4], 2, true); + const report3 = LHNTestUtils.getFakeReport([5, 6], 1, true); // Given the user is in all betas const betas = [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS, CONST.BETAS.POLICY_EXPENSE_CHAT]; @@ -654,28 +654,28 @@ describe('Sidebar', () => { it('orders IOU reports by displayName if amounts are the same', () => { // Given three IOU reports containing the same IOU amounts const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), hasOutstandingIOU: true, // This has to be added after the IOU report is generated iouReportID: null, }; const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']), + ...LHNTestUtils.getFakeReport([3, 4]), hasOutstandingIOU: true, // This has to be added after the IOU report is generated iouReportID: null, }; const report3 = { - ...LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com']), + ...LHNTestUtils.getFakeReport([5, 6]), hasOutstandingIOU: true, // This has to be added after the IOU report is generated iouReportID: null, }; const iouReport1 = { - ...LHNTestUtils.getFakeReport(['email7@test.com', 'email8@test.com']), + ...LHNTestUtils.getFakeReport([7, 8]), type: CONST.REPORT.TYPE.IOU, ownerEmail: 'email2@test.com', managerEmail: 'email2@test.com', @@ -685,7 +685,7 @@ describe('Sidebar', () => { chatReportID: report3.reportID, }; const iouReport2 = { - ...LHNTestUtils.getFakeReport(['email9@test.com', 'email10@test.com']), + ...LHNTestUtils.getFakeReport([9, 10]), type: CONST.REPORT.TYPE.IOU, ownerEmail: 'email2@test.com', managerEmail: 'email2@test.com', @@ -695,7 +695,7 @@ describe('Sidebar', () => { chatReportID: report3.reportID, }; const iouReport3 = { - ...LHNTestUtils.getFakeReport(['email11@test.com', 'email12@test.com']), + ...LHNTestUtils.getFakeReport([11, 12]), type: CONST.REPORT.TYPE.IOU, ownerEmail: 'email2@test.com', managerEmail: 'email2@test.com', @@ -746,15 +746,15 @@ describe('Sidebar', () => { // Given three nonArchived reports created at the same time const lastVisibleActionCreated = DateUtils.getDBTime(); const report1 = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), lastVisibleActionCreated, }; const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']), + ...LHNTestUtils.getFakeReport([3, 4]), lastVisibleActionCreated, }; const report3 = { - ...LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com']), + ...LHNTestUtils.getFakeReport([5, 6]), lastVisibleActionCreated, }; From 588cb20b4ea3d0d8d645dbed5f515da9527bca03 Mon Sep 17 00:00:00 2001 From: burczu Date: Wed, 7 Jun 2023 14:44:55 +0200 Subject: [PATCH 09/60] JSDoc fixed --- src/libs/UserUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/UserUtils.js b/src/libs/UserUtils.js index 776ff45318ec..2a4cac33ebf1 100644 --- a/src/libs/UserUtils.js +++ b/src/libs/UserUtils.js @@ -97,7 +97,7 @@ function getDefaultAvatar(accountID = -1) { /** * Helper method to return default avatar URL associated with login * - * @param {String} [login] + * @param {String} [accountID] * @param {Boolean} [isNewDot] * @returns {String} */ From ef3d9558f796a6401b1a05d1ecb50c890cf120cd Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Wed, 7 Jun 2023 15:41:21 +0100 Subject: [PATCH 10/60] fix: start migration for getSearchOptions, getOptions and createOption --- src/CONST.js | 4 ++ src/libs/OptionsListUtils.js | 79 +++++++++++++++++------------- src/libs/ReportUtils.js | 20 ++++---- tests/unit/OptionsListUtilsTest.js | 10 ++++ 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 455644e484b1..36847666c2e3 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -872,6 +872,10 @@ const CONST = { GUIDES_DOMAIN: 'team.expensify.com', }, + ACCOUNT_ID: { + CONCIERGE: '8392101', + }, + ENVIRONMENT: { DEV: 'development', STAGING: 'staging', diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index ced088836927..056716a0a086 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -161,36 +161,34 @@ function getAvatarsForLogins(logins, personalDetails) { } /** - * Returns the personal details for an array of logins + * Returns the personal details for an array of accountIDs * - * @param {Array} logins + * @param {Array} accountIDs * @param {Object} personalDetails * @returns {Object} – keys of the object are emails, values are PersonalDetails objects. */ -function getPersonalDetailsForLogins(logins, personalDetails) { +function getPersonalDetailsForAccountIDs(accountIDs, personalDetails) { const personalDetailsForLogins = {}; if (!personalDetails) { return personalDetailsForLogins; } - _.chain(logins) - - // Somehow it's possible for the logins coming from report.participants to contain undefined values so we use compact to remove them. + _.chain(accountIDs) + // Somehow it's possible for the accountIDs coming from report.participantAccountIDs to contain undefined values so we use compact to remove them. .compact() - .each((login) => { - let personalDetail = personalDetails[login]; + .each((accountID) => { + let personalDetail = personalDetails[accountID]; if (!personalDetail) { personalDetail = { - login, - displayName: LocalePhoneNumber.formatPhoneNumber(login), - avatar: UserUtils.getDefaultAvatar(login), + accountID, + avatar: UserUtils.getDefaultAvatar(accountID), }; } - if (login === CONST.EMAIL.CONCIERGE) { + if (accountID === CONST.ACCOUNT_ID.CONCIERGE) { personalDetail.avatar = CONST.CONCIERGE_ICON_URL; } - personalDetailsForLogins[login] = personalDetail; + personalDetailsForLogins[accountID] = personalDetail; }); return personalDetailsForLogins; } @@ -201,7 +199,7 @@ function getPersonalDetailsForLogins(logins, personalDetails) { * @returns {Boolean} */ function isPersonalDetailsReady(personalDetails) { - return !_.isEmpty(personalDetails) && _.some(_.keys(personalDetails), (key) => personalDetails[key].login); + return !_.isEmpty(personalDetails) && _.some(_.keys(personalDetails), (key) => personalDetails[key].accountID); } /** @@ -212,7 +210,7 @@ function isPersonalDetailsReady(personalDetails) { */ function getParticipantsOptions(report, personalDetails) { const participants = lodashGet(report, 'participants', []); - return _.map(getPersonalDetailsForLogins(participants, personalDetails), (details) => ({ + return _.map(getPersonalDetailsForAccountIDs(participants, personalDetails), (details) => ({ keyForList: details.login, login: details.login, text: details.displayName, @@ -302,12 +300,14 @@ function getSearchText(report, reportName, personalDetailList, isChatRoomOrPolic for (let i = 0; i < personalDetailList.length; i++) { const personalDetail = personalDetailList[i]; + if (personalDetail.login) { // The regex below is used to remove dots only from the local part of the user email (local-part@domain) // so that we can match emails that have dots without explicitly writing the dots (e.g: fistlast@domain will match first.last@domain) // More info https://github.com/Expensify/App/issues/8007 searchTerms = searchTerms.concat([personalDetail.displayName, personalDetail.login, personalDetail.login.replace(/\.(?=[^\s@]*@)/g, '')]); } } + } if (report) { Array.prototype.push.apply(searchTerms, reportName.split(/[,\s]/)); @@ -362,7 +362,7 @@ function getAllReportErrors(report, reportActions) { /** * Creates a report list option * - * @param {Array} logins + * @param {Array} accountIDs * @param {Object} personalDetails * @param {Object} report * @param {Object} reportActions @@ -371,7 +371,7 @@ function getAllReportErrors(report, reportActions) { * @param {Boolean} [options.forcePolicyNamePreview] * @returns {Object} */ -function createOption(logins, personalDetails, report, reportActions = {}, {showChatPreviewLine = false, forcePolicyNamePreview = false}) { +function createOption(accountIDs, personalDetails, report, reportActions = {}, {showChatPreviewLine = false, forcePolicyNamePreview = false}) { const result = { text: null, alternateText: null, @@ -402,7 +402,8 @@ function createOption(logins, personalDetails, report, reportActions = {}, {show isPolicyExpenseChat: false, }; - const personalDetailMap = getPersonalDetailsForLogins(logins, personalDetails); + + const personalDetailMap = getPersonalDetailsForAccountIDs(accountIDs, personalDetails); const personalDetailList = _.values(personalDetailMap); const personalDetail = personalDetailList[0] || {}; let hasMultipleParticipants = personalDetailList.length > 1; @@ -443,7 +444,7 @@ function createOption(logins, personalDetails, report, reportActions = {}, {show lastMessageTextFromReport = report ? report.lastMessageText || '' : ''; } - const lastActorDetails = personalDetailMap[report.lastActorEmail] || null; + const lastActorDetails = personalDetailMap[report.lastActorAccountID] || null; let lastMessageText = hasMultipleParticipants && lastActorDetails && lastActorDetails.login !== currentUserLogin ? `${lastActorDetails.displayName}: ` : ''; lastMessageText += report ? lastMessageTextFromReport : ''; @@ -466,10 +467,10 @@ function createOption(logins, personalDetails, report, reportActions = {}, {show } reportName = ReportUtils.getReportName(report); } else { - const login = logins[0]; - reportName = ReportUtils.getDisplayNameForParticipant(login); - result.keyForList = login; - result.alternateText = LocalePhoneNumber.formatPhoneNumber(login); + const accountID = accountIDs[0]; + reportName = ReportUtils.getDisplayNameForParticipant(accountID); + result.keyForList = accountID; + result.alternateText = ''; } result.isIOUReportOwner = ReportUtils.isIOUOwnedByCurrentUser(result, iouReports); @@ -483,7 +484,7 @@ function createOption(logins, personalDetails, report, reportActions = {}, {show result.text = reportName; result.searchText = getSearchText(report, reportName, personalDetailList, result.isChatRoom || result.isPolicyExpenseChat, result.isThread); - result.icons = ReportUtils.getIcons(report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.login)); + result.icons = ReportUtils.getIcons(report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.accountID)); result.subtitle = subtitle; return result; @@ -572,7 +573,7 @@ function getOptions( let recentReportOptions = []; let personalDetailsOptions = []; - const reportMapForLogins = {}; + const reportMapForAccountIDs = {}; const parsedPhoneNumber = parsePhoneNumber(LoginUtils.appendCountryCode(searchInputValue)); const searchValue = parsedPhoneNumber.possible ? parsedPhoneNumber.number.e164 : searchInputValue; @@ -603,7 +604,7 @@ function getOptions( const isChatRoom = ReportUtils.isChatRoom(report); const isTaskReport = ReportUtils.isTaskReport(report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report); - const logins = report.participants || []; + const accountIDs = report.participantAccountIDs || []; if (isPolicyExpenseChat && report.isOwnPolicyExpenseChat && !includeOwnedWorkspaceChats) { return; @@ -620,8 +621,8 @@ function getOptions( // Save the report in the map if this is a single participant so we can associate the reportID with the // personal detail option later. Individuals should not be associated with single participant // policyExpenseChats or chatRooms since those are not people. - if (logins.length <= 1 && !isPolicyExpenseChat && !isChatRoom) { - reportMapForLogins[logins[0]] = report; + if (accountIDs.length <= 1 && !isPolicyExpenseChat && !isChatRoom) { + reportMapForAccountIDs[accountIDs[0]] = report; } const isSearchingSomeonesPolicyExpenseChat = !report.isOwnPolicyExpenseChat && searchValue !== ''; @@ -630,7 +631,7 @@ function getOptions( const isPolicyChatAdmin = ReportUtils.isPolicyExpenseChatAdmin(report, policies); allReportOptions.push( - createOption(logins, personalDetails, report, reportActions, { + createOption(accountIDs, personalDetails, report, reportActions, { showChatPreviewLine, forcePolicyNamePreview: isPolicyExpenseChat ? isSearchingSomeonesPolicyExpenseChat || isPolicyChatAdmin : forcePolicyNamePreview, }), @@ -638,7 +639,7 @@ function getOptions( }); let allPersonalDetailsOptions = _.map(personalDetails, (personalDetail) => - createOption([personalDetail.login], personalDetails, reportMapForLogins[personalDetail.login], reportActions, { + createOption([personalDetail.accountID], personalDetails, reportMapForAccountIDs[personalDetail.accountID], reportActions, { showChatPreviewLine, forcePolicyNamePreview, }), @@ -727,15 +728,25 @@ function getOptions( !_.find(loginOptionsToExclude, (loginOptionToExclude) => loginOptionToExclude.login === addSMSDomainIfPhoneNumber(searchValue).toLowerCase()) && (searchValue !== CONST.EMAIL.CHRONOS || Permissions.canUseChronos(betas)) ) { - userToInvite = createOption([searchValue], personalDetails, null, reportActions, { + const searchPersonalDetails = _.find(personalDetails, (personalDetail) => personalDetail.login === searchValue); + if (!searchPersonalDetails) { + return { + recentReports: [], + personalDetails: [], + userToInvite: null, + currentUserOption: null, + }; + } + + userToInvite = createOption([searchPersonalDetails.accountID], personalDetails, null, reportActions, { showChatPreviewLine, }); // If user doesn't exist, use a default avatar userToInvite.icons = [ { - source: UserUtils.getAvatar('', searchValue), - name: searchValue, + source: UserUtils.getAvatar('', searchPersonalDetails.accountID), + name: searchPersonalDetails.login, type: CONST.ICON_TYPE_AVATAR, }, ]; @@ -960,7 +971,7 @@ export { getShareDestinationOptions, getMemberInviteOptions, getHeaderMessage, - getPersonalDetailsForLogins, + getPersonalDetailsForAccountIDs, getIOUConfirmationOptionsFromPayeePersonalDetail, getIOUConfirmationOptionsFromParticipants, getSearchText, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 3d9b2bf20104..f092735d569a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -829,18 +829,16 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) /** * Gets the personal details for a login by looking in the ONYXKEYS.PERSONAL_DETAILS_LIST Onyx key (stored in the local variable, allPersonalDetails). If it doesn't exist in Onyx, * then a default object is constructed. - * @param {String} login + * @param {String} accountID * @returns {Object} */ -function getPersonalDetailsForLogin(login) { - if (!login) { +function getPersonalDetailsForAccountID(accountID) { + if (!accountID) { return {}; } return ( - (allPersonalDetails && allPersonalDetails[login]) || { - login, - displayName: LocalePhoneNumber.formatPhoneNumber(login), - avatar: UserUtils.getDefaultAvatar(login), + (allPersonalDetails && allPersonalDetails[accountID]) || { + avatar: UserUtils.getDefaultAvatar(accountID), } ); } @@ -848,15 +846,15 @@ function getPersonalDetailsForLogin(login) { /** * Get the displayName for a single report participant. * - * @param {String} login + * @param {String} accountID * @param {Boolean} [shouldUseShortForm] * @returns {String} */ -function getDisplayNameForParticipant(login, shouldUseShortForm = false) { - if (!login) { +function getDisplayNameForParticipant(accountID, shouldUseShortForm = false) { + if (!accountID) { return ''; } - const personalDetails = getPersonalDetailsForLogin(login); + const personalDetails = getPersonalDetailsForAccountID(accountID); const longName = personalDetails.displayName; diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 95986953610a..3d31f3d463da 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -14,6 +14,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 1, participants: ['tonystark@expensify.com', 'reedrichards@expensify.com'], + participantAccountIDs: [2, 1], reportName: 'Iron Man, Mister Fantastic', hasDraft: true, }, @@ -23,6 +24,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 2, participants: ['peterparker@expensify.com'], + participantAccountIDs: [3], reportName: 'Spider-Man', }, @@ -33,6 +35,7 @@ describe('OptionsListUtils', () => { isPinned: true, reportID: 3, participants: ['reedrichards@expensify.com'], + participantAccountIDs: [1], reportName: 'Mister Fantastic', }, 4: { @@ -41,6 +44,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 4, participants: ['tchalla@expensify.com'], + participantAccountIDs: [4], reportName: 'Black Panther', }, 5: { @@ -49,6 +53,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 5, participants: ['suestorm@expensify.com'], + participantAccountIDs: [5], reportName: 'Invisible Woman', }, 6: { @@ -57,6 +62,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 6, participants: ['thor@expensify.com'], + participantAccountIDs: [6], reportName: 'Thor', }, @@ -67,6 +73,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 7, participants: ['steverogers@expensify.com'], + participantAccountIDs: [7], reportName: 'Captain America', }, @@ -77,6 +84,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 8, participants: ['galactus_herald@expensify.com'], + participantAccountIDs: [12], reportName: 'Silver Surfer', }, @@ -87,6 +95,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 9, participants: ['mistersinister@marauders.com'], + participantAccountIDs: [8], reportName: 'Mister Sinister', iouReportID: 100, hasOutstandingIOU: true, @@ -99,6 +108,7 @@ describe('OptionsListUtils', () => { reportID: 10, isPinned: false, participants: ['tonystark@expensify.com', 'steverogers@expensify.com'], + participantAccountIDs: [2, 7], reportName: '', oldPolicyName: "SHIELD's workspace", chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, From 5c395d0db61d7ac84e5e8a4c8d67b4b420146026 Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Wed, 7 Jun 2023 16:01:27 +0100 Subject: [PATCH 11/60] fix: complete migration of some report utils to accountID --- src/libs/OptionsListUtils.js | 5 ++--- src/libs/ReportUtils.js | 16 ++++++++++------ tests/unit/OptionsListUtilsTest.js | 5 +++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 056716a0a086..3415cf412084 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -467,9 +467,8 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { } reportName = ReportUtils.getReportName(report); } else { - const accountID = accountIDs[0]; - reportName = ReportUtils.getDisplayNameForParticipant(accountID); - result.keyForList = accountID; + reportName = ReportUtils.getDisplayNameForParticipant(accountIDs[0]); + result.keyForList = accountIDs[0]; result.alternateText = ''; } diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f092735d569a..f910123f69a1 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -23,9 +23,13 @@ import * as CurrencyUtils from './CurrencyUtils'; import * as UserUtils from './UserUtils'; let sessionEmail; +let sessionAccountID; Onyx.connect({ key: ONYXKEYS.SESSION, - callback: (val) => (sessionEmail = val ? val.email : null), + callback: (val) => { + sessionEmail = val ? val.email : null + sessionAccountID = val ? val.accountID : null + }, }); let preferredLocale = CONST.LOCALES.DEFAULT; @@ -941,7 +945,7 @@ function getMoneyRequestTotal(report, moneyRequestReports = {}) { * @returns {String} */ function getPolicyExpenseChatName(report) { - const reportOwnerDisplayName = getDisplayNameForParticipant(report.ownerEmail) || report.ownerEmail || report.reportName; + const reportOwnerDisplayName = getDisplayNameForParticipant(report.ownerAccountID) || report.ownerEmail || report.reportName; // If the policy expense chat is owned by this user, use the name of the policy as the report name. if (report.isOwnPolicyExpenseChat) { @@ -972,7 +976,7 @@ function getPolicyExpenseChatName(report) { */ function getMoneyRequestReportName(report) { const formattedAmount = CurrencyUtils.convertToDisplayString(getMoneyRequestTotal(report), report.currency); - const payerName = isExpenseReport(report) ? getPolicyName(report) : getDisplayNameForParticipant(report.managerEmail); + const payerName = isExpenseReport(report) ? getPolicyName(report) : getDisplayNameForParticipant(report.managerAccountID); return Localize.translateLocal(report.hasOutstandingIOU ? 'iou.payerOwesAmount' : 'iou.payerPaidAmount', {payer: payerName, amount: formattedAmount}); } @@ -1032,11 +1036,11 @@ function getReportName(report) { } // Not a room or PolicyExpenseChat, generate title from participants - const participants = (report && report.participants) || []; - const participantsWithoutCurrentUser = _.without(participants, sessionEmail); + const participants = (report && report.participantAccountIDs) || []; + const participantsWithoutCurrentUser = _.without(participants, sessionAccountID); const isMultipleParticipantReport = participantsWithoutCurrentUser.length > 1; - return _.map(participantsWithoutCurrentUser, (login) => getDisplayNameForParticipant(login, isMultipleParticipantReport)).join(', '); + return _.map(participantsWithoutCurrentUser, (accountID) => getDisplayNameForParticipant(accountID, isMultipleParticipantReport)).join(', '); } /** diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 3d31f3d463da..e2f9e048f437 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -276,9 +276,10 @@ describe('OptionsListUtils', () => { Onyx.init({ keys: ONYXKEYS, initialKeyStates: { - [ONYXKEYS.SESSION]: {email: 'tonystark@expensify.com'}, + [ONYXKEYS.SESSION]: {accountID: 2, email: 'tonystark@expensify.com'}, [`${ONYXKEYS.COLLECTION.REPORT}100`]: { ownerEmail: 'mistersinister@marauders.com', + ownerAccountID: 8, total: '1000', }, [`${ONYXKEYS.COLLECTION.POLICY}${POLICY.policyID}`]: POLICY, @@ -317,7 +318,7 @@ describe('OptionsListUtils', () => { .then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, PERSONAL_DETAILS_WITH_PERIODS)) .then(() => { // When we filter again but provide a searchValue that should match with periods - results = OptionsListUtils.getSearchOptions(REPORTS, PERSONAL_DETAILS_WITH_PERIODS, 'barryallen@expensify.com'); + results = OptionsListUtils.getSearchOptions(REPORTS, PERSONAL_DETAILS_WITH_PERIODS, 'barry.allen@expensify.com'); // Then we expect to have the personal detail with period filtered expect(results.recentReports.length).toBe(1); From 5f5789be72cf8784b55913273c0c8a42ccdffe5e Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Wed, 7 Jun 2023 16:22:31 +0100 Subject: [PATCH 12/60] fix: generate random accountID for users info not in Onyx --- src/libs/OptionsListUtils.js | 29 ++++++++++------------------- src/libs/ReportUtils.js | 5 ++--- src/libs/UserUtils.js | 14 ++++++++++++-- tests/unit/OptionsListUtilsTest.js | 4 ++++ 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 3415cf412084..86e18169cf02 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -301,13 +301,13 @@ function getSearchText(report, reportName, personalDetailList, isChatRoomOrPolic const personalDetail = personalDetailList[i]; if (personalDetail.login) { - // The regex below is used to remove dots only from the local part of the user email (local-part@domain) - // so that we can match emails that have dots without explicitly writing the dots (e.g: fistlast@domain will match first.last@domain) - // More info https://github.com/Expensify/App/issues/8007 - searchTerms = searchTerms.concat([personalDetail.displayName, personalDetail.login, personalDetail.login.replace(/\.(?=[^\s@]*@)/g, '')]); + // The regex below is used to remove dots only from the local part of the user email (local-part@domain) + // so that we can match emails that have dots without explicitly writing the dots (e.g: fistlast@domain will match first.last@domain) + // More info https://github.com/Expensify/App/issues/8007 + searchTerms = searchTerms.concat([personalDetail.displayName, personalDetail.login, personalDetail.login.replace(/\.(?=[^\s@]*@)/g, '')]); + } } } - } if (report) { Array.prototype.push.apply(searchTerms, reportName.split(/[,\s]/)); @@ -402,7 +402,6 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { isPolicyExpenseChat: false, }; - const personalDetailMap = getPersonalDetailsForAccountIDs(accountIDs, personalDetails); const personalDetailList = _.values(personalDetailMap); const personalDetail = personalDetailList[0] || {}; @@ -727,25 +726,17 @@ function getOptions( !_.find(loginOptionsToExclude, (loginOptionToExclude) => loginOptionToExclude.login === addSMSDomainIfPhoneNumber(searchValue).toLowerCase()) && (searchValue !== CONST.EMAIL.CHRONOS || Permissions.canUseChronos(betas)) ) { - const searchPersonalDetails = _.find(personalDetails, (personalDetail) => personalDetail.login === searchValue); - if (!searchPersonalDetails) { - return { - recentReports: [], - personalDetails: [], - userToInvite: null, - currentUserOption: null, - }; - } - - userToInvite = createOption([searchPersonalDetails.accountID], personalDetails, null, reportActions, { + const fakeAccountID = UserUtils.generateAccountID(); + userToInvite = createOption([fakeAccountID], personalDetails, null, reportActions, { showChatPreviewLine, }); + userToInvite.login = searchValue; // If user doesn't exist, use a default avatar userToInvite.icons = [ { - source: UserUtils.getAvatar('', searchPersonalDetails.accountID), - name: searchPersonalDetails.login, + source: UserUtils.getAvatar('', fakeAccountID), + login: searchValue, type: CONST.ICON_TYPE_AVATAR, }, ]; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f910123f69a1..280873b562b4 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -18,7 +18,6 @@ import DateUtils from './DateUtils'; import linkingConfig from './Navigation/linkingConfig'; import isReportMessageAttachment from './isReportMessageAttachment'; import * as defaultWorkspaceAvatars from '../components/Icon/WorkspaceDefaultAvatars'; -import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as CurrencyUtils from './CurrencyUtils'; import * as UserUtils from './UserUtils'; @@ -27,8 +26,8 @@ let sessionAccountID; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { - sessionEmail = val ? val.email : null - sessionAccountID = val ? val.accountID : null + sessionEmail = val ? val.email : null; + sessionAccountID = val ? val.accountID : null; }, }); diff --git a/src/libs/UserUtils.js b/src/libs/UserUtils.js index 776ff45318ec..86d903cb64b3 100644 --- a/src/libs/UserUtils.js +++ b/src/libs/UserUtils.js @@ -97,8 +97,8 @@ function getDefaultAvatar(accountID = -1) { /** * Helper method to return default avatar URL associated with login * - * @param {String} [login] - * @param {Boolean} [isNewDot] + * @param {String} accountID + * @param {Boolean} isNewDot * @returns {String} */ function getDefaultAvatarURL(accountID = '', isNewDot = false) { @@ -201,6 +201,15 @@ function getSmallSizeAvatar(avatarURL, accountID) { return `${source.substring(0, lastPeriodIndex)}_128${source.substring(lastPeriodIndex)}`; } +/** + * Generate a random accountID. + * + * @returns {String} + */ +function generateAccountID() { + return Math.floor(Math.random() * 99999999).toString(); +} + export { hashText, hasLoginListError, @@ -213,4 +222,5 @@ export { getAvatarUrl, getSmallSizeAvatar, getFullSizeAvatar, + generateAccountID, }; diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index e2f9e048f437..7b045b79cda1 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -182,6 +182,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 11, participants: ['concierge@expensify.com'], + participantAccountIDs: [999], reportName: 'Concierge', }, }; @@ -194,6 +195,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 12, participants: ['chronos@expensify.com'], + participantAccountIDs: [1000], reportName: 'Chronos', }, }; @@ -206,6 +208,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 13, participants: ['receipts@expensify.com'], + participantAccountIDs: [1001], reportName: 'Receipts', }, }; @@ -218,6 +221,7 @@ describe('OptionsListUtils', () => { isPinned: false, reportID: 14, participants: ['reedrichards@expensify.com', 'brucebanner@expensify.com', 'peterparker@expensify.com'], + participantAccountIDs: [1, 10, 3], reportName: '', oldPolicyName: 'Avengers Room', isArchivedRoom: false, From f18dd6c7ffee13cd9a6955cfc223c00c79f08476 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 11:34:13 -0400 Subject: [PATCH 13/60] New util to default displayName to hidden if unavailable --- src/libs/PersonalDetailsUtils.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index 1cdddc136f7e..2f87b710509d 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -1,3 +1,4 @@ +import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; import _ from 'underscore'; import ONYXKEYS from '../ONYXKEYS'; @@ -9,6 +10,17 @@ Onyx.connect({ callback: (val) => (personalDetails = _.values(val)), }); +/** + * @param {Object} personalDetails + * @param {Array} pathToDisplayName + * @param {String} [defaultValue] optional default display name value + */ +function getDisplayNameOrDefault(personalDetails, pathToDisplayName, defaultValue) { + let displayName = lodashGet(personalDetails, pathToDisplayName); + + return displayName || defaultValue || 'Hidden'; +} + /** * Given a list of account IDs (as string) it will return an array of personal details objects. * @param {Array} accountIDs - Array of accountIDs @@ -35,6 +47,6 @@ function getPersonalDetailsByIDs(accountIDs, currentUserAccountID, shouldChangeU } export { - // eslint-disable-next-line import/prefer-default-export + getDisplayNameOrDefault, getPersonalDetailsByIDs, }; From cf0b245954e072c25255a77a3733a688138131bb Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Wed, 7 Jun 2023 16:40:05 +0100 Subject: [PATCH 14/60] fix: update ReportUtils to use accountID and fix tests --- src/libs/ReportUtils.js | 2 +- tests/unit/ReportUtilsTest.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 280873b562b4..e23a1f73f832 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -873,7 +873,7 @@ function getDisplayNameForParticipant(accountID, shouldUseShortForm = false) { */ function getDisplayNamesWithTooltips(participants, isMultipleParticipantReport) { return _.map(participants, (participant) => { - const displayName = getDisplayNameForParticipant(participant.login, isMultipleParticipantReport); + const displayName = getDisplayNameForParticipant(participant.accountID, isMultipleParticipantReport); const tooltip = participant.login ? Str.removeSMSDomain(participant.login) : ''; let pronouns = participant.pronouns; diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index d56e1fdf6b25..368f9ef1789f 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -113,6 +113,7 @@ describe('ReportUtils', () => { expect( ReportUtils.getReportName({ participants: [currentUserEmail, 'ragnar@vikings.net'], + participantAccountIDs: [currentUserAccountID, 1], }), ).toBe('Ragnar Lothbrok'); }); @@ -121,6 +122,7 @@ describe('ReportUtils', () => { expect( ReportUtils.getReportName({ participants: [currentUserEmail, 'floki@vikings.net'], + participantAccountIDs: [currentUserAccountID, 2], }), ).toBe('floki@vikings.net'); }); @@ -129,6 +131,7 @@ describe('ReportUtils', () => { expect( ReportUtils.getReportName({ participants: [currentUserEmail, '+18332403627@expensify.sms'], + participantAccountIDs: [currentUserAccountID, 4], }), ).toBe('(833) 240-3627'); }); @@ -138,6 +141,7 @@ describe('ReportUtils', () => { expect( ReportUtils.getReportName({ participants: [currentUserEmail, 'ragnar@vikings.net', 'floki@vikings.net', 'lagertha@vikings.net', '+18332403627@expensify.sms'], + participantAccountIDs: [currentUserAccountID, 1, 2, 3, 4], }), ).toBe('Ragnar, floki@vikings.net, Lagertha, (833) 240-3627'); }); @@ -197,6 +201,7 @@ describe('ReportUtils', () => { policyID: policy.policyID, isOwnPolicyExpenseChat: true, ownerEmail: 'ragnar@vikings.net', + ownerAccountID: 1, }), ).toBe('Vikings Policy'); }); @@ -208,6 +213,7 @@ describe('ReportUtils', () => { policyID: policy.policyID, isOwnPolicyExpenseChat: false, ownerEmail: 'ragnar@vikings.net', + ownerAccountID: 1, }), ).toBe('Ragnar Lothbrok'); }); @@ -217,6 +223,7 @@ describe('ReportUtils', () => { const baseArchivedPolicyExpenseChat = { chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, ownerEmail: 'ragnar@vikings.net', + ownerAccountID: 1, policyID: policy.policyID, oldPolicyName: policy.name, statusNum: CONST.REPORT.STATUS.CLOSED, From 9d30f05bb95e215b9554d884c396ce2d6113fd31 Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Wed, 7 Jun 2023 17:19:12 +0100 Subject: [PATCH 15/60] fix: add notes and fix small issues --- src/libs/OptionsListUtils.js | 2 ++ src/libs/ReportUtils.js | 2 +- src/libs/UserUtils.js | 4 ++-- tests/unit/OptionsListUtilsTest.js | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 86e18169cf02..4cef9a52f24b 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -173,11 +173,13 @@ function getPersonalDetailsForAccountIDs(accountIDs, personalDetails) { return personalDetailsForLogins; } _.chain(accountIDs) + // NOTE: this comment is possibly legacy, we need to verify if it's still true // Somehow it's possible for the accountIDs coming from report.participantAccountIDs to contain undefined values so we use compact to remove them. .compact() .each((accountID) => { let personalDetail = personalDetails[accountID]; if (!personalDetail) { + // NOTE: this can possibly be changed to 'hidden' personalDetail = { accountID, avatar: UserUtils.getDefaultAvatar(accountID), diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index e23a1f73f832..018de5c1b932 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -975,7 +975,7 @@ function getPolicyExpenseChatName(report) { */ function getMoneyRequestReportName(report) { const formattedAmount = CurrencyUtils.convertToDisplayString(getMoneyRequestTotal(report), report.currency); - const payerName = isExpenseReport(report) ? getPolicyName(report) : getDisplayNameForParticipant(report.managerAccountID); + const payerName = isExpenseReport(report) ? getPolicyName(report) : getDisplayNameForParticipant(report.managerID); return Localize.translateLocal(report.hasOutstandingIOU ? 'iou.payerOwesAmount' : 'iou.payerPaidAmount', {payer: payerName, amount: formattedAmount}); } diff --git a/src/libs/UserUtils.js b/src/libs/UserUtils.js index bcdc9fa5d007..826c3746982c 100644 --- a/src/libs/UserUtils.js +++ b/src/libs/UserUtils.js @@ -202,12 +202,12 @@ function getSmallSizeAvatar(avatarURL, accountID) { } /** - * Generate a random accountID. + * Generate a random accountID. Uses the same approach of 'generateReportID'. * * @returns {String} */ function generateAccountID() { - return Math.floor(Math.random() * 99999999).toString(); + return (Math.floor(Math.random() * 2 ** 21) * 2 ** 32 + Math.floor(Math.random() * 2 ** 32)).toString(); } export { diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 7b045b79cda1..75c7927888eb 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -181,6 +181,7 @@ describe('OptionsListUtils', () => { lastVisibleActionCreated: '2022-11-22 03:26:02.022', isPinned: false, reportID: 11, + // NOTE: possibly remove 'participants' field in the future participants: ['concierge@expensify.com'], participantAccountIDs: [999], reportName: 'Concierge', From 3ca4e0d52073a170d0c0a65e74128f48ad20c6d5 Mon Sep 17 00:00:00 2001 From: Ana Margarida Silva Date: Wed, 7 Jun 2023 17:40:48 +0100 Subject: [PATCH 16/60] style: prettier --- src/libs/OptionsListUtils.js | 2 +- src/libs/UserUtils.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 4cef9a52f24b..5c20f34bb3b3 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -179,7 +179,7 @@ function getPersonalDetailsForAccountIDs(accountIDs, personalDetails) { .each((accountID) => { let personalDetail = personalDetails[accountID]; if (!personalDetail) { - // NOTE: this can possibly be changed to 'hidden' + // NOTE: this can possibly be changed to 'hidden' personalDetail = { accountID, avatar: UserUtils.getDefaultAvatar(accountID), diff --git a/src/libs/UserUtils.js b/src/libs/UserUtils.js index 826c3746982c..964644d730ef 100644 --- a/src/libs/UserUtils.js +++ b/src/libs/UserUtils.js @@ -202,7 +202,8 @@ function getSmallSizeAvatar(avatarURL, accountID) { } /** - * Generate a random accountID. Uses the same approach of 'generateReportID'. + * Generate a random accountID. + * Uses the same approach of 'generateReportID'. * * @returns {String} */ From 156deffd34fb3c412d005f0be70a4ffb677d2488 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 13:25:15 -0400 Subject: [PATCH 17/60] Update a few tests --- src/components/ArchivedReportFooter.js | 13 +++++--- src/libs/PersonalDetailsUtils.js | 6 ++-- tests/actions/IOUTest.js | 42 +++++++++++++++++--------- tests/ui/UnreadIndicatorsTest.js | 2 ++ 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index a59b5f1dd189..13da54b64ecf 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -12,6 +12,7 @@ import * as ReportUtils from '../libs/ReportUtils'; import reportPropTypes from '../pages/reportPropTypes'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; import styles from '../styles/styles'; +import * as PersonalDetailsUtils from '../libs/PersonalDetailsUtils'; const propTypes = { /** The reason this report was archived */ @@ -49,14 +50,16 @@ const defaultProps = { const ArchivedReportFooter = (props) => { const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT); - let displayName = lodashGet(props.personalDetails, `${props.report.ownerEmail}.displayName`, props.report.ownerEmail); + let displayName = PersonalDetailsUtils.getDisplayNameOrDefault( + props.personalDetails, [props.report.ownerAccountID, 'displayName'], props.report.ownerEmail, + ); let oldDisplayName; if (archiveReason === CONST.REPORT.ARCHIVE_REASON.ACCOUNT_MERGED) { - const newLogin = props.reportClosedAction.originalMessage.newLogin; - const oldLogin = props.reportClosedAction.originalMessage.oldLogin; - displayName = lodashGet(props.personalDetails, `${newLogin}.displayName`, newLogin); - oldDisplayName = lodashGet(props.personalDetails, `${oldLogin}.displayName`, oldLogin); + 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']); } return ( diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index 2f87b710509d..c0685c28120b 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -11,12 +11,12 @@ Onyx.connect({ }); /** - * @param {Object} personalDetails + * @param {Object} passedPersonalDetails * @param {Array} pathToDisplayName * @param {String} [defaultValue] optional default display name value */ -function getDisplayNameOrDefault(personalDetails, pathToDisplayName, defaultValue) { - let displayName = lodashGet(personalDetails, pathToDisplayName); +function getDisplayNameOrDefault(passedPersonalDetails, pathToDisplayName, defaultValue) { + let displayName = lodashGet(passedPersonalDetails, pathToDisplayName); return displayName || defaultValue || 'Hidden'; } diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 071ac2300f92..0eaaba65b3ca 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -11,9 +11,13 @@ import * as ReportActions from '../../src/libs/actions/ReportActions'; import * as Report from '../../src/libs/actions/Report'; const CARLOS_EMAIL = 'cmartins@expensifail.com'; +const CARLOS_ACCOUNT_ID = 1; const JULES_EMAIL = 'jules@expensifail.com'; +const JULES_ACCOUNT_ID = 2; const RORY_EMAIL = 'rory@expensifail.com'; +const RORY_ACCOUNT_ID = 3; const VIT_EMAIL = 'vit@expensifail.com'; +const VIT_ACCOUNT_ID = 4; describe('actions/IOU', () => { beforeAll(() => { @@ -36,7 +40,7 @@ describe('actions/IOU', () => { let iouAction; let transactionID; fetch.pause(); - IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL}, comment); + IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve() .then( () => @@ -57,7 +61,7 @@ describe('actions/IOU', () => { iouReportID = iouReport.reportID; // They should be linked together - expect(chatReport.participants).toEqual([CARLOS_EMAIL]); + expect(chatReport.participantAccountIDs).toEqual([CARLOS_ACCOUNT_ID]); expect(chatReport.iouReportID).toBe(iouReport.reportID); expect(chatReport.hasOutstandingIOU).toBe(true); @@ -183,7 +187,7 @@ describe('actions/IOU', () => { reportID: 1234, type: CONST.REPORT.TYPE.CHAT, hasOutstandingIOU: false, - participants: [CARLOS_EMAIL], + participantAccountIDs: [CARLOS_ACCOUNT_ID], }; const createdAction = { reportActionID: NumberUtils.rand64(), @@ -201,7 +205,7 @@ describe('actions/IOU', () => { }), ) .then(() => { - IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL}, comment); + IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve(); }) .then( @@ -343,7 +347,7 @@ describe('actions/IOU', () => { type: CONST.REPORT.TYPE.CHAT, hasOutstandingIOU: true, iouReportID, - participants: [CARLOS_EMAIL], + participantAccountIDs: [CARLOS_ACCOUNT_ID], }; const createdAction = { reportActionID: NumberUtils.rand64(), @@ -361,7 +365,9 @@ describe('actions/IOU', () => { chatReportID, type: CONST.REPORT.TYPE.IOU, ownerEmail: RORY_EMAIL, + ownerAccountID: RORY_ACCOUNT_ID, managerEmail: CARLOS_EMAIL, + managerID: CARLOS_ACCOUNT_ID, currency: CONST.CURRENCY.USD, total: existingTransaction.amount, }; @@ -369,6 +375,7 @@ describe('actions/IOU', () => { reportActionID: NumberUtils.rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.IOU, actorEmail: RORY_EMAIL, + actorAccountID: RORY_ACCOUNT_ID, created: DateUtils.getDBTime(), originalMessage: { IOUReportID: iouReportID, @@ -377,6 +384,7 @@ describe('actions/IOU', () => { currency: CONST.CURRENCY.USD, type: CONST.IOU.REPORT_ACTION_TYPE.CREATE, participants: [RORY_EMAIL, CARLOS_EMAIL], + participantAccountIDs: [RORY_ACCOUNT_ID, CARLOS_ACCOUNT_ID], }, }; let newIOUAction; @@ -392,7 +400,7 @@ describe('actions/IOU', () => { ) .then(() => Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${existingTransaction.transactionID}`, existingTransaction)) .then(() => { - IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL}, comment); + IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve(); }) .then( @@ -524,7 +532,7 @@ describe('actions/IOU', () => { let iouAction; let transactionID; fetch.pause(); - IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL}, comment); + IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return ( waitForPromisesToResolve() .then( @@ -547,7 +555,7 @@ describe('actions/IOU', () => { iouReportID = iouReport.reportID; // They should be linked together - expect(chatReport.participants).toEqual([CARLOS_EMAIL]); + expect(chatReport.participantAccountIDs).toEqual([CARLOS_ACCOUNT_ID]); expect(chatReport.iouReportID).toBe(iouReport.reportID); expect(chatReport.hasOutstandingIOU).toBe(true); @@ -784,6 +792,7 @@ describe('actions/IOU', () => { type: CONST.REPORT.TYPE.CHAT, hasOutstandingIOU: false, participants: [CARLOS_EMAIL], + participantAccountIDs: [CARLOS_ACCOUNT_ID], }; const carlosCreatedAction = { reportActionID: NumberUtils.rand64(), @@ -796,7 +805,7 @@ describe('actions/IOU', () => { type: CONST.REPORT.TYPE.CHAT, hasOutstandingIOU: true, iouReportID: julesIOUReportID, - participants: [JULES_EMAIL], + participantAccountIDs: [JULES_ACCOUNT_ID], }; const julesChatCreatedAction = { reportActionID: NumberUtils.rand64(), @@ -820,7 +829,9 @@ describe('actions/IOU', () => { chatReportID: julesChatReport.reportID, type: CONST.REPORT.TYPE.IOU, ownerEmail: RORY_EMAIL, + ownerAccountID: RORY_ACCOUNT_ID, managerEmail: JULES_EMAIL, + managerID: JULES_ACCOUNT_ID, currency: CONST.CURRENCY.USD, total: julesExistingTransaction.amount, }; @@ -828,6 +839,7 @@ describe('actions/IOU', () => { reportActionID: NumberUtils.rand64(), actionName: CONST.REPORT.ACTIONS.TYPE.IOU, actorEmail: RORY_EMAIL, + actorAccountID: RORY_ACCOUNT_ID, created: DateUtils.getDBTime(), originalMessage: { IOUReportID: julesIOUReportID, @@ -836,6 +848,7 @@ describe('actions/IOU', () => { currency: CONST.CURRENCY.USD, type: CONST.IOU.REPORT_ACTION_TYPE.CREATE, participants: [RORY_EMAIL, JULES_EMAIL], + participantAccountIDs: [RORY_ACCOUNT_ID, JULES_ACCOUNT_ID], }, }; @@ -881,6 +894,7 @@ describe('actions/IOU', () => { // When we split a bill offline fetch.pause(); IOU.splitBill( + // TODO: Migrate after the backend accepts accountIDs _.map([CARLOS_EMAIL, JULES_EMAIL, VIT_EMAIL], (email) => ({login: email})), RORY_EMAIL, amount, @@ -907,7 +921,7 @@ describe('actions/IOU', () => { expect(carlosChatReport.pendingFields).toBeFalsy(); // 2. The IOU report with Rory + Carlos (new) - carlosIOUReport = _.find(allReports, (report) => report.type === CONST.REPORT.TYPE.IOU && report.managerEmail === CARLOS_EMAIL); + carlosIOUReport = _.find(allReports, (report) => report.type === CONST.REPORT.TYPE.IOU && report.managerID === CARLOS_ACCOUNT_ID); expect(_.isEmpty(carlosIOUReport)).toBe(false); expect(carlosIOUReport.total).toBe(amount / 4); @@ -923,19 +937,19 @@ describe('actions/IOU', () => { expect(julesIOUReport.total).toBe(julesExistingTransaction.amount + amount / 4); // 5. The chat report with Rory + Vit (new) - vitChatReport = _.find(allReports, (report) => report.type === CONST.REPORT.TYPE.CHAT && _.isEqual(report.participants, [VIT_EMAIL])); + vitChatReport = _.find(allReports, (report) => report.type === CONST.REPORT.TYPE.CHAT && _.isEqual(report.participantAccountIDs, [VIT_ACCOUNT_ID])); expect(_.isEmpty(vitChatReport)).toBe(false); expect(vitChatReport.pendingFields).toStrictEqual({createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}); // 6. The IOU report with Rory + Vit (new) - vitIOUReport = _.find(allReports, (report) => report.type === CONST.REPORT.TYPE.IOU && report.managerEmail === VIT_EMAIL); + vitIOUReport = _.find(allReports, (report) => report.type === CONST.REPORT.TYPE.IOU && report.managerID === VIT_ACCOUNT_ID); expect(_.isEmpty(vitIOUReport)).toBe(false); expect(vitIOUReport.total).toBe(amount / 4); // 7. The group chat with everyone groupChat = _.find( allReports, - (report) => report.type === CONST.REPORT.TYPE.CHAT && _.isEqual(report.participants, [CARLOS_EMAIL, JULES_EMAIL, VIT_EMAIL]), + (report) => report.type === CONST.REPORT.TYPE.CHAT && _.isEqual(report.participantAccountIDs, [CARLOS_ACCOUNT_ID, JULES_ACCOUNT_ID, VIT_ACCOUNT_ID]), ); expect(_.isEmpty(groupChat)).toBe(false); expect(groupChat.pendingFields).toStrictEqual({createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}); @@ -1149,7 +1163,7 @@ describe('actions/IOU', () => { let createIOUAction; let payIOUAction; let transaction; - IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL}, comment); + IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve() .then( () => diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index ba5b6c2e823c..c12b03c6ae18 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -153,6 +153,7 @@ function signInAndGetAppWithUnreadChat() { lastVisibleActionCreated: reportAction9CreatedDate, lastMessageText: 'Test', participants: [USER_B_EMAIL], + participantAccountIDs: [USER_B_ACCOUNT_ID], type: CONST.REPORT.TYPE.CHAT, }); const createdReportActionID = NumberUtils.rand64(); @@ -305,6 +306,7 @@ describe('Unread Indicators', () => { lastVisibleActionCreated: DateUtils.getDBTime(NEW_REPORT_FIST_MESSAGE_CREATED_MOMENT.utc().valueOf()), lastMessageText: 'Comment 1', participants: [USER_C_EMAIL], + participantAccountIDs: [USER_C_ACCOUNT_ID], }, }, { From 9a70430302fecdc18a633520f17531d7cf8e6bba Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 13:26:55 -0400 Subject: [PATCH 18/60] Clean up session key subscription --- src/libs/ReportUtils.js | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 018de5c1b932..f9ba8b8e4a66 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -23,37 +23,31 @@ import * as UserUtils from './UserUtils'; let sessionEmail; let sessionAccountID; +let currentUserEmail; +let currentUserAccountID; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { - sessionEmail = val ? val.email : null; - sessionAccountID = val ? val.accountID : null; - }, -}); - -let preferredLocale = CONST.LOCALES.DEFAULT; -Onyx.connect({ - key: ONYXKEYS.NVP_PREFERRED_LOCALE, - callback: (val) => { + // When signed out, val is undefined if (!val) { return; } - preferredLocale = val; + + sessionEmail = val.email; + sessionAccountID = val.accountID; + currentUserEmail = val.email; + currentUserAccountID = val.accountID; }, }); -let currentUserEmail; -let currentUserAccountID; +let preferredLocale = CONST.LOCALES.DEFAULT; Onyx.connect({ - key: ONYXKEYS.SESSION, + key: ONYXKEYS.NVP_PREFERRED_LOCALE, callback: (val) => { - // When signed out, val is undefined if (!val) { return; } - - currentUserEmail = val.email; - currentUserAccountID = val.accountID; + preferredLocale = val; }, }); @@ -63,7 +57,7 @@ Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { currentUserPersonalDetails = lodashGet(val, currentUserAccountID, {}); - allPersonalDetails = val; + allPersonalDetails = val || {}; }, }); From f376593e35385a02f4ad985306fcfbdf48eb729a Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 10:32:27 -0700 Subject: [PATCH 19/60] Add new policy members key --- src/ONYXKEYS.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 0b8e27463f05..8656e3dd3d7f 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -114,6 +114,7 @@ export default { DOWNLOAD: 'download_', POLICY: 'policy_', POLICY_MEMBER_LIST: 'policyMemberList_', + POLICY_MEMBERS: 'policyMembers_', WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_', REPORT: 'report_', REPORT_ACTIONS: 'reportActions_', From 1d585b747e8bad4d83a064cd6fb09150fd86344b Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 10:33:28 -0700 Subject: [PATCH 20/60] workspaces list with policy members by accountID --- src/libs/PolicyUtils.js | 18 +++++++++--------- src/pages/workspace/WorkspacesListPage.js | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libs/PolicyUtils.js b/src/libs/PolicyUtils.js index 91396be628a3..601eaa1f128b 100644 --- a/src/libs/PolicyUtils.js +++ b/src/libs/PolicyUtils.js @@ -5,14 +5,14 @@ import CONST from '../CONST'; import ONYXKEYS from '../ONYXKEYS'; /** - * Checks if we have any errors stored within the POLICY_MEMBER_LIST. Determines whether we should show a red brick road error or not. - * Data structure: {email: {role:'user', errors: []}, email2: {role:'admin', errors: [{1231312313: 'Unable to do X'}]}, ...} + * Checks if we have any errors stored within the POLICY_MEMBERS. Determines whether we should show a red brick road error or not. + * Data structure: {accountID: {role:'user', errors: []}, accountID2: {role:'admin', errors: [{1231312313: 'Unable to do X'}]}, ...} * - * @param {Object} policyMemberList + * @param {Object} policyMembers * @returns {Boolean} */ -function hasPolicyMemberError(policyMemberList) { - return _.some(policyMemberList, (member) => !_.isEmpty(member.errors)); +function hasPolicyMemberError(policyMembers) { + return _.some(policyMembers, (member) => !_.isEmpty(member.errors)); } /** @@ -53,12 +53,12 @@ function hasCustomUnitsError(policy) { * * @param {Object} policy * @param {String} policy.id - * @param {Object} policyMembers + * @param {Object} policyMembersCollection * @returns {String} */ -function getPolicyBrickRoadIndicatorStatus(policy, policyMembers) { - const policyMemberList = lodashGet(policyMembers, `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${policy.id}`, {}); - if (hasPolicyMemberError(policyMemberList) || hasCustomUnitsError(policy) || hasPolicyErrorFields(policy)) { +function getPolicyBrickRoadIndicatorStatus(policy, policyMembersCollection) { + const policyMembers = lodashGet(policyMembersCollection, `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policy.id}`, {}); + if (hasPolicyMemberError(policyMembers) || hasCustomUnitsError(policy) || hasPolicyErrorFields(policy)) { return CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR; } return ''; diff --git a/src/pages/workspace/WorkspacesListPage.js b/src/pages/workspace/WorkspacesListPage.js index bf362168ad99..14affcd5303b 100755 --- a/src/pages/workspace/WorkspacesListPage.js +++ b/src/pages/workspace/WorkspacesListPage.js @@ -217,7 +217,7 @@ export default compose( key: ONYXKEYS.COLLECTION.POLICY, }, policyMembers: { - key: ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST, + key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, }, reimbursementAccount: { key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, From c74be2cc9d6787f2cd7d43683106ceeed0213c9a Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 10:38:26 -0700 Subject: [PATCH 21/60] Avatar with policy members by accountID --- src/components/AvatarWithIndicator.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js index 1835e739c25b..bbbb4e8a9616 100644 --- a/src/components/AvatarWithIndicator.js +++ b/src/components/AvatarWithIndicator.js @@ -29,7 +29,7 @@ const propTypes = { /* Onyx Props */ /** The employee list of all policies (coming from Onyx) */ - policiesMemberList: PropTypes.objectOf(policyMemberPropType), + policyMembers: PropTypes.objectOf(policyMemberPropType), /** All the user's policies (from Onyx via withFullPolicy) */ policies: PropTypes.objectOf(policyPropTypes.policy), @@ -62,7 +62,7 @@ const propTypes = { const defaultProps = { tooltipText: '', reimbursementAccount: {}, - policiesMemberList: {}, + policyMembers: {}, policies: {}, bankAccountList: {}, cardList: {}, @@ -75,7 +75,7 @@ const AvatarWithIndicator = (props) => { // If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and // those should be cleaned out before doing any error checking const cleanPolicies = _.pick(props.policies, (policy) => policy); - const cleanPolicyMembers = _.pick(props.policiesMemberList, (member) => member); + const cleanPolicyMembers = _.pick(props.policyMembers, (member) => member); // All of the error & info-checking methods are put into an array. This is so that using _.some() will return // early as soon as the first error / info condition is returned. This makes the checks very efficient since @@ -114,8 +114,8 @@ AvatarWithIndicator.propTypes = propTypes; AvatarWithIndicator.displayName = 'AvatarWithIndicator'; export default withOnyx({ - policiesMemberList: { - key: ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST, + policyMembers: { + key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, }, policies: { key: ONYXKEYS.COLLECTION.POLICY, From 0348e225116bd5c98fcc7d11f76e59ef91c3584f Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 10:40:55 -0700 Subject: [PATCH 22/60] Settings page with policy members by accountID --- src/pages/settings/InitialSettingsPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index f2c58e5aa2ac..84c3d7fbec0a 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -99,7 +99,7 @@ const propTypes = { errorFields: PropTypes.objectOf(PropTypes.objectOf(PropTypes.string)), }), - /** List of policy members */ + /** Members keyed by accountID for all policies */ policyMembers: PropTypes.objectOf(policyMemberPropType), ...withLocalizePropTypes, @@ -394,7 +394,7 @@ export default compose( key: ONYXKEYS.COLLECTION.POLICY, }, policyMembers: { - key: ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST, + key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, }, userWallet: { key: ONYXKEYS.USER_WALLET, From dda26cbce78eb02aca26e49f9fad732e2dcada6c Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 13:50:02 -0400 Subject: [PATCH 23/60] Migrate to new optionslistutil --- src/components/AvatarWithDisplayName.js | 2 +- src/components/ReportWelcomeText.js | 4 ++-- src/libs/OptionsListUtils.js | 2 +- src/libs/ReportUtils.js | 30 ++++++++++++++++++------- src/libs/SidebarUtils.js | 4 ++-- src/pages/ReportDetailsPage.js | 4 ++-- src/pages/home/HeaderView.js | 6 ++--- src/pages/iou/SplitBillDetailsPage.js | 6 ++--- src/pages/tasks/NewTaskPage.js | 2 +- 9 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js index 6da7f00f5637..3ae2d82cc5d3 100644 --- a/src/components/AvatarWithDisplayName.js +++ b/src/components/AvatarWithDisplayName.js @@ -54,7 +54,7 @@ const AvatarWithDisplayName = (props) => { const subtitle = ReportUtils.getChatRoomSubtitle(props.report); const isExpenseReport = ReportUtils.isExpenseReport(props.report); const icons = ReportUtils.getIcons(props.report, props.personalDetails, props.policies); - const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins([props.report.ownerEmail], props.personalDetails); + const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs([props.report.ownerAccountID], props.personalDetails); const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(ownerPersonalDetails, false); const avatarContainerStyle = StyleUtils.getEmptyAvatarStyle(props.size) || styles.emptyAvatar; return ( diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js index 9ca3d672bee0..667f705d205a 100644 --- a/src/components/ReportWelcomeText.js +++ b/src/components/ReportWelcomeText.js @@ -54,9 +54,9 @@ const ReportWelcomeText = (props) => { const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isChatRoom = ReportUtils.isChatRoom(props.report); const isDefault = !(isChatRoom || isPolicyExpenseChat); - const participants = lodashGet(props.report, 'participants', []); + const participants = lodashGet(props.report, 'participantAccountIDs', []); const isMultipleParticipant = participants.length > 1; - const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails), isMultipleParticipant); + const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participants, props.personalDetails), isMultipleParticipant); const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(props.report); const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(props.report, participants, props.betas); return ( diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 5c20f34bb3b3..34c7f19f22a8 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -211,7 +211,7 @@ function isPersonalDetailsReady(personalDetails) { * @returns {Array} */ function getParticipantsOptions(report, personalDetails) { - const participants = lodashGet(report, 'participants', []); + const participants = lodashGet(report, 'participantAccountIDs', []); return _.map(getPersonalDetailsForAccountIDs(participants, personalDetails), (details) => ({ keyForList: details.login, login: details.login, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f9ba8b8e4a66..977867318ba1 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -620,6 +620,15 @@ function hasAutomatedExpensifyEmails(emails) { return _.intersection(emails, CONST.EXPENSIFY_EMAILS).length > 0; } +/** + * Returns true if there is any automated expensify account in accountIDs + * @param {Array} accountIDs + * @returns {Boolean} + */ +function hasAutomatedExpensifyAccountIDs(accountIDs) { + return _.intersection(accountIDs, CONST.EXPENSIFY_ACCOUNT_IDS).length > 0; +} + /** * Returns true if there are any Expensify accounts (i.e. with domain 'expensify.com') in the set of emails. * @@ -701,9 +710,9 @@ function getIconsForParticipants(participants, personalDetails) { const participantsList = participants || []; for (let i = 0; i < participantsList.length; i++) { - const login = participantsList[i]; - const avatarSource = UserUtils.getAvatar(lodashGet(personalDetails, [login, 'avatar'], ''), login); - participantDetails.push([login, lodashGet(personalDetails, [login, 'firstName'], ''), avatarSource]); + const accountID = participantsList[i]; + const avatarSource = UserUtils.getAvatar(lodashGet(personalDetails, [accountID, 'avatar'], ''), accountID); + participantDetails.push([accountID, lodashGet(personalDetails, [accountID, 'firstName'], ''), avatarSource]); } // Sort all logins by first name (which is the second element in the array) @@ -756,8 +765,9 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) const parentReportAction = ReportActionsUtils.getParentReportAction(report); const actorEmail = lodashGet(parentReportAction, 'actorEmail', ''); + const actorAccountID = lodashGet(parentReportAction, 'actorAccountID', ''); const actorIcon = { - source: UserUtils.getAvatar(lodashGet(personalDetails, [actorEmail, 'avatar']), actorEmail), + source: UserUtils.getAvatar(lodashGet(personalDetails, [actorAccountID, 'avatar']), actorAccountID), name: actorEmail, type: CONST.ICON_TYPE_AVATAR, }; @@ -794,7 +804,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) } const adminIcon = { - source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerEmail, 'avatar']), report.ownerEmail), + source: UserUtils.getAvatar(lodashGet(personalDetails, [report.ownerAccountID, 'avatar']), report.ownerAccountID), name: report.ownerEmail, type: CONST.ICON_TYPE_AVATAR, }; @@ -811,16 +821,17 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) } if (isIOUReport(report)) { const email = isPayer ? report.managerEmail : report.ownerEmail; + const accountID = isPayer ? report.managerID : report.ownerAccountID; return [ { - source: UserUtils.getAvatar(lodashGet(personalDetails, [email, 'avatar']), email), + source: UserUtils.getAvatar(lodashGet(personalDetails, [accountID, 'avatar']), accountID), name: email, type: CONST.ICON_TYPE_AVATAR, }, ]; } - return getIconsForParticipants(report.participants, personalDetails); + return getIconsForParticipants(report.participantAccountIDs, personalDetails); } /** @@ -2019,7 +2030,9 @@ function getMoneyRequestOptions(report, reportParticipants, betas) { return []; } - const participants = _.filter(reportParticipants, (email) => currentUserPersonalDetails.login !== email); + const participants = _.filter(reportParticipants, (accountID) => currentUserPersonalDetails.accountID !== accountID); + + // FAK, NEED ACCOUNT IDS FOR THESE const hasExcludedIOUEmails = lodashIntersection(reportParticipants, CONST.EXPENSIFY_EMAILS).length > 0; const hasMultipleParticipants = participants.length > 1; @@ -2172,6 +2185,7 @@ export { isConciergeChatReport, isCurrentUserTheOnlyParticipant, hasAutomatedExpensifyEmails, + hasAutomatedExpensifyAccountIDs, hasExpensifyGuidesEmails, hasOutstandingIOU, isIOUOwnedByCurrentUser, diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 25c21d1b3060..bf35fe70af7a 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -232,7 +232,7 @@ function getOptionData(reportID) { isMoneyRequestReport: false, }; - const participantPersonalDetailList = _.values(OptionsListUtils.getPersonalDetailsForLogins(report.participants, personalDetails)); + const participantPersonalDetailList = _.values(OptionsListUtils.getPersonalDetailsForAccountIDs(report.participantAccountIDs, personalDetails)); const personalDetail = participantPersonalDetailList[0] || {}; result.isThread = ReportUtils.isThread(report); @@ -276,7 +276,7 @@ function getOptionData(reportID) { // If the last actor's details are not currently saved in Onyx Collection, // then try to get that from the last report action if that action is valid // to get data from. - let lastActorDetails = personalDetails[report.lastActorEmail] || null; + let lastActorDetails = personalDetails[report.lastActorAccountID] || null; if (!lastActorDetails && visibleReportActionItems[report.reportID]) { const lastActorDisplayName = lodashGet(visibleReportActionItems[report.reportID], 'person[0].text'); lastActorDetails = lastActorDisplayName diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js index eb350257efea..48df414e038e 100644 --- a/src/pages/ReportDetailsPage.js +++ b/src/pages/ReportDetailsPage.js @@ -69,7 +69,7 @@ const ReportDetailsPage = (props) => { // eslint-disable-next-line react-hooks/exhaustive-deps -- policy is a dependency because `getChatRoomSubtitle` calls `getPolicyName` which in turn retrieves the value from the `policy` value stored in Onyx const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(props.report), [props.report, policy]); const canLeaveRoom = useMemo(() => ReportUtils.canLeaveRoom(props.report, !_.isEmpty(policy)), [policy, props.report]); - const participants = useMemo(() => lodashGet(props.report, 'participants', []), [props.report]); + const participants = useMemo(() => lodashGet(props.report, 'participantAccountIDs', []), [props.report]); const menuItems = useMemo(() => { if (isArchivedRoom) { @@ -122,7 +122,7 @@ const ReportDetailsPage = (props) => { const displayNamesWithTooltips = useMemo(() => { const hasMultipleParticipants = participants.length > 1; - return ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails), hasMultipleParticipants); + return ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participants, props.personalDetails), hasMultipleParticipants); }, [participants, props.personalDetails]); const chatRoomSubtitleText = chatRoomSubtitle ? ( diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index c6f312574394..c9e5a5dc70d9 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -68,8 +68,8 @@ const defaultProps = { }; const HeaderView = (props) => { - const participants = lodashGet(props.report, 'participants', []); - const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails); + const participants = lodashGet(props.report, 'participantAccountIDs', []); + const participantPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants, props.personalDetails); const isMultipleParticipant = participants.length > 1; const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(participantPersonalDetails, isMultipleParticipant); const isThread = ReportUtils.isThread(props.report); @@ -79,7 +79,7 @@ const HeaderView = (props) => { const reportHeaderData = (isTaskReport || !isThread) && props.report.parentReportID ? props.parentReport : props.report; const title = ReportUtils.getReportName(reportHeaderData); const subtitle = ReportUtils.getChatRoomSubtitle(reportHeaderData, props.parentReport); - const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); + const isConcierge = participants.length === 1 && _.contains(participants, CONST.ACCOUNT_ID.CONCIERGE); const isAutomatedExpensifyAccount = participants.length === 1 && ReportUtils.hasAutomatedExpensifyEmails(participants); const guideCalendarLink = lodashGet(props.account, 'guideCalendarLink'); diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 807c9179f531..f43d4429c322 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -64,10 +64,10 @@ function getReportID(route) { const SplitBillDetailsPage = (props) => { const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`]; - const personalDetails = OptionsListUtils.getPersonalDetailsForLogins(reportAction.originalMessage.participants, props.personalDetails); + const personalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(reportAction.originalMessage.participantAccountIDs, props.personalDetails); const participants = OptionsListUtils.getParticipantsOptions(reportAction.originalMessage, personalDetails); - const payeePersonalDetails = _.filter(participants, (participant) => participant.login === reportAction.actorEmail)[0]; - const participantsExcludingPayee = _.filter(participants, (participant) => participant.login !== reportAction.actorEmail); + const payeePersonalDetails = _.filter(participants, (participant) => participant.accountID === reportAction.actorAccountID)[0]; + const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID); const splitAmount = parseInt(lodashGet(reportAction, 'originalMessage.amount', 0), 10); return ( diff --git a/src/pages/tasks/NewTaskPage.js b/src/pages/tasks/NewTaskPage.js index 32f700eba16e..adc628a5b68d 100644 --- a/src/pages/tasks/NewTaskPage.js +++ b/src/pages/tasks/NewTaskPage.js @@ -77,7 +77,7 @@ const NewTaskPage = (props) => { // If we have an assignee, we want to set the assignee data // If there's an issue with the assignee chosen, we want to notify the user if (props.task.assignee) { - const assigneeDetails = lodashGet(OptionsListUtils.getPersonalDetailsForLogins([props.task.assignee], props.personalDetails), props.task.assignee); + const assigneeDetails = lodashGet(OptionsListUtils.getPersonalDetailsForAccountIDs([props.task.assigneeAccountID], props.personalDetails), props.task.assignee); if (!assigneeDetails) { setSubmitError(true); return setErrorMessage('newTaskPage.assigneeError'); From 5bd48f82dd9f66dc7147fe240f92a09b499b9df5 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 13:57:24 -0400 Subject: [PATCH 24/60] Migrate to accountID & simplify --- src/libs/ReportUtils.js | 8 +++----- src/libs/SidebarUtils.js | 10 ++++++---- tests/unit/ReportUtilsTest.js | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 977867318ba1..526e1a6c7581 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1730,11 +1730,10 @@ function isUnreadWithMention(report) { * * @param {Object} report * @param {String} report.iouReportID - * @param {String} currentUserLogin * @param {Object} iouReports * @returns {boolean} */ -function hasOutstandingIOU(report, currentUserLogin, iouReports) { +function hasOutstandingIOU(report, iouReports) { if (!report || !report.iouReportID || _.isUndefined(report.hasOutstandingIOU)) { return false; } @@ -1816,13 +1815,12 @@ function canSeeDefaultRoom(report, policies, betas) { * @param {Object} report * @param {String} reportIDFromRoute * @param {Boolean} isInGSDMode - * @param {String} currentUserLogin * @param {Object} iouReports * @param {String[]} betas * @param {Object} policies * @returns {boolean} */ -function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, currentUserLogin, iouReports, betas, policies) { +function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, iouReports, betas, policies) { const isInDefaultMode = !isInGSDMode; // Exclude reports that have no data because there wouldn't be anything to show in the option item. @@ -1849,7 +1847,7 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, curr // Include reports if they have a draft, are pinned, or have an outstanding IOU // These are always relevant to the user no matter what view mode the user prefers - if (report.hasDraft || report.isPinned || hasOutstandingIOU(report, currentUserLogin, iouReports)) { + if (report.hasDraft || report.isPinned || hasOutstandingIOU(report, iouReports)) { return true; } diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index bf35fe70af7a..1b8c4c9e29a8 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -78,10 +78,12 @@ Onyx.connect({ callback: (val) => (policies = val), }); -let currentUserLogin; +let currentUserAccountID; Onyx.connect({ key: ONYXKEYS.SESSION, - callback: (val) => (currentUserLogin = val), + callback: (val) => { + currentUserAccountID = val.accountID; + }, }); let preferredLocale; @@ -99,7 +101,7 @@ function getOrderedReportIDs(reportIDFromRoute) { const isInDefaultMode = !isInGSDMode; // Filter out all the reports that shouldn't be displayed - const reportsToDisplay = _.filter(allReports, (report) => ReportUtils.shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, currentUserLogin, allReports, betas, policies)); + const reportsToDisplay = _.filter(allReports, (report) => ReportUtils.shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, allReports, betas, policies)); if (_.isEmpty(reportsToDisplay)) { // Display Concierge chat report when there is no report to be displayed const conciergeChatReport = _.find(allReports, ReportUtils.isConciergeChatReport); @@ -286,7 +288,7 @@ function getOptionData(reportID) { } : null; } - let lastMessageText = hasMultipleParticipants && lastActorDetails && lastActorDetails.login !== currentUserLogin.email ? `${lastActorDetails.displayName}: ` : ''; + let lastMessageText = hasMultipleParticipants && lastActorDetails && lastActorDetails.accountID !== currentUserAccountID ? `${lastActorDetails.displayName}: ` : ''; lastMessageText += report ? lastMessageTextFromReport : ''; if (result.isArchivedRoom) { diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index 368f9ef1789f..652a88f7277f 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -280,7 +280,7 @@ describe('ReportUtils', () => { iouReportID: '1', }; const iouReports = {}; - expect(ReportUtils.hasOutstandingIOU(report, undefined, iouReports)).toBe(false); + expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(false); }); it('returns false when the matched IOU report does not have an owner email', () => { const report = { @@ -292,7 +292,7 @@ describe('ReportUtils', () => { reportID: '1', }, }; - expect(ReportUtils.hasOutstandingIOU(report, undefined, iouReports)).toBe(false); + expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(false); }); it('returns false when the matched IOU report does not have an owner email', () => { const report = { @@ -305,7 +305,7 @@ describe('ReportUtils', () => { ownerEmail: 'a@a.com', }, }; - expect(ReportUtils.hasOutstandingIOU(report, 'b@b.com', iouReports)).toBe(false); + expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(false); }); it('returns true when the report has an oustanding IOU', () => { const report = { @@ -319,7 +319,7 @@ describe('ReportUtils', () => { ownerEmail: 'a@a.com', }, }; - expect(ReportUtils.hasOutstandingIOU(report, 'b@b.com', iouReports)).toBe(true); + expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(true); }); it('returns false when the report has no oustanding IOU', () => { const report = { @@ -333,7 +333,7 @@ describe('ReportUtils', () => { ownerEmail: 'a@a.com', }, }; - expect(ReportUtils.hasOutstandingIOU(report, 'b@b.com', iouReports)).toBe(false); + expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(false); }); }); From 60db5875ab5e9c449a39632f70d4f95607f3879b Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 10:59:14 -0700 Subject: [PATCH 25/60] withPolicy HOC members by accountID --- src/pages/workspace/withPolicy.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/withPolicy.js b/src/pages/workspace/withPolicy.js index 4458cc45ece9..7520f58c8c5d 100644 --- a/src/pages/workspace/withPolicy.js +++ b/src/pages/workspace/withPolicy.js @@ -58,12 +58,12 @@ const policyPropTypes = { }), /** The employee list of this policy */ - policyMemberList: PropTypes.objectOf(policyMemberPropType), + policyMembers: PropTypes.objectOf(policyMemberPropType), }; const policyDefaultProps = { policy: {}, - policyMemberList: {}, + policyMembers: {}, }; /* @@ -117,8 +117,8 @@ export default function (WrappedComponent) { policy: { key: (props) => `${ONYXKEYS.COLLECTION.POLICY}${getPolicyIDFromRoute(props.route)}`, }, - policyMemberList: { - key: (props) => `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${getPolicyIDFromRoute(props.route)}`, + policyMembers: { + key: (props) => `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${getPolicyIDFromRoute(props.route)}`, }, })(withPolicy); } From eae14ebd831170d24091b056f662891746d15159 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 10:59:41 -0700 Subject: [PATCH 26/60] Workspace page with members by accountID --- src/pages/workspace/WorkspaceInitialPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index 6c70f0f20b16..9de3d8594493 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -91,7 +91,7 @@ const WorkspaceInitialPage = (props) => { ); const policyName = lodashGet(policy, 'name', ''); - const hasMembersError = PolicyUtils.hasPolicyMemberError(props.policyMemberList); + const hasMembersError = PolicyUtils.hasPolicyMemberError(props.policyMembers); const hasGeneralSettingsError = !_.isEmpty(lodashGet(policy, 'errorFields.generalSettings', {})) || !_.isEmpty(lodashGet(policy, 'errorFields.avatar', {})); const hasCustomUnitsError = PolicyUtils.hasCustomUnitsError(policy); const menuItems = [ From 7e77b01a1810a6ed42a2093707ec5a3e7b048ad4 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 14:51:49 -0400 Subject: [PATCH 27/60] Lots of accountID migrations --- src/components/MoneyRequestHeader.js | 8 ++++---- src/components/TaskHeader.js | 6 +++--- src/components/participantPropTypes.js | 3 +++ src/libs/ReportUtils.js | 2 ++ src/pages/DetailsPage.js | 11 +++++++---- src/pages/ReportParticipantsPage.js | 20 ++++++++++---------- src/pages/home/report/ReportActionCompose.js | 7 ++++--- src/pages/home/sidebar/SidebarLinks.js | 8 ++++++-- src/pages/personalDetailsPropType.js | 3 +++ 9 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 600a96aede18..816c0ba5814d 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -80,16 +80,16 @@ const MoneyRequestHeader = (props) => { const moneyRequestReport = props.isSingleTransactionView ? props.parentReport : props.report; const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); const isExpenseReport = ReportUtils.isExpenseReport(moneyRequestReport); - const payeeName = isExpenseReport ? ReportUtils.getPolicyName(moneyRequestReport, props.policies) : ReportUtils.getDisplayNameForParticipant(moneyRequestReport.managerEmail); + const payeeName = isExpenseReport ? ReportUtils.getPolicyName(moneyRequestReport, props.policies) : ReportUtils.getDisplayNameForParticipant(moneyRequestReport.managerID); const payeeAvatar = isExpenseReport ? ReportUtils.getWorkspaceAvatar(moneyRequestReport) - : UserUtils.getAvatar(lodashGet(props.personalDetails, [moneyRequestReport.managerEmail, 'avatar']), moneyRequestReport.managerEmail); + : UserUtils.getAvatar(lodashGet(props.personalDetails, [moneyRequestReport.managerID, 'avatar']), moneyRequestReport.managerID); const policy = props.policies[`${ONYXKEYS.COLLECTION.POLICY}${props.report.policyID}`]; const isPayer = - Policy.isAdminOfFreePolicy([policy]) || (ReportUtils.isMoneyRequestReport(moneyRequestReport) && lodashGet(props.session, 'email', null) === moneyRequestReport.managerEmail); + Policy.isAdminOfFreePolicy([policy]) || (ReportUtils.isMoneyRequestReport(moneyRequestReport) && lodashGet(props.session, 'accountID', null) === moneyRequestReport.managerID); const shouldShowSettlementButton = !isSettled && !props.isSingleTransactionView && isPayer; const bankAccountRoute = ReportUtils.getBankAccountRoute(props.chatReport); - const shouldShowPaypal = Boolean(lodashGet(props.personalDetails, [moneyRequestReport.managerEmail, 'payPalMeAddress'])); + const shouldShowPaypal = Boolean(lodashGet(props.personalDetails, [moneyRequestReport.managerID, 'payPalMeAddress'])); return ( - {!_.isEmpty(props.report.managerEmail) && ( + {!_.isEmpty(props.report.managerID) && ( <> { const displayName = getDisplayNameForParticipant(participant.accountID, isMultipleParticipantReport); + + // TODO: Maybe get login from personal details via participant accountID? const tooltip = participant.login ? Str.removeSMSDomain(participant.login) : ''; let pronouns = participant.pronouns; diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index 540f85f33cfe..b21dfbb3f97a 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -90,19 +90,22 @@ const getPhoneNumber = (details) => { class DetailsPage extends React.PureComponent { render() { const login = lodashGet(this.props.route.params, 'login', ''); - let details = lodashGet(this.props.personalDetails, login); + let details = _.find(this.props.personalDetails, (detail) => { + return detail.login === login.toLowerCase(); + }); if (!details) { details = { + accountID: -1, login, - displayName: ReportUtils.getDisplayNameForParticipant(login), - avatar: UserUtils.getAvatar(lodashGet(details, 'avatar', ''), login), + displayName: login, + avatar: UserUtils.getDefaultAvatar(), }; } const isSMSLogin = details.login ? Str.isSMSLogin(details.login) : false; - const shouldShowLocalTime = !ReportUtils.hasAutomatedExpensifyEmails([details.login]) && details.timezone; + const shouldShowLocalTime = !ReportUtils.hasAutomatedExpensifyAccountIDs([details.accountID]) && details.timezone; let pronouns = details.pronouns; if (pronouns && pronouns.startsWith(CONST.PRONOUNS.PREFIX)) { diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index 4f7b9f1a4045..72b1da70cafb 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -54,28 +54,28 @@ const defaultProps = { * @return {Array} */ const getAllParticipants = (report, personalDetails) => { - const {participants} = report; + const {participantAccountIDs} = report; - return _.chain(participants) - .map((login) => { - const userLogin = Str.removeSMSDomain(login); - const userPersonalDetail = lodashGet(personalDetails, login, {displayName: userLogin, avatar: ''}); + return _.chain(participantAccountIDs) + .map((accountID) => { + const userLogin = Str.removeSMSDomain(personalDetails.login) || 'Hidden'; + const userPersonalDetail = lodashGet(personalDetails, accountID, {displayName: personalDetails.displayName || 'Hidden', avatar: ''}); return { alternateText: userLogin, displayName: userPersonalDetail.displayName, icons: [ { - source: UserUtils.getAvatar(userPersonalDetail.avatar, login), - name: login, + source: UserUtils.getAvatar(userPersonalDetail.avatar, accountID), + name: userLogin, type: CONST.ICON_TYPE_AVATAR, }, ], - keyForList: userLogin, - login, + keyForList: accountID, + login: userLogin, text: userPersonalDetail.displayName, tooltipText: userLogin, - participantsList: [{login, displayName: userPersonalDetail.displayName}], + participantsList: [{accountID, displayName: userPersonalDetail.displayName}], }; }) .sortBy((participant) => participant.displayName.toLowerCase()) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 8b1c0513dc9d..480615e76dc1 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -904,9 +904,10 @@ class ReportActionCompose extends React.Component { } render() { - const reportParticipants = _.without(lodashGet(this.props.report, 'participants', []), this.props.currentUserPersonalDetails.login); - const participantsWithoutExpensifyEmails = _.difference(reportParticipants, CONST.EXPENSIFY_EMAILS); - const reportRecipient = this.props.personalDetails[participantsWithoutExpensifyEmails[0]]; + const reportParticipants = _.without(lodashGet(this.props.report, 'participantAccountIDs', []), this.props.currentUserPersonalDetails.accountID); + // TODO: ACCOUNT IDS!!! + const participantsWithoutExpensifyAccountIDs = _.difference(reportParticipants, CONST.EXPENSIFY_EMAILS); + const reportRecipient = this.props.personalDetails[participantsWithoutExpensifyAccountIDs[0]]; const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(this.props.personalDetails, this.props.report, this.props.currentUserPersonalDetails.login) && !this.props.isComposerFullSize; diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js index eb5f9efb85a2..915f6b4b80b6 100644 --- a/src/pages/home/sidebar/SidebarLinks.js +++ b/src/pages/home/sidebar/SidebarLinks.js @@ -69,6 +69,9 @@ const propTypes = { /** Login email of the current user */ login: PropTypes.string, + + /** AccountID of the current user */ + accountID: PropTypes.number, }), /** Current reportID from the route in react navigation state object */ @@ -200,7 +203,7 @@ class SidebarLinks extends React.Component { ) : ( @@ -266,10 +269,11 @@ const personalDetailsSelector = (personalDetails) => // It's OK to do param-reassignment in _.reduce() because we absolutely know the starting state of finalPersonalDetails // eslint-disable-next-line no-param-reassign finalPersonalDetails[accountID] = { + accountID, login: personalData.login, displayName: personalData.displayName, firstName: personalData.firstName, - avatar: UserUtils.getAvatar(personalData.avatar, personalData.login), + avatar: UserUtils.getAvatar(personalData.avatar, personalData.accountID), }; return finalPersonalDetails; }, diff --git a/src/pages/personalDetailsPropType.js b/src/pages/personalDetailsPropType.js index a86e42ae6fa8..cf02b34f3fbd 100644 --- a/src/pages/personalDetailsPropType.js +++ b/src/pages/personalDetailsPropType.js @@ -16,6 +16,9 @@ export default PropTypes.shape({ // Flag to set when Avatar uploading avatarUploading: PropTypes.bool, + // accountID of the current user from their personal details + accountID: PropTypes.number, + // login of the current user from their personal details login: PropTypes.string, From f141c28f13962b3bf544f731914186773958dc5b Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 14:52:50 -0400 Subject: [PATCH 28/60] A few more small migrations --- src/libs/OptionsListUtils.js | 11 +++++++++-- .../MoneyRequestParticipantsSplitSelector.js | 5 +++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 34c7f19f22a8..f3abf4fa96d8 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -23,9 +23,13 @@ import * as UserUtils from './UserUtils'; */ let currentUserLogin; +let currentUserAccountID; Onyx.connect({ key: ONYXKEYS.SESSION, - callback: (val) => (currentUserLogin = val && val.email), + callback: (val) => { + currentUserLogin = val && val.email; + currentUserAccountID = val && val.accountID; + }, }); let loginList; @@ -243,6 +247,7 @@ function getParticipantNames(personalDetailList) { // `_.contains(Array, value)` for an Array with n members. const participantNames = new Set(); _.each(personalDetailList, (participant) => { + // TODO: maybe get participant name by accountID in personalDetails?? if (participant.login) { participantNames.add(participant.login.toLowerCase()); } @@ -446,7 +451,7 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { } const lastActorDetails = personalDetailMap[report.lastActorAccountID] || null; - let lastMessageText = hasMultipleParticipants && lastActorDetails && lastActorDetails.login !== currentUserLogin ? `${lastActorDetails.displayName}: ` : ''; + let lastMessageText = hasMultipleParticipants && lastActorDetails && lastActorDetails.accountID !== currentUserAccountID ? `${lastActorDetails.displayName}: ` : ''; lastMessageText += report ? lastMessageTextFromReport : ''; if (result.isArchivedRoom) { @@ -510,6 +515,8 @@ function isSearchStringMatch(searchValue, searchText, participantNames = new Set /** * Checks if the given userDetails is currentUser or not. + * Note: We can't migrate this off of using logins because this is used to check if you're trying to start a chat with + * yourself or a different user, and people won't be starting new chats via accountID usually. * * @param {Object} userDetails * @returns {Boolean} diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index 813a8740c5b9..e0b77787462c 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -170,12 +170,12 @@ class MoneyRequestParticipantsSplitSelector extends Component { * @param {Object} option */ toggleOption(option) { - const isOptionInList = _.some(this.props.participants, (selectedOption) => selectedOption.login === option.login); + const isOptionInList = _.some(this.props.participants, (selectedOption) => selectedOption.accountID === option.accountID); let newSelectedOptions; if (isOptionInList) { - newSelectedOptions = _.reject(this.props.participants, (selectedOption) => selectedOption.login === option.login); + newSelectedOptions = _.reject(this.props.participants, (selectedOption) => selectedOption.accountID === option.accountID); } else { newSelectedOptions = [...this.props.participants, option]; } @@ -189,6 +189,7 @@ class MoneyRequestParticipantsSplitSelector extends Component { this.props.betas, isOptionInList ? prevState.searchTerm : '', newSelectedOptions, + // TODO: need to update :D CONST.EXPENSIFY_EMAILS, ); return { From fd201cd195d6cba3085f71fba904c852f36dac24 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 15:34:27 -0400 Subject: [PATCH 29/60] Add most expensify-email accountIDs --- .env.example | 17 ++++++++++++ src/CONST.js | 77 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/.env.example b/.env.example index cf13ef583016..944da2aa9296 100644 --- a/.env.example +++ b/.env.example @@ -11,3 +11,20 @@ USE_WEB_PROXY=false USE_WDYR=false CAPTURE_METRICS=false ONYX_METRICS=false + +EXPENSIFY_ACCOUNT_ID_ACCOUNTING=-1 +EXPENSIFY_ACCOUNT_ID_ADMIN=-1 +EXPENSIFY_ACCOUNT_ID_BILLS=-1 +EXPENSIFY_ACCOUNT_ID_CHRONOS=-1 +EXPENSIFY_ACCOUNT_ID_CONCIERGE=-1 +EXPENSIFY_ACCOUNT_ID_CONTRIBUTORS=-1 +EXPENSIFY_ACCOUNT_ID_FIRST_RESPONDER=-1 +EXPENSIFY_ACCOUNT_ID_HELP=-1 +EXPENSIFY_ACCOUNT_ID_INTEGRATION_TESTING_CREDS=-1 +EXPENSIFY_ACCOUNT_ID_PAYROLL=-1 +EXPENSIFY_ACCOUNT_ID_QA=-1 +EXPENSIFY_ACCOUNT_ID_QA_TRAVIS=-1 +EXPENSIFY_ACCOUNT_ID_RECEIPTS=-1 +EXPENSIFY_ACCOUNT_ID_REWARDS=-1 +EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR=-1 +EXPENSIFY_ACCOUNT_ID_SVFG=-1 diff --git a/src/CONST.js b/src/CONST.js index 36847666c2e3..3695a263c86c 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -854,26 +854,43 @@ const CONST = { LHN_SKELETON_VIEW_ITEM_HEIGHT: 64, EXPENSIFY_PARTNER_NAME: 'expensify.com', EMAIL: { - CONCIERGE: 'concierge@expensify.com', - HELP: 'help@expensify.com', - RECEIPTS: 'receipts@expensify.com', + ACCOUNTING: 'accounting@expensify.com', + ADMIN: 'admin@expensify.com', + BILLS: 'bills@expensify.com', CHRONOS: 'chronos@expensify.com', - QA: 'qa@expensify.com', + CONCIERGE: 'concierge@expensify.com', CONTRIBUTORS: 'contributors@expensify.com', FIRST_RESPONDER: 'firstresponders@expensify.com', + GUIDES_DOMAIN: 'team.expensify.com', + HELP: 'help@expensify.com', + INTEGRATION_TESTING_CREDS: 'integrationtestingcreds@expensify.com', + PAYROLL: 'payroll@expensify.com', + QA: 'qa@expensify.com', QA_TRAVIS: 'qa+travisreceipts@expensify.com', - BILLS: 'bills@expensify.com', + RECEIPTS: 'receipts@expensify.com', STUDENT_AMBASSADOR: 'studentambassadors@expensify.com', - ACCOUNTING: 'accounting@expensify.com', - PAYROLL: 'payroll@expensify.com', SVFG: 'svfg@expensify.com', - INTEGRATION_TESTING_CREDS: 'integrationtestingcreds@expensify.com', - ADMIN: 'admin@expensify.com', - GUIDES_DOMAIN: 'team.expensify.com', }, ACCOUNT_ID: { - CONCIERGE: '8392101', + ACCOUNTING: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_ACCOUNTING', 9645353), + ADMIN: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_ADMIN', -1), + BILLS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_BILLS', 1371), + CHRONOS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CHRONOS', 10027416), + CONCIERGE: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CONCIERGE', 8392101), + CONTRIBUTORS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CONTRIBUTORS', 9675014), + FIRST_RESPONDER: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_FIRST_RESPONDER', 9375152), + HELP: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_HELP', -1), + INTEGRATION_TESTING_CREDS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_INTEGRATION_TESTING_CREDS', -1), + PAYROLL: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_PAYROLL', 9679724), + QA: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA', 3126513), + QA_TRAVIS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA_TRAVIS', 8595733), + RECEIPTS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1), + REWARDS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767), // rewards@expensify.com + STUDENT_AMBASSADOR: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956), + SVFG: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843), + // TODO: maybe make separate domain email things?? + // GUIDES_DOMAIN: , }, ENVIRONMENT: { @@ -1157,23 +1174,43 @@ const CONST = { }, get EXPENSIFY_EMAILS() { return [ - this.EMAIL.CONCIERGE, - this.EMAIL.HELP, - this.EMAIL.RECEIPTS, + this.EMAIL.ACCOUNTING, + this.EMAIL.ADMIN, + this.EMAIL.BILLS, this.EMAIL.CHRONOS, - this.EMAIL.QA, + this.EMAIL.CONCIERGE, this.EMAIL.CONTRIBUTORS, this.EMAIL.FIRST_RESPONDER, + this.EMAIL.HELP, + this.EMAIL.INTEGRATION_TESTING_CREDS, + this.EMAIL.PAYROLL, + this.EMAIL.QA, this.EMAIL.QA_TRAVIS, - this.EMAIL.BILLS, + this.EMAIL.RECEIPTS, this.EMAIL.STUDENT_AMBASSADOR, - this.EMAIL.ACCOUNTING, - this.EMAIL.PAYROLL, this.EMAIL.SVFG, - this.EMAIL.INTEGRATION_TESTING_CREDS, - this.EMAIL.ADMIN, ]; }, + get EXPENSIFY_ACCOUNT_IDS() { + return [ + this.ACCOUNT_ID.ACCOUNTING, + this.ACCOUNT_ID.ADMIN, + this.ACCOUNT_ID.BILLS, + this.ACCOUNT_ID.CHRONOS, + this.ACCOUNT_ID.CONCIERGE, + this.ACCOUNT_ID.CONTRIBUTORS, + this.ACCOUNT_ID.FIRST_RESPONDER, + this.ACCOUNT_ID.HELP, + this.ACCOUNT_ID.INTEGRATION_TESTING_CREDS, + this.ACCOUNT_ID.PAYROLL, + this.ACCOUNT_ID.QA, + this.ACCOUNT_ID.QA_TRAVIS, + this.ACCOUNT_ID.RECEIPTS, + this.ACCOUNT_ID.REWARDS, + this.ACCOUNT_ID.STUDENT_AMBASSADOR, + this.ACCOUNT_ID.SVFG, + ] + } // Auth limit is 60k for the column but we store edits and other metadata along the html so let's use a lower limit to accommodate for it. MAX_COMMENT_LENGTH: 15000, From 73cdf02a8d0487d70aad6df6d365168f0682b4da Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 16:01:10 -0400 Subject: [PATCH 30/60] More migration to report participantAccountIDs --- src/components/ReportActionItem/IOUPreview.js | 16 ++++----- src/libs/OptionsListUtils.js | 20 ++++++++++- src/libs/ReportUtils.js | 35 ++++++++++--------- src/libs/SidebarUtils.js | 2 +- src/libs/actions/Task.js | 2 +- 5 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 4defeb177b70..1b61046aaf1c 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -127,14 +127,14 @@ const IOUPreview = (props) => { if (_.isEmpty(props.iouReport)) { return null; } - const sessionEmail = lodashGet(props.session, 'email', null); - const managerEmail = props.iouReport.managerEmail || ''; - const ownerEmail = props.iouReport.ownerEmail || ''; - const participantEmails = props.isBillSplit ? lodashGet(props.action, 'originalMessage.participants', []) : [managerEmail, ownerEmail]; - const participantAvatars = OptionsListUtils.getAvatarsForLogins(participantEmails, props.personalDetails); + const sessionAccountID = lodashGet(props.session, 'accountID', null); + const managerID = props.iouReport.managerID || ''; + const ownerAccountID = props.iouReport.ownerAccountID || ''; + const participantAccountIDs = props.isBillSplit ? lodashGet(props.action, 'originalMessage.participantAccountIDs', []) : [managerID, ownerAccountID]; + const participantAvatars = OptionsListUtils.getAvatarsForAccountIDs(participantAccountIDs, props.personalDetails); // Pay button should only be visible to the manager of the report. - const isCurrentUserManager = managerEmail === sessionEmail; + const isCurrentUserManager = managerID === sessionAccountID; const moneyRequestAction = ReportUtils.getMoneyRequestAction(props.action); @@ -227,10 +227,10 @@ const IOUPreview = (props) => { )} {!_.isEmpty(requestComment) && {requestComment}} - {props.isBillSplit && !_.isEmpty(participantEmails) && ( + {props.isBillSplit && !_.isEmpty(participantAccountIDs) && ( {props.translate('iou.amountEach', { - amount: CurrencyUtils.convertToDisplayString(IOUUtils.calculateAmount(participantEmails.length - 1, requestAmount), requestCurrency), + amount: CurrencyUtils.convertToDisplayString(IOUUtils.calculateAmount(participantAccountIDs.length - 1, requestAmount), requestCurrency), })} )} diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index f3abf4fa96d8..7643377080eb 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -164,6 +164,23 @@ function getAvatarsForLogins(logins, personalDetails) { }); } +/** + * Returns avatar data for a list of user accountIDs + * + * @param {*} accountIDs + * @param {*} personalDetails + */ +function getAvatarsForAccountIDs(accountIDs, personalDetails) { + return _.map(accountIDs, (accountID) => { + const userPersonalDetail = lodashGet(personalDetails, accountID, {login: '', accountID, avatar: ''}); + return { + source: UserUtils.getAvatar(userPersonalDetail.avatar, userPersonalDetail.accountID), + type: CONST.ICON_TYPE_AVATAR, + name: userPersonalDetail.login, + }; + }); +} + /** * Returns the personal details for an array of accountIDs * @@ -437,7 +454,7 @@ function createOption(accountIDs, personalDetails, report, reportActions = {}, { result.isPinned = report.isPinned; result.iouReportID = report.iouReportID; result.keyForList = String(report.reportID); - result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participants || []); + result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs || []); result.hasOutstandingIOU = report.hasOutstandingIOU; hasMultipleParticipants = personalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; @@ -963,6 +980,7 @@ function getHeaderMessage(hasSelectableOptions, hasUserToInvite, searchValue, ma export { addSMSDomainIfPhoneNumber, getAvatarsForLogins, + getAvatarsForAccountIDs, isCurrentUser, isPersonalDetailsReady, getSearchOptions, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 46532e014522..2903da24ef7a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -89,16 +89,15 @@ function getChatType(report) { /** * Returns the concatenated title for the PrimaryLogins of a report * - * @param {Array} logins + * @param {Array} accountIDs * @returns {string} */ -function getReportParticipantsTitle(logins) { +function getReportParticipantsTitle(accountIDs) { return ( - _.chain(logins) + _.chain(accountIDs) - // Somehow it's possible for the logins coming from report.participants to contain undefined values so we use compact to remove them. + // Somehow it's possible for the logins coming from report.participantAccountIDs to contain undefined values so we use compact to remove them. .compact() - .map((login) => Str.removeSMSDomain(login)) .value() .join(', ') ); @@ -371,7 +370,7 @@ function hasExpensifyGuidesEmails(emails) { * @returns {Boolean} */ function isConciergeChatReport(report) { - return lodashGet(report, 'participants', []).length === 1 && report.participants[0] === CONST.EMAIL.CONCIERGE; + return lodashGet(report, 'participantAccountIDs', []).length === 1 && report.participantAccountIDs[0] === CONST.ACCOUNT_ID.CONCIERGE; } /** @@ -401,6 +400,8 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim // We allow public announce rooms, admins, and announce rooms through since we bypass the default rooms beta for them. // Check where ReportUtils.findLastAccessedReport is called in MainDrawerNavigator.js for more context. // Domain rooms are now the only type of default room that are on the defaultRooms beta. + // TODO: migrate to report.participantAccountIDs later - not sure how we'll determine if a list of account IDs + // includes an expensify guide account ID :O sortedReports = _.filter( sortedReports, (report) => !isDomainRoom(report) || getPolicyType(report, policies) === CONST.POLICY.TYPE.FREE || hasExpensifyGuidesEmails(lodashGet(report, ['participants'], [])), @@ -608,7 +609,7 @@ function getRoomWelcomeMessage(report) { * @returns {Boolean} */ function chatIncludesConcierge(report) { - return report.participants && _.contains(report.participants, CONST.EMAIL.CONCIERGE); + return report.participantAccountIDs && _.contains(report.participantAccountIDs, CONST.ACCOUNT_ID.CONCIERGE); } /** @@ -647,10 +648,10 @@ function hasExpensifyEmails(emails) { * @return {Boolean} */ function canShowReportRecipientLocalTime(personalDetails, report, login) { - const reportParticipants = _.without(lodashGet(report, 'participants', []), login); - const participantsWithoutExpensifyEmails = _.difference(reportParticipants, CONST.EXPENSIFY_EMAILS); - const hasMultipleParticipants = participantsWithoutExpensifyEmails.length > 1; - const reportRecipient = personalDetails[participantsWithoutExpensifyEmails[0]]; + const reportParticipants = _.without(lodashGet(report, 'participantAccountIDs', []), login); + const participantsWithoutExpensifyAccountIDs = _.difference(reportParticipants, CONST.EXPENSIFY_ACCOUNT_IDS); + const hasMultipleParticipants = participantsWithoutExpensifyAccountIDs.length > 1; + const reportRecipient = personalDetails[participantsWithoutExpensifyAccountIDs[0]]; const reportRecipientTimezone = lodashGet(reportRecipient, 'timezone', CONST.DEFAULT_TIME_ZONE); const isReportParticipantValidated = lodashGet(reportRecipient, 'validated', false); return Boolean( @@ -1831,7 +1832,7 @@ function shouldReportBeInOptionList(report, reportIDFromRoute, isInGSDMode, iouR if ( !report || !report.reportID || - (_.isEmpty(report.participants) && !isThread(report) && !isPublicRoom(report) && !isArchivedRoom(report) && !isMoneyRequestReport(report) && !isTaskReport(report)) + (_.isEmpty(report.participantAccountIDs) && !isThread(report) && !isPublicRoom(report) && !isArchivedRoom(report) && !isMoneyRequestReport(report) && !isTaskReport(report)) ) { return false; } @@ -1886,12 +1887,12 @@ function getChatByParticipants(newParticipantList) { newParticipantList.sort(); return _.find(allReports, (report) => { // If the report has been deleted, or there are no participants (like an empty #admins room) then skip it - if (!report || !report.participants || isThread(report)) { + if (!report || !report.participantAccountIDs || isThread(report)) { return false; } // Only return the room if it has all the participants and is not a policy room - return !isUserCreatedPolicyRoom(report) && _.isEqual(newParticipantList, _.sortBy(report.participants)); + return !isUserCreatedPolicyRoom(report) && _.isEqual(newParticipantList, _.sortBy(report.participantAccountIDs)); }); } @@ -1905,12 +1906,12 @@ function getChatByParticipantsAndPolicy(newParticipantList, policyID) { newParticipantList.sort(); return _.find(allReports, (report) => { // If the report has been deleted, or there are no participants (like an empty #admins room) then skip it - if (!report || !report.participants) { + if (!report || !report.participantAccountIDs) { return false; } // Only return the room if it has all the participants and is not a policy room - return report.policyID === policyID && _.isEqual(newParticipantList, _.sortBy(report.participants)); + return report.policyID === policyID && _.isEqual(newParticipantList, _.sortBy(report.participantAccountIDs)); }); } @@ -1928,7 +1929,7 @@ function getAllPolicyReports(policyID) { * @returns {Boolean} */ function chatIncludesChronos(report) { - return report.participants && _.contains(report.participants, CONST.EMAIL.CHRONOS); + return report.participantAccountIDs && _.contains(report.participantAccountIDs, CONST.ACCOUNT_ID.CHRONOS); } /** diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 1b8c4c9e29a8..90be9454db57 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -255,7 +255,7 @@ function getOptionData(reportID) { result.isPinned = report.isPinned; result.iouReportID = report.iouReportID; result.keyForList = String(report.reportID); - result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participants || []); + result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs || []); result.hasOutstandingIOU = report.hasOutstandingIOU; result.parentReportID = report.parentReportID || null; const parentReport = result.parentReportID ? allReports[`${ONYXKEYS.COLLECTION.REPORT}${result.parentReportID}`] : null; diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index ec150a332155..0b3204ee53da 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -485,7 +485,7 @@ function getAssignee(details) { subtitle: '', }; } - const source = UserUtils.getAvatar(lodashGet(details, 'avatar', ''), lodashGet(details, 'login', '')); + const source = UserUtils.getAvatar(lodashGet(details, 'avatar', ''), lodashGet(details, 'accountID', -1)); return { icons: [{source, type: 'avatar', name: details.login}], displayName: details.displayName, From 60b146307d9bd45b80df0d288c89bbeaa8b86985 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 16:08:17 -0400 Subject: [PATCH 31/60] Add missing comma --- src/CONST.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 3695a263c86c..18d88d5cc4e6 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -1209,8 +1209,8 @@ const CONST = { this.ACCOUNT_ID.REWARDS, this.ACCOUNT_ID.STUDENT_AMBASSADOR, this.ACCOUNT_ID.SVFG, - ] - } + ]; + }, // Auth limit is 60k for the column but we store edits and other metadata along the html so let's use a lower limit to accommodate for it. MAX_COMMENT_LENGTH: 15000, From 3d577f50a24299660105df6f013d70c9f0aa8e4e Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 13:49:21 -0700 Subject: [PATCH 32/60] Get policy member details by accountID --- src/pages/workspace/WorkspaceMembersPage.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index e65510ba7ed4..6570481b9ed9 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -35,6 +35,7 @@ import TextInput from '../../components/TextInput'; import KeyboardDismissingFlatList from '../../components/KeyboardDismissingFlatList'; import withCurrentUserPersonalDetails from '../../components/withCurrentUserPersonalDetails'; import * as PolicyUtils from '../../libs/PolicyUtils'; +import Log from '../../libs/Log'; const propTypes = { /** The personal details of the person who is logged in */ @@ -371,16 +372,19 @@ class WorkspaceMembersPage extends React.Component { } render() { - const policyMemberList = lodashGet(this.props, 'policyMemberList', {}); const policyOwner = lodashGet(this.props.policy, 'owner'); const currentUserLogin = lodashGet(this.props.currentUserPersonalDetails, 'login'); const removableMembers = {}; let data = []; - _.each(policyMemberList, (policyMember, email) => { + _.each(this.props.policyMembers, (policyMember, accountID) => { if (this.isDeletedPolicyMember(policyMember)) { return; } - const details = lodashGet(this.props.personalDetails, email, {displayName: email, login: email}); + const details = this.props.personalDetails[accountID]; + if (!details) { + Log.hmmm(`[WorkspaceMembersPage] no personal details found for policy member with accountID: ${accountID}`); + return; + } data.push({ ...policyMember, ...details, From 43d050a00925b38952d560bd330974ba18c26599 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 14:25:41 -0700 Subject: [PATCH 33/60] Fix get workspace members when keyed by accountID --- src/pages/workspace/WorkspaceMembersPage.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 6570481b9ed9..29b25e9b7662 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -118,10 +118,18 @@ class WorkspaceMembersPage extends React.Component { */ getWorkspaceMembers() { /** - * We filter clientMemberEmails to only pass members without errors - * Otherwise, the members with errors would immediately be removed before the user has a chance to read the error + * Create a list of member emails by filtering for members without errors, then mapping each policy member accountID to the login from the personalDetail object. + * TODO: Clean up OpenWorkspaceMembersPage so we can pass accountIDs instead of emails. + * + * We filter clientMemberEmails to only pass members without errors. Otherwise, the members with errors would immediately be removed before the user has a chance to read the error. */ - const clientMemberEmails = _.keys(_.pick(this.props.policyMemberList, (member) => _.isEmpty(member.errors))); + const clientMemberEmails = _.chain(this.props.policyMembers) + .filter((member) => _.isEmpty(member.errors)) + .keys() + .map((accountID) => this.props.personalDetails[accountID]) + .compact() + .value(); + Policy.openWorkspaceMembersPage(this.props.route.params.policyID, clientMemberEmails); } From 083c8a8d249e82dc9be384630caf03f9eecf1cec Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 17:30:12 -0400 Subject: [PATCH 34/60] A few more updates --- src/CONST.js | 32 +++++++++++------------ src/components/participantPropTypes.js | 2 +- src/libs/OptionsListUtils.js | 8 +++--- src/libs/ReportUtils.js | 9 ++++++- src/libs/SidebarUtils.js | 7 ++++- src/libs/UserUtils.js | 2 +- src/pages/home/report/ReportActionItem.js | 4 +-- src/pages/personalDetailsPropType.js | 2 +- 8 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 18d88d5cc4e6..2e0b684fd8f2 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -873,22 +873,22 @@ const CONST = { }, ACCOUNT_ID: { - ACCOUNTING: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_ACCOUNTING', 9645353), - ADMIN: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_ADMIN', -1), - BILLS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_BILLS', 1371), - CHRONOS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CHRONOS', 10027416), - CONCIERGE: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CONCIERGE', 8392101), - CONTRIBUTORS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CONTRIBUTORS', 9675014), - FIRST_RESPONDER: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_FIRST_RESPONDER', 9375152), - HELP: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_HELP', -1), - INTEGRATION_TESTING_CREDS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_INTEGRATION_TESTING_CREDS', -1), - PAYROLL: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_PAYROLL', 9679724), - QA: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA', 3126513), - QA_TRAVIS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA_TRAVIS', 8595733), - RECEIPTS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1), - REWARDS: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767), // rewards@expensify.com - STUDENT_AMBASSADOR: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956), - SVFG: lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843), + ACCOUNTING: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_ACCOUNTING', 9645353)), + ADMIN: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_ADMIN', -1)), + BILLS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_BILLS', 1371)), + CHRONOS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CHRONOS', 10027416)), + CONCIERGE: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CONCIERGE', 8392101)), + CONTRIBUTORS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_CONTRIBUTORS', 9675014)), + FIRST_RESPONDER: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_FIRST_RESPONDER', 9375152)), + HELP: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_HELP', -1)), + INTEGRATION_TESTING_CREDS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_INTEGRATION_TESTING_CREDS', -1)), + PAYROLL: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_PAYROLL', 9679724)), + QA: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA', 3126513)), + QA_TRAVIS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_QA_TRAVIS', 8595733)), + RECEIPTS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_RECEIPTS', -1)), + REWARDS: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_REWARDS', 11023767)), // rewards@expensify.com + STUDENT_AMBASSADOR: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_STUDENT_AMBASSADOR', 10476956)), + SVFG: Number(lodashGet(Config, 'EXPENSIFY_ACCOUNT_ID_SVFG', 2012843)), // TODO: maybe make separate domain email things?? // GUIDES_DOMAIN: , }, diff --git a/src/components/participantPropTypes.js b/src/components/participantPropTypes.js index a54d82eeb0ed..8ef58595c5d1 100644 --- a/src/components/participantPropTypes.js +++ b/src/components/participantPropTypes.js @@ -5,7 +5,7 @@ export default PropTypes.shape({ login: PropTypes.string, // Account ID of participant - accountID: PropTypes.number, + accountID: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), // Display Name of participant displayName: PropTypes.string, diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 7643377080eb..2f87b9400628 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -189,9 +189,9 @@ function getAvatarsForAccountIDs(accountIDs, personalDetails) { * @returns {Object} – keys of the object are emails, values are PersonalDetails objects. */ function getPersonalDetailsForAccountIDs(accountIDs, personalDetails) { - const personalDetailsForLogins = {}; + const personalDetailsForAccountIDs = {}; if (!personalDetails) { - return personalDetailsForLogins; + return personalDetailsForAccountIDs; } _.chain(accountIDs) // NOTE: this comment is possibly legacy, we need to verify if it's still true @@ -211,9 +211,9 @@ function getPersonalDetailsForAccountIDs(accountIDs, personalDetails) { personalDetail.avatar = CONST.CONCIERGE_ICON_URL; } - personalDetailsForLogins[accountID] = personalDetail; + personalDetailsForAccountIDs[accountID] = personalDetail; }); - return personalDetailsForLogins; + return personalDetailsForAccountIDs; } /** diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 2903da24ef7a..f8faabe57f24 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -370,7 +370,7 @@ function hasExpensifyGuidesEmails(emails) { * @returns {Boolean} */ function isConciergeChatReport(report) { - return lodashGet(report, 'participantAccountIDs', []).length === 1 && report.participantAccountIDs[0] === CONST.ACCOUNT_ID.CONCIERGE; + return lodashGet(report, 'participantAccountIDs', []).length === 1 && report.participantAccountIDs[0] == CONST.ACCOUNT_ID.CONCIERGE; } /** @@ -845,6 +845,13 @@ function getPersonalDetailsForAccountID(accountID) { if (!accountID) { return {}; } + if (accountID == CONST.ACCOUNT_ID.CONCIERGE) { + return { + accountID, + displayName: 'Concierge', + avatar: UserUtils.getDefaultAvatar(accountID), + }; + } return ( (allPersonalDetails && allPersonalDetails[accountID]) || { avatar: UserUtils.getDefaultAvatar(accountID), diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 90be9454db57..c75659343cfe 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -211,9 +211,11 @@ function getOptionData(reportID) { icons: null, tooltipText: null, ownerEmail: null, + ownerAccountID: null, subtitle: null, participantsList: null, login: null, + accountID: null, reportID: null, phoneNumber: null, payPalMeAddress: null, @@ -248,6 +250,7 @@ function getOptionData(reportID) { result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions); result.brickRoadIndicator = !_.isEmpty(result.allReportErrors) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''; result.ownerEmail = report.ownerEmail; + result.ownerAccountID = report.ownerAccountID; result.reportID = report.reportID; result.isUnread = ReportUtils.isUnread(report); result.isUnreadWithMention = ReportUtils.isUnreadWithMention(report); @@ -285,6 +288,7 @@ function getOptionData(reportID) { ? { displayName: lastActorDisplayName, login: report.lastActorEmail, + accountID: report.lastActorAccountID, } : null; } @@ -331,6 +335,7 @@ function getOptionData(reportID) { result.iouReportAmount = ReportUtils.getMoneyRequestTotal(result, allReports); if (!hasMultipleParticipants) { + result.accountID = personalDetail.accountID; result.login = personalDetail.login; result.phoneNumber = personalDetail.phoneNumber; result.payPalMeAddress = personalDetail.payPalMeAddress; @@ -342,7 +347,7 @@ function getOptionData(reportID) { result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; - result.icons = ReportUtils.getIcons(result.isTaskReport ? parentReport : report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.login), true); + result.icons = ReportUtils.getIcons(result.isTaskReport ? parentReport : report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.accountID), true); result.searchText = OptionsListUtils.getSearchText(report, reportName, participantPersonalDetailList, result.isChatRoom || result.isPolicyExpenseChat, result.isThread); result.displayNamesWithTooltips = displayNamesWithTooltips; return result; diff --git a/src/libs/UserUtils.js b/src/libs/UserUtils.js index 964644d730ef..315448d4c549 100644 --- a/src/libs/UserUtils.js +++ b/src/libs/UserUtils.js @@ -83,7 +83,7 @@ function getDefaultAvatar(accountID = -1) { if (accountID <= 0) { return Expensicons.FallbackAvatar; } - if (accountID === CONST.EMAIL.CONCIERGE) { + if (accountID == CONST.ACCOUNT_ID.CONCIERGE) { return Expensicons.ConciergeAvatar; } diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 273c59eb03d9..02ae67acfeb3 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -321,7 +321,7 @@ function ReportActionItem(props) { const hasReplies = numberOfThreadReplies > 0; const shouldDisplayThreadReplies = hasReplies && props.action.childCommenterCount && !ReportUtils.isThreadFirstChat(props.action, props.report.reportID); - const oldestFourEmails = lodashGet(props.action, 'childOldestFourEmails', '').split(','); + const oldestFourAccountIDs = lodashGet(props.action, 'childOldestFourAccountIDs', '').split(','); const draftMessageRightAlign = props.draftMessage ? styles.chatItemReactionsDraftRight : {}; return ( @@ -353,7 +353,7 @@ function ReportActionItem(props) { numberOfReplies={numberOfThreadReplies} mostRecentReply={`${props.action.childLastVisibleActionCreated}`} isHovered={hovered} - icons={ReportUtils.getIconsForParticipants(oldestFourEmails, props.personalDetails)} + icons={ReportUtils.getIconsForParticipants(oldestFourAccountIDs, props.personalDetails)} /> )} diff --git a/src/pages/personalDetailsPropType.js b/src/pages/personalDetailsPropType.js index cf02b34f3fbd..e0f906f137d2 100644 --- a/src/pages/personalDetailsPropType.js +++ b/src/pages/personalDetailsPropType.js @@ -17,7 +17,7 @@ export default PropTypes.shape({ avatarUploading: PropTypes.bool, // accountID of the current user from their personal details - accountID: PropTypes.number, + accountID: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), // login of the current user from their personal details login: PropTypes.string, From 5204d4c569d305332fcfc07176a822e2e1e6162c Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 14:36:45 -0700 Subject: [PATCH 35/60] Set selected employees with members by accountIDs --- src/pages/workspace/WorkspaceMembersPage.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 29b25e9b7662..eed37a42b349 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -99,10 +99,18 @@ class WorkspaceMembersPage extends React.Component { this.validate(); } - if (prevProps.policyMemberList !== this.props.policyMemberList) { - this.setState((prevState) => ({ - selectedEmployees: _.intersection(prevState.selectedEmployees, _.keys(this.props.policyMemberList)), - })); + if (prevProps.policyMembers !== this.props.policyMembers) { + this.setState((prevState) => { + const policyMemberEmails = _.chain(this.props.policyMembers) + .keys() + .map((accountID) => this.personalDetails[accountID]) + .compact() + .map((personalDetail) => personalDetail.login) + .value(); + return { + selectedEmployees: _.intersection(prevState.selectedEmployees, policyMemberEmails), + } + }); } const isReconnecting = prevProps.network.isOffline && !this.props.network.isOffline; @@ -128,6 +136,7 @@ class WorkspaceMembersPage extends React.Component { .keys() .map((accountID) => this.props.personalDetails[accountID]) .compact() + .map((personalDetail) => personalDetail.login) .value(); Policy.openWorkspaceMembersPage(this.props.route.params.policyID, clientMemberEmails); From b5c20b7278892566079cd8f618062f62f6df261b Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 17:46:20 -0400 Subject: [PATCH 36/60] Update needed hoc --- src/components/withCurrentUserPersonalDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/withCurrentUserPersonalDetails.js b/src/components/withCurrentUserPersonalDetails.js index 60819a5f9ec4..cc0a5c1aab51 100644 --- a/src/components/withCurrentUserPersonalDetails.js +++ b/src/components/withCurrentUserPersonalDetails.js @@ -38,7 +38,7 @@ export default function (WrappedComponent) { const WithCurrentUserPersonalDetails = (props) => { const currentUserEmail = props.session.email; const accountID = props.session.accountID; - const currentUserPersonalDetails = useMemo(() => ({...props.personalDetails[currentUserEmail], accountID}), [props.personalDetails, currentUserEmail, accountID]); + const currentUserPersonalDetails = useMemo(() => ({...props.personalDetails[accountID], accountID}), [props.personalDetails, currentUserEmail, accountID]); return ( Date: Wed, 7 Jun 2023 17:52:34 -0400 Subject: [PATCH 37/60] Update personal details --- src/libs/actions/PersonalDetails.js | 32 ++++++++++++++++------------- src/libs/actions/User.js | 6 +++--- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 9726b62b3bf6..07da46ff18a5 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -11,9 +11,13 @@ import ROUTES from '../../ROUTES'; import Navigation from '../Navigation/Navigation'; let currentUserEmail = ''; +let currentUserAccountID; Onyx.connect({ key: ONYXKEYS.SESSION, - callback: (val) => (currentUserEmail = val ? val.email : ''), + callback: (val) => { + currentUserEmail = val ? val.email : ''; + currentUserAccountID = val ? val.accountID : -1; + }, }); let personalDetails; @@ -104,7 +108,7 @@ function updatePronouns(pronouns) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { + [currentUserAccountID]: { pronouns, }, }, @@ -129,7 +133,7 @@ function updateDisplayName(firstName, lastName) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { + [currentUserAccountID]: { firstName, lastName, displayName: getDisplayName(currentUserEmail, { @@ -254,7 +258,7 @@ function updateAutomaticTimezone(timezone) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { + [currentUserAccountID]: { timezone, }, }, @@ -321,7 +325,7 @@ function updateAvatar(file) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { + [currentUserAccountID]: { avatar: file.uri, avatarThumbnail: file.uri, originalFileName: file.name, @@ -341,7 +345,7 @@ function updateAvatar(file) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { + [currentUserAccountID]: { pendingFields: { avatar: null, }, @@ -354,9 +358,9 @@ function updateAvatar(file) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { - avatar: personalDetails[currentUserEmail].avatar, - avatarThumbnail: personalDetails[currentUserEmail].avatarThumbnail || personalDetails[currentUserEmail].avatar, + [currentUserAccountID]: { + avatar: personalDetails[currentUserAccountID].avatar, + avatarThumbnail: personalDetails[currentUserAccountID].avatarThumbnail || personalDetails[currentUserAccountID].avatar, pendingFields: { avatar: null, }, @@ -373,7 +377,7 @@ function updateAvatar(file) { */ function deleteAvatar() { // We want to use the old dot avatar here as this affects both platforms. - const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserEmail); + const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserAccountID); API.write( 'DeleteUserAvatar', @@ -384,7 +388,7 @@ function deleteAvatar() { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { + [currentUserAccountID]: { avatar: defaultAvatar, }, }, @@ -395,8 +399,8 @@ function deleteAvatar() { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { - avatar: personalDetails[currentUserEmail].avatar, + [currentUserAccountID]: { + avatar: personalDetails[currentUserAccountID].avatar, }, }, }, @@ -410,7 +414,7 @@ function deleteAvatar() { */ function clearAvatarErrors() { Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { - [currentUserEmail]: { + [currentUserAccountID]: { errorFields: { avatar: null, }, diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index d3959be7497e..9e2ae4abd637 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -24,7 +24,7 @@ let currentEmail = ''; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { - currentUserAccountID = lodashGet(val, 'accountID', ''); + currentUserAccountID = lodashGet(val, 'accountID', -1); currentEmail = lodashGet(val, 'email', ''); }, }); @@ -33,11 +33,11 @@ let myPersonalDetails = {}; Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (val) => { - if (!val || !currentEmail) { + if (!val || !currentUserAccountID) { return; } - myPersonalDetails = val[currentEmail]; + myPersonalDetails = val[currentUserAccountID]; }, }); From 40aaaad42aef845c8f19a1ff34c57c96fa984343 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 18:13:13 -0400 Subject: [PATCH 38/60] A few little fixes --- src/components/ReportWelcomeText.js | 2 +- src/pages/DetailsPage.js | 23 +++++++++++++++++------ src/pages/reportPropTypes.js | 9 +++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js index 667f705d205a..460d8cef0119 100644 --- a/src/components/ReportWelcomeText.js +++ b/src/components/ReportWelcomeText.js @@ -70,7 +70,7 @@ const ReportWelcomeText = (props) => { {props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartOne')} {/* Use the policyExpenseChat owner's first name or their email if it's undefined or an empty string */} - {lodashGet(props.personalDetails, [props.report.ownerEmail, 'firstName']) || props.report.ownerEmail} + {lodashGet(props.personalDetails, [props.report.ownerAccountID, 'firstName']) || props.report.ownerEmail} {props.translate('reportActionsView.beginningOfChatHistoryPolicyExpenseChatPartTwo')} {ReportUtils.getPolicyName(props.report)} diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index b21dfbb3f97a..63167fa53211 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -95,12 +95,23 @@ class DetailsPage extends React.PureComponent { }); if (!details) { - details = { - accountID: -1, - login, - displayName: login, - avatar: UserUtils.getDefaultAvatar(), - }; + // TODO: these personal details aren't in my local test account but are in + // my staging account, i wonder why! + if (login == CONST.EMAIL.CONCIERGE) { + details = { + accountID: CONST.ACCOUNT_ID.CONCIERGE, + login, + displayName: 'Concierge', + avatar: UserUtils.getDefaultAvatar(CONST.ACCOUNT_ID.CONCIERGE), + }; + } else { + details = { + accountID: -1, + login, + displayName: login, + avatar: UserUtils.getDefaultAvatar(), + }; + } } const isSMSLogin = details.login ? Str.isSMSLogin(details.login) : false; diff --git a/src/pages/reportPropTypes.js b/src/pages/reportPropTypes.js index bb7c197e8bf2..20d10758b030 100644 --- a/src/pages/reportPropTypes.js +++ b/src/pages/reportPropTypes.js @@ -28,6 +28,9 @@ export default PropTypes.shape({ /** The email of the last message's actor */ lastActorEmail: PropTypes.string, + /** The accountID of the last message's actor */ + lastActorAccountID: PropTypes.number, + /** The text of the last message on the report */ lastMessageText: PropTypes.string, @@ -50,9 +53,15 @@ export default PropTypes.shape({ /** The email address of the report owner */ ownerEmail: PropTypes.string, + /** The accountID of the report owner */ + ownerAccountID: PropTypes.number, + /** List of primarylogins of participants of the report */ participants: PropTypes.arrayOf(PropTypes.string), + /** List of accountIDs of participants of the report */ + participantAccountIDs: PropTypes.arrayOf(PropTypes.number), + /** Linked policy's ID */ policyID: PropTypes.string, From d580e30df3eec599c4eda09e07dddcf0caa6f83a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 18:15:34 -0400 Subject: [PATCH 39/60] Fix lint issues --- src/libs/OptionsListUtils.js | 5 +++-- src/libs/PersonalDetailsUtils.js | 3 ++- src/pages/DetailsPage.js | 4 +--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 2f87b9400628..3f0f2faa6f97 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -167,8 +167,9 @@ function getAvatarsForLogins(logins, personalDetails) { /** * Returns avatar data for a list of user accountIDs * - * @param {*} accountIDs - * @param {*} personalDetails + * @param {Array} accountIDs + * @param {Object} personalDetails + * @returns {Object} */ function getAvatarsForAccountIDs(accountIDs, personalDetails) { return _.map(accountIDs, (accountID) => { diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index c0685c28120b..2282a1e91ae6 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -14,9 +14,10 @@ Onyx.connect({ * @param {Object} passedPersonalDetails * @param {Array} pathToDisplayName * @param {String} [defaultValue] optional default display name value + * @returns {String} */ function getDisplayNameOrDefault(passedPersonalDetails, pathToDisplayName, defaultValue) { - let displayName = lodashGet(passedPersonalDetails, pathToDisplayName); + const displayName = lodashGet(passedPersonalDetails, pathToDisplayName); return displayName || defaultValue || 'Hidden'; } diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index 63167fa53211..40df151dacf1 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -90,9 +90,7 @@ const getPhoneNumber = (details) => { class DetailsPage extends React.PureComponent { render() { const login = lodashGet(this.props.route.params, 'login', ''); - let details = _.find(this.props.personalDetails, (detail) => { - return detail.login === login.toLowerCase(); - }); + let details = _.find(this.props.personalDetails, (detail) => (detail.login === login.toLowerCase())); if (!details) { // TODO: these personal details aren't in my local test account but are in From 7f981d86cd54746c6528557e626c7325016c8aa9 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 18:24:20 -0400 Subject: [PATCH 40/60] Fix report action item avatars --- src/pages/home/report/ReportActionItemSingle.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 96fd6be6ad26..d1c0fe6684c8 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -67,8 +67,9 @@ const showUserDetails = (email) => { const ReportActionItemSingle = (props) => { const actorEmail = props.action.actorEmail.replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); - const {avatar, displayName, pendingFields} = props.personalDetails[actorEmail] || {}; - const avatarSource = UserUtils.getAvatar(avatar, actorEmail); + const actorAccountID = props.action.actorAccountID; + const {avatar, displayName, pendingFields} = props.personalDetails[actorAccountID] || {}; + const avatarSource = UserUtils.getAvatar(avatar, actorAccountID); // Since the display name for a report action message is delivered with the report history as an array of fragments // we'll need to take the displayName from personal details and have it be in the same format for now. Eventually, From 75e00300044396baa72135022447567b900df87a Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 18:25:16 -0400 Subject: [PATCH 41/60] Remove unused var --- src/components/withCurrentUserPersonalDetails.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/withCurrentUserPersonalDetails.js b/src/components/withCurrentUserPersonalDetails.js index cc0a5c1aab51..8225ba68ee56 100644 --- a/src/components/withCurrentUserPersonalDetails.js +++ b/src/components/withCurrentUserPersonalDetails.js @@ -22,7 +22,6 @@ export default function (WrappedComponent) { /** Session of the current user */ session: PropTypes.shape({ - email: PropTypes.string, accountID: PropTypes.number, }), }; @@ -30,15 +29,13 @@ export default function (WrappedComponent) { forwardedRef: undefined, personalDetails: {}, session: { - email: '', accountID: 0, }, }; const WithCurrentUserPersonalDetails = (props) => { - const currentUserEmail = props.session.email; const accountID = props.session.accountID; - const currentUserPersonalDetails = useMemo(() => ({...props.personalDetails[accountID], accountID}), [props.personalDetails, currentUserEmail, accountID]); + const currentUserPersonalDetails = useMemo(() => ({...props.personalDetails[accountID], accountID}), [props.personalDetails, accountID]); return ( Date: Wed, 7 Jun 2023 18:27:08 -0400 Subject: [PATCH 42/60] Fix race condition --- src/libs/SidebarUtils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index c75659343cfe..333ffd8e3ec0 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -82,6 +82,10 @@ let currentUserAccountID; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { + if (!val) { + return; + } + currentUserAccountID = val.accountID; }, }); From a1509a8dfaf4900d94ae6c05ae48aeb9bf56d3c4 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 18:45:45 -0400 Subject: [PATCH 43/60] Fix some report utils tests --- src/libs/ReportUtils.js | 5 ++--- tests/unit/ReportUtilsTest.js | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f8faabe57f24..c11ba60799f6 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2040,11 +2040,10 @@ function getMoneyRequestOptions(report, reportParticipants, betas) { const participants = _.filter(reportParticipants, (accountID) => currentUserPersonalDetails.accountID !== accountID); - // FAK, NEED ACCOUNT IDS FOR THESE - const hasExcludedIOUEmails = lodashIntersection(reportParticipants, CONST.EXPENSIFY_EMAILS).length > 0; + const hasExcludedIOUAccountIDs = lodashIntersection(reportParticipants, CONST.EXPENSIFY_ACCOUNT_IDS).length > 0; const hasMultipleParticipants = participants.length > 1; - if (hasExcludedIOUEmails || (participants.length === 0 && !report.isOwnPolicyExpenseChat) || !Permissions.canUseIOU(betas)) { + if (hasExcludedIOUAccountIDs || (participants.length === 0 && !report.isOwnPolicyExpenseChat) || !Permissions.canUseIOU(betas)) { return []; } diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index 652a88f7277f..7527c30bb385 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -353,20 +353,20 @@ describe('ReportUtils', () => { describe('return empty iou options if', () => { it('participants contains excluded iou emails', () => { - const allEmpty = _.every(CONST.EXPENSIFY_EMAILS, (email) => { - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, email], [CONST.BETAS.IOU]); + const allEmpty = _.every(CONST.EXPENSIFY_ACCOUNT_IDS, (accountID) => { + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserAccountID, accountID], [CONST.BETAS.IOU]); return moneyRequestOptions.length === 0; }); expect(allEmpty).toBe(true); }); it('no participants except self', () => { - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail], [CONST.BETAS.IOU]); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserAccountID], [CONST.BETAS.IOU]); expect(moneyRequestOptions.length).toBe(0); }); it('no iou permission', () => { - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], []); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserAccountID, ...participants], []); expect(moneyRequestOptions.length).toBe(0); }); }); @@ -380,7 +380,7 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), chatType, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants[0]], [CONST.BETAS.IOU]); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserAccountID, participants[0]], [CONST.BETAS.IOU]); return moneyRequestOptions.length === 1 && moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT); }, ); @@ -388,33 +388,33 @@ describe('ReportUtils', () => { }); it('has multiple participants exclude self', () => { - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, ...participants], [CONST.BETAS.IOU]); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserAccountID, ...participants], [CONST.BETAS.IOU]); expect(moneyRequestOptions.length).toBe(1); expect(moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)).toBe(true); }); - }); - describe('return only iou request option if', () => { it(' does not have iou send permission', () => { - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserEmail, participants], [CONST.BETAS.IOU]); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({}, [currentUserAccountID, ...participants], [CONST.BETAS.IOU]); expect(moneyRequestOptions.length).toBe(1); - expect(moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)).toBe(true); + expect(moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)).toBe(true); }); + }); + describe('return only iou request option if', () => { it('a policy expense chat', () => { const report = { ...LHNTestUtils.getFakeReport(), chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, isOwnPolicyExpenseChat: true, }; - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserEmail, participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, [currentUserAccountID, ...participants], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); expect(moneyRequestOptions.length).toBe(1); expect(moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)).toBe(true); }); }); it('return both iou send and request money in DM', () => { - const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({type: 'chat'}, [currentUserEmail, participants[0]], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); + const moneyRequestOptions = ReportUtils.getMoneyRequestOptions({type: 'chat'}, [currentUserAccountID, participants[0]], [CONST.BETAS.IOU, CONST.BETAS.IOU_SEND]); expect(moneyRequestOptions.length).toBe(2); expect(moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)).toBe(true); expect(moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.SEND)).toBe(true); From 10176c4559480a0ceb1cf7419673898ce4b06160 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 18:54:39 -0400 Subject: [PATCH 44/60] A bit more updates --- src/libs/IOUUtils.js | 2 ++ src/libs/ReportUtils.js | 1 + src/libs/actions/IOU.js | 5 +++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/IOUUtils.js b/src/libs/IOUUtils.js index 7224e63f31e0..5d722d4fd261 100644 --- a/src/libs/IOUUtils.js +++ b/src/libs/IOUUtils.js @@ -51,6 +51,8 @@ function updateIOUOwnerAndTotal(iouReport, actorEmail, amount, currency, type = if (iouReportUpdate.total < 0) { // The total sign has changed and hence we need to flip the manager and owner of the report. + iouReportUpdate.ownerAccountID = iouReport.managerID; + iouReportUpdate.managerID = iouReport.ownerAccountID; iouReportUpdate.ownerEmail = iouReport.managerEmail; iouReportUpdate.managerEmail = iouReport.ownerEmail; iouReportUpdate.total = -iouReportUpdate.total; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c11ba60799f6..daa8ff8553c3 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1359,6 +1359,7 @@ function buildOptimisticIOUReportAction(type, amount, currency, comment, partici if (type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT) { delete originalMessage.IOUReportID; originalMessage.participants = [currentUserEmail, ..._.pluck(participants, 'login')]; + originalMessage.participantAccountIDs = [currentUserAccountID, ..._.pluck(participants, 'accountID')]; } return { diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 936e3edaf170..2ecf93b893e9 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -262,6 +262,7 @@ function buildOnyxDataForMoneyRequest( */ function requestMoney(report, amount, currency, payeeEmail, participant, comment) { const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login); + const payerAccountID = participant.accountID; const isPolicyExpenseChat = participant.isPolicyExpenseChat || participant.isOwnPolicyExpenseChat; // STEP 1: Get existing chat report OR build a new optimistic one @@ -275,13 +276,13 @@ function requestMoney(report, amount, currency, payeeEmail, participant, comment } if (!chatReport) { - chatReport = ReportUtils.getChatByParticipants([payerEmail]); + chatReport = ReportUtils.getChatByParticipants([payerAccountID]); } // If we still don't have a report, it likely doens't exist and we need to build an optimistic one if (!chatReport) { isNewChatReport = true; - chatReport = ReportUtils.buildOptimisticChatReport([payerEmail]); + chatReport = ReportUtils.buildOptimisticChatReport([payerAccountID]); } // STEP 2: Get existing IOU report and update its total OR build a new optimistic one From c3497ff4733e22cdd21a4e5692306d4f59542b50 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 19:39:15 -0400 Subject: [PATCH 45/60] Fix a few more tests --- src/pages/reportPropTypes.js | 2 +- tests/unit/SidebarOrderTest.js | 24 ++++++++++++------------ tests/utils/LHNTestUtils.js | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/pages/reportPropTypes.js b/src/pages/reportPropTypes.js index 20d10758b030..4b50909032a1 100644 --- a/src/pages/reportPropTypes.js +++ b/src/pages/reportPropTypes.js @@ -57,7 +57,7 @@ export default PropTypes.shape({ ownerAccountID: PropTypes.number, /** List of primarylogins of participants of the report */ - participants: PropTypes.arrayOf(PropTypes.string), + participants: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])), /** List of accountIDs of participants of the report */ participantAccountIDs: PropTypes.arrayOf(PropTypes.number), diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index b2072f66ed03..3c3863c411b2 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -359,8 +359,8 @@ describe('Sidebar', () => { const iouReport = { ...LHNTestUtils.getFakeReport([7, 8]), type: CONST.REPORT.TYPE.IOU, - ownerEmail: 'email2@test.com', - managerEmail: 'email2@test.com', + ownerAccountID: 2, + managerID: 2, hasOutstandingIOU: true, total: 10000, currency: 'USD', @@ -368,7 +368,7 @@ describe('Sidebar', () => { }; report3.iouReportID = iouReport.reportID; const reportIDFromRoute = report2.reportID; - const currentlyLoggedInUserEmail = 'email9@test.com'; + const currentlyLoggedInUserAccountID = 9; LHNTestUtils.getDefaultRenderedSidebarLinks(reportIDFromRoute); return ( @@ -378,7 +378,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, - [ONYXKEYS.SESSION]: {email: currentlyLoggedInUserEmail}, + [ONYXKEYS.SESSION]: {accountID: currentlyLoggedInUserAccountID}, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, @@ -677,8 +677,8 @@ describe('Sidebar', () => { const iouReport1 = { ...LHNTestUtils.getFakeReport([7, 8]), type: CONST.REPORT.TYPE.IOU, - ownerEmail: 'email2@test.com', - managerEmail: 'email2@test.com', + ownerAccountID: 2, + managerID: 2, hasOutstandingIOU: true, total: 10000, currency: 'USD', @@ -687,8 +687,8 @@ describe('Sidebar', () => { const iouReport2 = { ...LHNTestUtils.getFakeReport([9, 10]), type: CONST.REPORT.TYPE.IOU, - ownerEmail: 'email2@test.com', - managerEmail: 'email2@test.com', + ownerAccountID: 2, + managerID: 2, hasOutstandingIOU: true, total: 10000, currency: 'USD', @@ -697,8 +697,8 @@ describe('Sidebar', () => { const iouReport3 = { ...LHNTestUtils.getFakeReport([11, 12]), type: CONST.REPORT.TYPE.IOU, - ownerEmail: 'email2@test.com', - managerEmail: 'email2@test.com', + ownerAccountID: 2, + managerID: 2, hasOutstandingIOU: true, total: 10000, currency: 'USD', @@ -709,7 +709,7 @@ describe('Sidebar', () => { report2.iouReportID = iouReport2.reportID; report3.iouReportID = iouReport3.reportID; - const currentlyLoggedInUserEmail = 'email13@test.com'; + const currentlyLoggedInUserAccountID = 13; LHNTestUtils.getDefaultRenderedSidebarLinks('0'); return ( waitForPromisesToResolve() @@ -718,7 +718,7 @@ describe('Sidebar', () => { Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, - [ONYXKEYS.SESSION]: {email: currentlyLoggedInUserEmail}, + [ONYXKEYS.SESSION]: {accountID: currentlyLoggedInUserAccountID}, [`${ONYXKEYS.COLLECTION.REPORT}${report1.reportID}`]: report1, [`${ONYXKEYS.COLLECTION.REPORT}${report2.reportID}`]: report2, [`${ONYXKEYS.COLLECTION.REPORT}${report3.reportID}`]: report3, diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index 601b14487b4c..9dd195c094b8 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -108,7 +108,7 @@ function getFakeReport(participants = [1, 2], millisecondsInThePast = 0, isUnrea reportName: 'Report', lastVisibleActionCreated, lastReadTime: isUnread ? DateUtils.subtractMillisecondsFromDateTime(lastVisibleActionCreated, 1) : lastVisibleActionCreated, - participants, + participantAccountIDs: participants, }; } From 651309a3a5475b47de7fd36c6051be3cb488f7b7 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 19:42:04 -0400 Subject: [PATCH 46/60] Fix sidebar filter tests --- tests/unit/SidebarFilterTest.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index f79b5e2f2ddd..927381177223 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -163,11 +163,11 @@ describe('Sidebar', () => { chatType: CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, }; const report2 = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']), + ...LHNTestUtils.getFakeReport([3, 4]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, }; const report3 = { - ...LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com']), + ...LHNTestUtils.getFakeReport([5, 6]), chatType: CONST.REPORT.CHAT_TYPE.DOMAIN_ALL, }; @@ -255,7 +255,7 @@ describe('Sidebar', () => { describe('all combinations of isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft', () => { // Given a report that is the active report and doesn't change - const report1 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']); + const report1 = LHNTestUtils.getFakeReport([3, 4]); // Given a free policy that doesn't change const policy = { @@ -348,9 +348,9 @@ describe('Sidebar', () => { it('hides unread chats', () => { // Given the sidebar is rendered in #focus mode (hides read chats) // with report 1 and 2 having unread actions - const report1 = LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 0, true); - const report2 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com'], 0, true); - const report3 = LHNTestUtils.getFakeReport(['email5@test.com', 'email6@test.com']); + const report1 = LHNTestUtils.getFakeReport([1, 2], 0, true); + const report2 = LHNTestUtils.getFakeReport([3, 4], 0, true); + const report3 = LHNTestUtils.getFakeReport([5, 6]); LHNTestUtils.getDefaultRenderedSidebarLinks(report1.reportID); return ( @@ -414,11 +414,11 @@ describe('Sidebar', () => { it('always shows pinned and draft chats', () => { // Given a draft report and a pinned report const draftReport = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), hasDraft: true, }; const pinnedReport = { - ...LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']), + ...LHNTestUtils.getFakeReport([3, 4]), isPinned: true, }; LHNTestUtils.getDefaultRenderedSidebarLinks(draftReport.reportID); @@ -449,18 +449,18 @@ describe('Sidebar', () => { it('archived rooms are displayed only when they have unread messages', () => { // Given an archived chat report, an archived default policy room, and an archived user created policy room const archivedReport = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }; const archivedPolicyRoomReport = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }; const archivedUserCreatedPolicyRoomReport = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, statusNum: CONST.REPORT.STATUS.CLOSED, stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, @@ -520,11 +520,11 @@ describe('Sidebar', () => { it('policy rooms are displayed only when they have unread messages', () => { // Given a default policy room and user created policy room const policyRoomReport = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, }; const userCreatedPolicyRoomReport = { - ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com']), + ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, }; LHNTestUtils.getDefaultRenderedSidebarLinks(); @@ -576,7 +576,7 @@ describe('Sidebar', () => { describe('all combinations of isArchived, isUserCreatedPolicyRoom, hasAddWorkspaceError, isUnread, isPinned, hasDraft', () => { // Given a report that is the active report and doesn't change - const report1 = LHNTestUtils.getFakeReport(['email3@test.com', 'email4@test.com']); + const report1 = LHNTestUtils.getFakeReport([3, 4]); // Given a free policy that doesn't change const policy = { From f141959411f4803fa898696b1300ec4461606e7b Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 16:47:23 -0700 Subject: [PATCH 47/60] Create util to get emails from policy members --- src/libs/PolicyUtils.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/libs/PolicyUtils.js b/src/libs/PolicyUtils.js index 601eaa1f128b..a0a9a4114a34 100644 --- a/src/libs/PolicyUtils.js +++ b/src/libs/PolicyUtils.js @@ -100,4 +100,24 @@ function isExpensifyTeam(email) { */ const isPolicyAdmin = (policy) => lodashGet(policy, 'role') === CONST.POLICY.ROLE.ADMIN; -export {hasPolicyMemberError, hasPolicyError, hasPolicyErrorFields, hasCustomUnitsError, getPolicyBrickRoadIndicatorStatus, shouldShowPolicy, isExpensifyTeam, isPolicyAdmin}; +/** + * @param {Object} policyMembers + * @param {Object} personalDetails + * @returns {Boolean} + * + * Create a list of member emails by filtering for members without errors, then mapping each policy member accountID to the login from the personalDetail object. + * TODO: Clean up uses of this function to work with accountIDs instead of emails. + * + * We filter clientMemberEmails to only pass members without errors. Otherwise, the members with errors would immediately be removed before the user has a chance to read the error. + */ +function getClientPolicyMemberEmails(policyMembers, personalDetails) { + return _.chain(policyMembers) + .filter((member) => _.isEmpty(member.errors)) + .keys() + .map((accountID) => personalDetails[accountID]) + .compact() + .map((personalDetail) => personalDetail.login) + .value(); +} + +export {hasPolicyMemberError, hasPolicyError, hasPolicyErrorFields, hasCustomUnitsError, getPolicyBrickRoadIndicatorStatus, shouldShowPolicy, isExpensifyTeam, isPolicyAdmin, getClientPolicyMemberEmails}; From 6dd4a1a1d86d015eb3317f97fcd530ae577dc591 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 16:47:51 -0700 Subject: [PATCH 48/60] Workspace invite with policy members by accountID --- src/pages/workspace/WorkspaceInvitePage.js | 25 +++++++++------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index f724485ed3ca..8cce7dddd0b0 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -24,6 +24,7 @@ import {withNetwork} from '../../components/OnyxProvider'; import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; import networkPropTypes from '../../components/networkPropTypes'; import ROUTES from '../../ROUTES'; +import * as PolicyUtils from '../../libs/PolicyUtils'; const personalDetailsPropTypes = PropTypes.shape({ /** The login of the person (either email or phone number) */ @@ -86,16 +87,14 @@ class WorkspaceInvitePage extends React.Component { componentDidMount() { this.clearErrors(); - - const clientPolicyMembers = _.keys(this.props.policyMemberList); - Policy.openWorkspaceInvitePage(this.props.route.params.policyID, clientPolicyMembers); + Policy.openWorkspaceInvitePage(this.props.route.params.policyID, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)); } componentDidUpdate(prevProps) { if (!_.isEqual(prevProps.personalDetails, this.props.personalDetails)) { this.updateOptionsWithSearchTerm(this.props.searchTerm); } - if (!_.isEqual(prevProps.policyMemberList, this.props.policyMemberList)) { + if (!_.isEqual(prevProps.policyMembers, this.props.policyMembers)) { this.updateOptionsWithSearchTerm(this.state.searchTerm); } @@ -104,20 +103,16 @@ class WorkspaceInvitePage extends React.Component { return; } - const clientPolicyMembers = _.keys(this.props.policyMemberList); - Policy.openWorkspaceInvitePage(this.props.route.params.policyID, clientPolicyMembers); + Policy.openWorkspaceInvitePage(this.props.route.params.policyID, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)); } getExcludedUsers() { - const policyMemberList = lodashGet(this.props, 'policyMemberList', {}); - const usersToExclude = _.filter( - _.keys(policyMemberList), - (policyMember) => - this.props.network.isOffline || - policyMemberList[policyMember].pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || - !_.isEmpty(policyMemberList[policyMember].errors), - ); - return [...CONST.EXPENSIFY_EMAILS, ...usersToExclude]; + const clientPolicyMemberEmails = PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails); + let usersToExclude = [...CONST.EXPENSIFY_EMAILS, ...clientPolicyMemberEmails]; + if (!this.props.network.isOffline) { + usersToExclude = _.filter(this.props.policyMembers, (policyMember) => policyMember.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(policyMember.errors)); + } + return usersToExclude; } /** From bde96829acaa2e8227a8d264c476378a78a9a971 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 16:51:06 -0700 Subject: [PATCH 49/60] Use new util to get policy member emails --- src/pages/workspace/WorkspaceMembersPage.js | 30 +++------------------ 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index eed37a42b349..c35843cb0287 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -100,17 +100,9 @@ class WorkspaceMembersPage extends React.Component { } if (prevProps.policyMembers !== this.props.policyMembers) { - this.setState((prevState) => { - const policyMemberEmails = _.chain(this.props.policyMembers) - .keys() - .map((accountID) => this.personalDetails[accountID]) - .compact() - .map((personalDetail) => personalDetail.login) - .value(); - return { - selectedEmployees: _.intersection(prevState.selectedEmployees, policyMemberEmails), - } - }); + this.setState((prevState) => ({ + selectedEmployees: _.intersection(prevState.selectedEmployees, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)), + })); } const isReconnecting = prevProps.network.isOffline && !this.props.network.isOffline; @@ -125,21 +117,7 @@ class WorkspaceMembersPage extends React.Component { * Get members for the current workspace */ getWorkspaceMembers() { - /** - * Create a list of member emails by filtering for members without errors, then mapping each policy member accountID to the login from the personalDetail object. - * TODO: Clean up OpenWorkspaceMembersPage so we can pass accountIDs instead of emails. - * - * We filter clientMemberEmails to only pass members without errors. Otherwise, the members with errors would immediately be removed before the user has a chance to read the error. - */ - const clientMemberEmails = _.chain(this.props.policyMembers) - .filter((member) => _.isEmpty(member.errors)) - .keys() - .map((accountID) => this.props.personalDetails[accountID]) - .compact() - .map((personalDetail) => personalDetail.login) - .value(); - - Policy.openWorkspaceMembersPage(this.props.route.params.policyID, clientMemberEmails); + Policy.openWorkspaceMembersPage(this.props.route.params.policyID, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)); } /** From fc38685bb42a7b4becefb85b7f1f1d5d4793d303 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 17:35:37 -0700 Subject: [PATCH 50/60] Map member emails to accountIDs for easy access --- src/libs/PolicyUtils.js | 23 ++++++++++++++------- src/pages/workspace/WorkspaceInvitePage.js | 10 +++++---- src/pages/workspace/WorkspaceMembersPage.js | 4 ++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/libs/PolicyUtils.js b/src/libs/PolicyUtils.js index a0a9a4114a34..86f5bc5e1458 100644 --- a/src/libs/PolicyUtils.js +++ b/src/libs/PolicyUtils.js @@ -103,21 +103,28 @@ const isPolicyAdmin = (policy) => lodashGet(policy, 'role') === CONST.POLICY.ROL /** * @param {Object} policyMembers * @param {Object} personalDetails - * @returns {Boolean} + * @returns {Object} * - * Create a list of member emails by filtering for members without errors, then mapping each policy member accountID to the login from the personalDetail object. + * Create an object mapping member emails to their accountIDs. Filter for members without errors, and get the login email from the personalDetail object using the accountID. * TODO: Clean up uses of this function to work with accountIDs instead of emails. * - * We filter clientMemberEmails to only pass members without errors. Otherwise, the members with errors would immediately be removed before the user has a chance to read the error. + * We only return members without errors. Otherwise, the members with errors would immediately be removed before the user has a chance to read the error. */ -function getClientPolicyMemberEmails(policyMembers, personalDetails) { +function getClientPolicyMemberEmailsToAccountIDs(policyMembers, personalDetails) { return _.chain(policyMembers) .filter((member) => _.isEmpty(member.errors)) .keys() - .map((accountID) => personalDetails[accountID]) - .compact() - .map((personalDetail) => personalDetail.login) + .reduce((result, accountID) => { + const personalDetail = personalDetails[accountID]; + if (personalDetail && personalDetail.login) { + return { + ...result, + [personalDetail.login]: accountID, + } + } + return result; + }, {}) .value(); } -export {hasPolicyMemberError, hasPolicyError, hasPolicyErrorFields, hasCustomUnitsError, getPolicyBrickRoadIndicatorStatus, shouldShowPolicy, isExpensifyTeam, isPolicyAdmin, getClientPolicyMemberEmails}; +export {hasPolicyMemberError, hasPolicyError, hasPolicyErrorFields, hasCustomUnitsError, getPolicyBrickRoadIndicatorStatus, shouldShowPolicy, isExpensifyTeam, isPolicyAdmin, getClientPolicyMemberEmailsToAccountIDs}; diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index 8cce7dddd0b0..b70fc5521df3 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -87,7 +87,8 @@ class WorkspaceInvitePage extends React.Component { componentDidMount() { this.clearErrors(); - Policy.openWorkspaceInvitePage(this.props.route.params.policyID, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)); + const policyMemberEmailsToAccountIDs = PolicyUtils.getClientPolicyMemberEmailsToAccountIDs(this.props.policyMembers, this.props.personalDetails); + Policy.openWorkspaceInvitePage(this.props.route.params.policyID, _.keys(policyMemberEmailsToAccountIDs)); } componentDidUpdate(prevProps) { @@ -103,12 +104,13 @@ class WorkspaceInvitePage extends React.Component { return; } - Policy.openWorkspaceInvitePage(this.props.route.params.policyID, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)); + const policyMemberEmailsToAccountIDs = PolicyUtils.getClientPolicyMemberEmailsToAccountIDs(this.props.policyMembers, this.props.personalDetails); + Policy.openWorkspaceInvitePage(this.props.route.params.policyID, _.keys(policyMemberEmailsToAccountIDs)); } getExcludedUsers() { - const clientPolicyMemberEmails = PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails); - let usersToExclude = [...CONST.EXPENSIFY_EMAILS, ...clientPolicyMemberEmails]; + const policyMemberEmailsToAccountIDs = PolicyUtils.getClientPolicyMemberEmailsToAccountIDs(this.props.policyMembers, this.props.personalDetails); + let usersToExclude = [...CONST.EXPENSIFY_EMAILS, ...(_.keys(policyMemberEmailsToAccountIDs))]; if (!this.props.network.isOffline) { usersToExclude = _.filter(this.props.policyMembers, (policyMember) => policyMember.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(policyMember.errors)); } diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index c35843cb0287..5d4cd5031bbc 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -101,7 +101,7 @@ class WorkspaceMembersPage extends React.Component { if (prevProps.policyMembers !== this.props.policyMembers) { this.setState((prevState) => ({ - selectedEmployees: _.intersection(prevState.selectedEmployees, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)), + selectedEmployees: _.intersection(prevState.selectedEmployees, _.keys(PolicyUtils.getClientPolicyMemberEmailsToAccountIDs(this.props.policyMembers, this.props.personalDetails))), })); } @@ -117,7 +117,7 @@ class WorkspaceMembersPage extends React.Component { * Get members for the current workspace */ getWorkspaceMembers() { - Policy.openWorkspaceMembersPage(this.props.route.params.policyID, PolicyUtils.getClientPolicyMemberEmails(this.props.policyMembers, this.props.personalDetails)); + Policy.openWorkspaceMembersPage(this.props.route.params.policyID, _.keys(PolicyUtils.getClientPolicyMemberEmailsToAccountIDs(this.props.policyMembers, this.props.personalDetails))); } /** From 8d9c4eb6ddefaa3723f15fb76de7ecedc08c23c8 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 17:36:42 -0700 Subject: [PATCH 51/60] Remove policy members optimistically by accountID --- src/libs/actions/Policy.js | 11 ++++++----- src/pages/workspace/WorkspaceMembersPage.js | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 66bcf0ba1392..9741cab260be 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -186,34 +186,35 @@ function hasActiveFreePolicy(policies) { * Remove the passed members from the policy employeeList * * @param {Array} members + * @param {Array} accountIDs * @param {String} policyID */ -function removeMembers(members, policyID) { +function removeMembers(members, accountIDs, policyID) { // In case user selects only themselves (admin), their email will be filtered out and the members // array passed will be empty, prevent the function from proceeding in that case as there is noone to remove if (members.length === 0) { return; } - const membersListKey = `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${policyID}`; + const membersListKey = `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`; const optimisticData = [ { onyxMethod: Onyx.METHOD.MERGE, key: membersListKey, - value: _.object(members, Array(members.length).fill({pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE})), + value: _.object(accountIDs, Array(members.length).fill({pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE})), }, ]; const successData = [ { onyxMethod: Onyx.METHOD.MERGE, key: membersListKey, - value: _.object(members, Array(members.length).fill(null)), + value: _.object(accountIDs, Array(members.length).fill(null)), }, ]; const failureData = [ { onyxMethod: Onyx.METHOD.MERGE, key: membersListKey, - value: _.object(members, Array(members.length).fill({errors: ErrorUtils.getMicroSecondOnyxError('workspace.people.error.genericRemove')})), + value: _.object(accountIDs, Array(members.length).fill({errors: ErrorUtils.getMicroSecondOnyxError('workspace.people.error.genericRemove')})), }, ]; API.write( diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 5d4cd5031bbc..d6eda058c7c8 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -180,7 +180,11 @@ class WorkspaceMembersPage extends React.Component { // Remove the admin from the list const membersToRemove = _.without(this.state.selectedEmployees, this.props.session.email); - Policy.removeMembers(membersToRemove, this.props.route.params.policyID); + + // It's a pain, but we need to map the emails back to accountIDs now so we can set optimistic data. TODO removeMembers using accountIDs only. + const emailsToAccountIDs = PolicyUtils.getClientPolicyMemberEmailsToAccountIDs(this.props.policyMembers, this.props.personalDetails); + const accountIDsToRemove = _.map(membersToRemove, (email) => emailsToAccountIDs[email]); + Policy.removeMembers(membersToRemove, accountIDsToRemove, this.props.route.params.policyID); this.setState({ selectedEmployees: [], isRemoveMembersConfirmModalVisible: false, From e55550d1bab7b32878410ef2ab692f8cfcb05da7 Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 17:47:34 -0700 Subject: [PATCH 52/60] policyMembers is actually allPolicyMembers --- src/components/AvatarWithIndicator.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js index bbbb4e8a9616..44036bad1669 100644 --- a/src/components/AvatarWithIndicator.js +++ b/src/components/AvatarWithIndicator.js @@ -29,7 +29,7 @@ const propTypes = { /* Onyx Props */ /** The employee list of all policies (coming from Onyx) */ - policyMembers: PropTypes.objectOf(policyMemberPropType), + allPolicyMembers: PropTypes.objectOf(PropTypes.objectOf(policyMemberPropType)), /** All the user's policies (from Onyx via withFullPolicy) */ policies: PropTypes.objectOf(policyPropTypes.policy), @@ -62,7 +62,7 @@ const propTypes = { const defaultProps = { tooltipText: '', reimbursementAccount: {}, - policyMembers: {}, + allPolicyMembers: {}, policies: {}, bankAccountList: {}, cardList: {}, @@ -75,7 +75,7 @@ const AvatarWithIndicator = (props) => { // If a policy was just deleted from Onyx, then Onyx will pass a null value to the props, and // those should be cleaned out before doing any error checking const cleanPolicies = _.pick(props.policies, (policy) => policy); - const cleanPolicyMembers = _.pick(props.policyMembers, (member) => member); + const cleanAllPolicyMembers = _.pick(props.allPolicyMembers, (policyMembers) => policyMembers); // All of the error & info-checking methods are put into an array. This is so that using _.some() will return // early as soon as the first error / info condition is returned. This makes the checks very efficient since @@ -85,7 +85,7 @@ const AvatarWithIndicator = (props) => { () => PaymentMethods.hasPaymentMethodError(props.bankAccountList, props.cardList), () => _.some(cleanPolicies, PolicyUtils.hasPolicyError), () => _.some(cleanPolicies, PolicyUtils.hasCustomUnitsError), - () => _.some(cleanPolicyMembers, PolicyUtils.hasPolicyMemberError), + () => _.some(cleanAllPolicyMembers, PolicyUtils.hasPolicyMemberError), () => !_.isEmpty(props.reimbursementAccount.errors), () => UserUtils.hasLoginListError(props.loginList), @@ -114,7 +114,7 @@ AvatarWithIndicator.propTypes = propTypes; AvatarWithIndicator.displayName = 'AvatarWithIndicator'; export default withOnyx({ - policyMembers: { + allPolicyMembers: { key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, }, policies: { From bac0a50882749f11da4b55a0e296ec400370291f Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 17:55:49 -0700 Subject: [PATCH 53/60] Rename to allPolicyMembers and update prop type --- src/pages/settings/InitialSettingsPage.js | 8 ++++---- src/pages/workspace/WorkspacesListPage.js | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js index 84c3d7fbec0a..83e8f2d8abde 100755 --- a/src/pages/settings/InitialSettingsPage.js +++ b/src/pages/settings/InitialSettingsPage.js @@ -100,7 +100,7 @@ const propTypes = { }), /** Members keyed by accountID for all policies */ - policyMembers: PropTypes.objectOf(policyMemberPropType), + allPolicyMembers: PropTypes.objectOf(PropTypes.objectOf(policyMemberPropType)), ...withLocalizePropTypes, ...withCurrentUserPersonalDetailsPropTypes, @@ -118,7 +118,7 @@ const defaultProps = { bankAccountList: {}, cardList: {}, loginList: {}, - policyMembers: {}, + allPolicyMembers: {}, ...withCurrentUserPersonalDetailsDefaultProps, }; @@ -170,7 +170,7 @@ class InitialSettingsPage extends React.Component { !_.isEmpty(this.props.reimbursementAccount.errors) || _.chain(this.props.policies) .filter((policy) => policy && policy.type === CONST.POLICY.TYPE.FREE && policy.role === CONST.POLICY.ROLE.ADMIN) - .some((policy) => PolicyUtils.hasPolicyError(policy) || PolicyUtils.getPolicyBrickRoadIndicatorStatus(policy, this.props.policyMembers)) + .some((policy) => PolicyUtils.hasPolicyError(policy) || PolicyUtils.getPolicyBrickRoadIndicatorStatus(policy, this.props.allPolicyMembers)) .value() ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : null; @@ -393,7 +393,7 @@ export default compose( policies: { key: ONYXKEYS.COLLECTION.POLICY, }, - policyMembers: { + allPolicyMembers: { key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, }, userWallet: { diff --git a/src/pages/workspace/WorkspacesListPage.js b/src/pages/workspace/WorkspacesListPage.js index 14affcd5303b..d6c8cdb53a06 100755 --- a/src/pages/workspace/WorkspacesListPage.js +++ b/src/pages/workspace/WorkspacesListPage.js @@ -54,8 +54,8 @@ const propTypes = { /** Bank account attached to free plan */ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes, - /** List of policy members */ - policyMembers: PropTypes.objectOf(policyMemberPropType), + /** A collection of objects for all policies which key policy member objects by accountIDs */ + allPolicyMembers: PropTypes.objectOf(PropTypes.objectOf(policyMemberPropType)), /** The user's wallet account */ userWallet: PropTypes.shape({ @@ -71,7 +71,7 @@ const propTypes = { const defaultProps = { policies: {}, - policyMembers: {}, + allPolicyMembers: {}, reimbursementAccount: {}, userWallet: { currentBalance: 0, @@ -130,7 +130,7 @@ class WorkspacesListPage extends Component { action: () => Navigation.navigate(ROUTES.getWorkspaceInitialRoute(policy.id)), iconFill: themeColors.textLight, fallbackIcon: Expensicons.FallbackWorkspaceAvatar, - brickRoadIndicator: reimbursementAccountBrickRoadIndicator || PolicyUtils.getPolicyBrickRoadIndicatorStatus(policy, this.props.policyMembers), + brickRoadIndicator: reimbursementAccountBrickRoadIndicator || PolicyUtils.getPolicyBrickRoadIndicatorStatus(policy, this.props.allPolicyMembers), pendingAction: policy.pendingAction, errors: policy.errors, dismissError: () => dismissWorkspaceError(policy.id, policy.pendingAction), @@ -216,7 +216,7 @@ export default compose( policies: { key: ONYXKEYS.COLLECTION.POLICY, }, - policyMembers: { + allPolicyMembers: { key: ONYXKEYS.COLLECTION.POLICY_MEMBERS, }, reimbursementAccount: { From ed057ccb61ad078685b328ca4ef7dd8d0f34320e Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Wed, 7 Jun 2023 18:21:55 -0700 Subject: [PATCH 54/60] WIP invitedEmailsToAccountIDs --- src/libs/actions/Policy.js | 30 +++++++++++-------- .../workspace/WorkspaceInviteMessagePage.js | 12 ++++---- src/pages/workspace/WorkspaceInvitePage.js | 4 ++- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 9741cab260be..69c492880a98 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -231,11 +231,11 @@ function removeMembers(members, accountIDs, policyID) { * Optimistically create a chat for each member of the workspace, creates both optimistic and success data for onyx. * * @param {String} policyID - * @param {Array} members + * @param {Object} invitedEmailsToAccountIDs * @param {Array} betas * @returns {Object} - object with onyxSuccessData, onyxOptimisticData, and optimisticReportIDs (map login to reportID) */ -function createPolicyExpenseChats(policyID, members, betas) { +function createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, betas) { const workspaceMembersChats = { onyxSuccessData: [], onyxOptimisticData: [], @@ -324,17 +324,17 @@ function createPolicyExpenseChats(policyID, members, betas) { /** * Adds members to the specified workspace/policyID * - * @param {Array} memberLogins + * @param {Object} invitedEmailsToAccountIDs * @param {String} welcomeNote * @param {String} policyID * @param {Array} betas */ -function addMembersToWorkspace(memberLogins, welcomeNote, policyID, betas) { +function addMembersToWorkspace(invitedEmailsToAccountIDs, welcomeNote, policyID, betas) { const membersListKey = `${ONYXKEYS.COLLECTION.POLICY_MEMBER_LIST}${policyID}`; - const logins = _.map(memberLogins, (memberLogin) => OptionsListUtils.addSMSDomainIfPhoneNumber(memberLogin)); + const accountIDs = _.values(invitedEmailsToAccountIDs); // create onyx data for policy expense chats for each new member - const membersChats = createPolicyExpenseChats(policyID, logins, betas); + const membersChats = createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, betas); const optimisticData = [ { @@ -342,7 +342,7 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID, betas) { key: membersListKey, // Convert to object with each key containing {pendingAction: ‘add’} - value: _.object(logins, Array(logins.length).fill({pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD})), + value: _.object(accountIDs, Array(accountIDs.length).fill({pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD})), }, ...membersChats.onyxOptimisticData, ]; @@ -354,7 +354,7 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID, betas) { // Convert to object with each key clearing pendingAction. We don’t // need to remove the members since that will be handled by onClose of OfflineWithFeedback. - value: _.object(logins, Array(logins.length).fill({pendingAction: null, errors: null})), + value: _.object(accountIDs, Array(accountIDs.length).fill({pendingAction: null, errors: null})), }, ...membersChats.onyxSuccessData, ]; @@ -367,8 +367,8 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID, betas) { // Convert to object with each key containing the error. We don’t // need to remove the members since that is handled by onClose of OfflineWithFeedback. value: _.object( - logins, - Array(logins.length).fill({ + accountIDs, + Array(accountIDs.length).fill({ errors: ErrorUtils.getMicroSecondOnyxError('workspace.people.error.genericAdd'), }), ), @@ -376,6 +376,7 @@ function addMembersToWorkspace(memberLogins, welcomeNote, policyID, betas) { ...membersChats.onyxFailureData, ]; + const logins = _.map(_.keys(invitedEmailsToAccountIDs), (memberLogin) => OptionsListUtils.addSMSDomainIfPhoneNumber(memberLogin)); API.write( 'AddMembersToWorkspace', { @@ -1080,8 +1081,13 @@ function openWorkspaceInvitePage(policyID, clientMemberEmails) { }); } -function setWorkspaceInviteMembersDraft(policyID, memberEmails) { - Onyx.set(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${policyID}`, memberEmails); + +/** + * @param {String} policyID + * @param {Object} invitedEmailsToAccountIDs + */ +function setWorkspaceInviteMembersDraft(policyID, invitedEmailsToAccountIDs) { + Onyx.set(`${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${policyID}`, invitedEmailsToAccountIDs); } export { diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.js b/src/pages/workspace/WorkspaceInviteMessagePage.js index 327e387c9d2e..f44a4c3c4870 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.js +++ b/src/pages/workspace/WorkspaceInviteMessagePage.js @@ -44,7 +44,7 @@ const propTypes = { /** Beta features list */ betas: PropTypes.arrayOf(PropTypes.string), - invitedMembersDraft: PropTypes.arrayOf(PropTypes.string), + invitedEmailsToAccountIDsDraft: PropTypes.objectOf(PropTypes.number), /** URL Route params */ route: PropTypes.shape({ @@ -63,7 +63,7 @@ const defaultProps = { ...policyDefaultProps, personalDetails: {}, betas: [], - invitedMembersDraft: [], + invitedEmailsToAccountIDsDraft: {}, }; class WorkspaceInviteMessagePage extends React.Component { @@ -115,7 +115,7 @@ class WorkspaceInviteMessagePage extends React.Component { } sendInvitation() { - Policy.addMembersToWorkspace(this.props.invitedMembersDraft, this.state.welcomeNote, this.props.route.params.policyID, this.props.betas); + Policy.addMembersToWorkspace(this.props.invitedEmailsToAccountIDsDraft, this.state.welcomeNote, this.props.route.params.policyID, this.props.betas); Policy.setWorkspaceInviteMembersDraft(this.props.route.params.policyID, []); Navigation.navigate(ROUTES.getWorkspaceMembersRoute(this.props.route.params.policyID)); } @@ -131,7 +131,7 @@ class WorkspaceInviteMessagePage extends React.Component { validate() { const errorFields = {}; - if (_.isEmpty(this.props.invitedMembersDraft)) { + if (_.isEmpty(this.props.invitedEmailsToAccountIDsDraft)) { errorFields.welcomeMessage = this.props.translate('workspace.inviteMessage.inviteNoMembersError'); } return errorFields; @@ -178,7 +178,7 @@ class WorkspaceInviteMessagePage extends React.Component { @@ -221,7 +221,7 @@ export default compose( betas: { key: ONYXKEYS.BETAS, }, - invitedMembersDraft: { + invitedEmailsToAccountIDsDraft: { key: ({route}) => `${ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT}${route.params.policyID.toString()}`, }, }), diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index b70fc5521df3..db95e1ed7702 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -227,7 +227,9 @@ class WorkspaceInvitePage extends React.Component { .compact() .uniq() .value(); - Policy.setWorkspaceInviteMembersDraft(this.props.route.params.policyID, filteredLogins); + const policyMemberEmailsToAccountIDs = PolicyUtils.getClientPolicyMemberEmailsToAccountIDs(this.props.policyMembers, this.props.personalDetails); + const invitedEmailsToAccountIDs = _.reduce(filteredLogins, (result, login) => ({...result, [login]: policyMemberEmailsToAccountIDs[login]}), {}); + Policy.setWorkspaceInviteMembersDraft(this.props.route.params.policyID, invitedEmailsToAccountIDs); Navigation.navigate(ROUTES.getWorkspaceInviteMessageRoute(this.props.route.params.policyID)); } From 1e974911d2d6ed4dc3820e61708d6fd46f86fac2 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 7 Jun 2023 21:58:36 -0400 Subject: [PATCH 55/60] Many iOU updates --- src/components/ReportActionItem/IOUPreview.js | 6 +++ src/libs/OptionsListUtils.js | 4 +- src/libs/ReportUtils.js | 12 ++++-- src/libs/actions/IOU.js | 38 ++++++++++--------- src/pages/NewChatPage.js | 2 +- src/pages/home/report/ReportActionCompose.js | 5 +-- src/pages/iou/MoneyRequestModal.js | 10 ++--- .../MoneyRequestParticipantsSelector.js | 2 +- .../MoneyRequestParticipantsSplitSelector.js | 8 ++-- src/pages/tasks/TaskAssigneeSelectorModal.js | 4 +- tests/actions/IOUTest.js | 11 +++--- tests/unit/IOUUtilsTest.js | 4 +- 12 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 1b61046aaf1c..f9ff201de152 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -59,9 +59,15 @@ const propTypes = { /** Email address of the manager in this iou report */ managerEmail: PropTypes.string, + /** Account ID of the manager in this iou report */ + managerID: PropTypes.number, + /** Email address of the creator of this iou report */ ownerEmail: PropTypes.string, + /** Account ID of the creator of this iou report */ + ownerAccountID: PropTypes.number, + /** Outstanding amount in cents of this transaction */ total: PropTypes.number, diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 3f0f2faa6f97..f3282460d9b7 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -237,13 +237,14 @@ function getParticipantsOptions(report, personalDetails) { return _.map(getPersonalDetailsForAccountIDs(participants, personalDetails), (details) => ({ keyForList: details.login, login: details.login, + accountID: details.accountID, text: details.displayName, firstName: lodashGet(details, 'firstName', ''), lastName: lodashGet(details, 'lastName', ''), alternateText: Str.isSMSLogin(details.login || '') ? LocalePhoneNumber.formatPhoneNumber(details.login) : details.login, icons: [ { - source: UserUtils.getAvatar(details.avatar, details.login), + source: UserUtils.getAvatar(details.avatar, details.accountID), name: details.login, type: CONST.ICON_TYPE_AVATAR, }, @@ -849,6 +850,7 @@ function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail, amount ], descriptiveText: amountText, login: personalDetail.login, + accountID: personalDetail.accountID, }; } diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index daa8ff8553c3..b2e1d1b535ce 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1202,7 +1202,7 @@ function buildOptimisticTaskCommentReportAction(taskReportID, taskTitle, taskAss * Builds an optimistic IOU report with a randomly generated reportID * * @param {String} payeeEmail - Email of the person generating the IOU. - * @param {String} payerEmail - Email of the other person participating in the IOU. + * @param {Number} payerAccountID - AccountID of the other person participating in the IOU. * @param {Number} total - IOU amount in the smallest unit of the currency. * @param {String} chatReportID - Report ID of the chat where the IOU is. * @param {String} currency - IOU currency. @@ -1210,8 +1210,10 @@ function buildOptimisticTaskCommentReportAction(taskReportID, taskTitle, taskAss * * @returns {Object} */ -function buildOptimisticIOUReport(payeeEmail, payerEmail, total, chatReportID, currency, isSendingMoney = false) { +function buildOptimisticIOUReport(payeeEmail, payerAccountID, total, chatReportID, currency, isSendingMoney = false) { const formattedTotal = CurrencyUtils.convertToDisplayString(total, currency); + // TODO: REPLACE ME + const payerEmail = 'REPLACE ME WITH PERSONAL DETAILS'; return { // If we're sending money, hasOutstandingIOU should be false hasOutstandingIOU: !isSendingMoney, @@ -1219,8 +1221,9 @@ function buildOptimisticIOUReport(payeeEmail, payerEmail, total, chatReportID, c cachedTotal: formattedTotal, chatReportID, currency, - managerEmail: payerEmail, + managerID: payerAccountID, ownerEmail: payeeEmail, + // ownerAccountID: 0, reportID: generateReportID(), state: CONST.REPORT.STATE.SUBMITTED, stateNum: isSendingMoney ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.PROCESSING, @@ -1483,6 +1486,7 @@ function buildOptimisticChatReport( isOwnPolicyExpenseChat, isPinned: reportName === CONST.REPORT.WORKSPACE_CHAT_ROOMS.ADMINS, lastActorEmail: '', + lastActorAccountID: 0, lastMessageHtml: '', lastMessageText: null, lastReadTime: currentTime, @@ -1490,9 +1494,11 @@ function buildOptimisticChatReport( notificationPreference, oldPolicyName, ownerEmail: ownerEmail || CONST.REPORT.OWNER_EMAIL_FAKE, + // ownerAccountID: ownerAccountID || 0, parentReportActionID, parentReportID, participants: participantList, + participantAccountIDs: participantList, policyID, reportID: generateReportID(), reportName, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 2ecf93b893e9..c4a3e36859ba 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -301,7 +301,7 @@ function requestMoney(report, amount, currency, payeeEmail, participant, comment } else { iouReport = isPolicyExpenseChat ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID, payeeEmail, amount, currency) - : ReportUtils.buildOptimisticIOUReport(payeeEmail, payerEmail, amount, chatReport.reportID, currency); + : ReportUtils.buildOptimisticIOUReport(payeeEmail, payerAccountID, amount, chatReport.reportID, currency); } // STEP 3: Build optimistic transaction @@ -391,9 +391,10 @@ function requestMoney(report, amount, currency, payeeEmail, participant, comment function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, existingGroupChatReportID = '') { const currentUserEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); const participantLogins = _.map(participants, (participant) => OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase()); + const participantAccountIDs = _.map(participants, (participant) => participant.accountID); const existingGroupChatReport = existingGroupChatReportID ? chatReports[`${ONYXKEYS.COLLECTION.REPORT}${existingGroupChatReportID}`] - : ReportUtils.getChatByParticipants(participantLogins); + : ReportUtils.getChatByParticipants(participantAccountIDs); const groupChatReport = existingGroupChatReport || ReportUtils.buildOptimisticChatReport(participantLogins); // ReportID is -2 (aka "deleted") on the group transaction: https://github.com/Expensify/Auth/blob/3fa2698654cd4fbc30f9de38acfca3fbeb7842e4/auth/command/SplitTransaction.cpp#L24-L27 @@ -503,11 +504,12 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment // Loop through participants creating individual chats, iouReports and reportActionIDs as needed const splitAmount = IOUUtils.calculateAmount(participants.length, amount, false); - const splits = [{email: currentUserEmail, amount: IOUUtils.calculateAmount(participants.length, amount, true)}]; + const splits = [{email: currentUserEmail, accountID: currentUserAccountID, amount: IOUUtils.calculateAmount(participants.length, amount, true)}]; const hasMultipleParticipants = participants.length > 1; _.each(participants, (participant) => { const email = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase(); + const accountID = participant.accountID; if (email === currentUserEmail) { return; } @@ -516,7 +518,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment // If we only have one participant and the request was initiated from the global create menu, i.e. !existingGroupChatReportID, the oneOnOneChatReport is the groupChatReport let oneOnOneChatReport; let isNewOneOnOneChatReport = false; - oneOnOneChatReport = !hasMultipleParticipants && !existingGroupChatReportID ? groupChatReport : ReportUtils.getChatByParticipants([email]); + oneOnOneChatReport = !hasMultipleParticipants && !existingGroupChatReportID ? groupChatReport : ReportUtils.getChatByParticipants([accountID]); if (!oneOnOneChatReport) { isNewOneOnOneChatReport = true; @@ -529,7 +531,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment if (!isNewOneOnOneIOUReport) { oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReports[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`], currentUserEmail, splitAmount, currency); } else { - oneOnOneIOUReport = ReportUtils.buildOptimisticIOUReport(currentUserEmail, email, splitAmount, oneOnOneChatReport.reportID, currency); + oneOnOneIOUReport = ReportUtils.buildOptimisticIOUReport(currentUserEmail, accountID, splitAmount, oneOnOneChatReport.reportID, currency); } // STEP 3: Build optimistic transaction @@ -816,12 +818,13 @@ function buildPayPalPaymentUrl(amount, submitterPayPalMeAddress, currency) { * @param {String} currency * @param {String} comment * @param {String} paymentMethodType - * @param {String} managerEmail - Email of the person sending the money + * @param {String} managerID - Account ID of the person sending the money * @param {Object} recipient - The user receiving the money * @returns {Object} */ -function getSendMoneyParams(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) { +function getSendMoneyParams(report, amount, currency, comment, paymentMethodType, managerID, recipient) { const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login); + const recipientAccountID = recipient.accountID; const newIOUReportDetails = JSON.stringify({ amount, currency, @@ -839,7 +842,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType chatReport = ReportUtils.buildOptimisticChatReport([recipientEmail]); isNewChat = true; } - const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerEmail, amount, chatReport.reportID, currency, true); + const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerID, amount, chatReport.reportID, currency, true); const optimisticTransaction = TransactionUtils.buildOptimisticTransaction(amount * 100, currency, optimisticIOUReport.reportID, comment); const optimisticTransactionData = { @@ -1103,11 +1106,11 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho * @param {Number} amount * @param {String} currency * @param {String} comment - * @param {String} managerEmail - Email of the person sending the money + * @param {String} managerID - Account ID of the person sending the money * @param {Object} recipient - The user receiving the money */ -function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, recipient) { - const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerEmail, recipient); +function sendMoneyElsewhere(report, amount, currency, comment, managerID, recipient) { + const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerID, recipient); API.write('SendMoneyElsewhere', params, {optimisticData, successData, failureData}); @@ -1119,11 +1122,11 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec * @param {Number} amount * @param {String} currency * @param {String} comment - * @param {String} managerEmail - Email of the person sending the money + * @param {String} managerID - Account ID of the person sending the money * @param {Object} recipient - The user receiving the money */ -function sendMoneyWithWallet(report, amount, currency, comment, managerEmail, recipient) { - const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.EXPENSIFY, managerEmail, recipient); +function sendMoneyWithWallet(report, amount, currency, comment, managerID, recipient) { + const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.EXPENSIFY, managerID, recipient); API.write('SendMoneyWithWallet', params, {optimisticData, successData, failureData}); @@ -1135,11 +1138,11 @@ function sendMoneyWithWallet(report, amount, currency, comment, managerEmail, re * @param {Number} amount * @param {String} currency * @param {String} comment - * @param {String} managerEmail - Email of the person sending the money + * @param {String} managerID - Account ID of the person sending the money * @param {Object} recipient - The user receiving the money */ -function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, recipient) { - const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME, managerEmail, recipient); +function sendMoneyViaPaypal(report, amount, currency, comment, managerID, recipient) { + const {params, optimisticData, successData, failureData} = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME, managerID, recipient); API.write('SendMoneyViaPaypal', params, {optimisticData, successData, failureData}); @@ -1157,6 +1160,7 @@ function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, rec function payMoneyRequest(paymentType, chatReport, iouReport) { const recipient = { login: iouReport.ownerEmail, + accountID: iouReport.ownerAccountID, payPalMeAddress: iouReport.submitterPayPalMeAddress, }; const {params, optimisticData, successData, failureData} = getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentType); diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js index 374c99780b50..98522e691d55 100755 --- a/src/pages/NewChatPage.js +++ b/src/pages/NewChatPage.js @@ -51,7 +51,7 @@ class NewChatPage extends Component { this.createChat = this.createChat.bind(this); this.createGroup = this.createGroup.bind(this); this.updateOptionsWithSearchTerm = this.updateOptionsWithSearchTerm.bind(this); - this.excludedGroupEmails = _.without(CONST.EXPENSIFY_EMAILS, CONST.EMAIL.CONCIERGE); + this.excludedGroupEmails = _.without(CONST.EXPENSIFY_ACCOUNT_IDS, CONST.ACCOUNT_ID.CONCIERGE); const {recentReports, personalDetails, userToInvite} = OptionsListUtils.getNewChatOptions( props.reports, diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 480615e76dc1..fac82dfa5e8b 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -428,7 +428,7 @@ class ReportActionCompose extends React.Component { // We only prevent the task option from showing if it's a DM and the other user is an Expensify default email if ( !Permissions.canUseTasks(this.props.betas) || - (lodashGet(this.props.report, 'participants', []).length === 1 && _.some(reportParticipants, (email) => _.contains(CONST.EXPENSIFY_EMAILS, email))) + (lodashGet(this.props.report, 'participantAccountIDs', []).length === 1 && _.some(reportParticipants, (accountID) => _.contains(CONST.EXPENSIFY_ACCOUNT_IDS, accountID))) ) { return []; } @@ -905,8 +905,7 @@ class ReportActionCompose extends React.Component { render() { const reportParticipants = _.without(lodashGet(this.props.report, 'participantAccountIDs', []), this.props.currentUserPersonalDetails.accountID); - // TODO: ACCOUNT IDS!!! - const participantsWithoutExpensifyAccountIDs = _.difference(reportParticipants, CONST.EXPENSIFY_EMAILS); + const participantsWithoutExpensifyAccountIDs = _.difference(reportParticipants, CONST.EXPENSIFY_ACCOUNT_IDS); const reportRecipient = this.props.personalDetails[participantsWithoutExpensifyAccountIDs[0]]; const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(this.props.personalDetails, this.props.report, this.props.currentUserPersonalDetails.login) && !this.props.isComposerFullSize; diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 249d1f48e9b3..d3058dcc1798 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -249,20 +249,20 @@ const MoneyRequestModal = (props) => { const participant = selectedOptions[0]; if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { - IOU.sendMoneyElsewhere(props.report, amount, currency, trimmedComment, props.currentUserPersonalDetails.login, participant); + IOU.sendMoneyElsewhere(props.report, amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant); return; } if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { - IOU.sendMoneyViaPaypal(props.report, amount, currency, trimmedComment, props.currentUserPersonalDetails.login, participant); + IOU.sendMoneyViaPaypal(props.report, amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant); return; } if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { - IOU.sendMoneyWithWallet(props.report, amount, currency, trimmedComment, props.currentUserPersonalDetails.login, participant); + IOU.sendMoneyWithWallet(props.report, amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant); } }, - [amount, props.iou.comment, selectedOptions, props.currentUserPersonalDetails.login, props.iou.selectedCurrencyCode, props.report], + [amount, props.iou.comment, selectedOptions, props.currentUserPersonalDetails.accountID, props.iou.selectedCurrencyCode, props.report], ); /** @@ -372,7 +372,7 @@ const MoneyRequestModal = (props) => { ReportScrollManager.scrollToBottom(); }} hasMultipleParticipants={props.hasMultipleParticipants} - participants={_.filter(selectedOptions, (email) => props.currentUserPersonalDetails.login !== email.login)} + participants={_.filter(selectedOptions, (option) => props.currentUserPersonalDetails.accountID !== option.accountID)} iouAmount={amount} iouType={props.iouType} // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 49f569925692..1849329a4f1d 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -79,7 +79,7 @@ class MoneyRequestParticipantsSelector extends Component { this.props.betas, searchTerm, [], - CONST.EXPENSIFY_EMAILS, + CONST.EXPENSIFY_ACCOUNT_IDS, // If we are using this component in the "Request money" flow then we pass the includeOwnedWorkspaceChats argument so that the current user // sees the option to request money from their admin on their own Workspace Chat. diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js index e0b77787462c..2582bacd6506 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSplitSelector.js @@ -29,6 +29,7 @@ const propTypes = { participants: PropTypes.arrayOf( PropTypes.shape({ login: PropTypes.string.isRequired, + accountID: PropTypes.number.isRequired, alternateText: PropTypes.string, hasDraftComment: PropTypes.bool, icons: PropTypes.arrayOf(avatarPropTypes), @@ -73,7 +74,7 @@ class MoneyRequestParticipantsSplitSelector extends Component { props.betas, '', props.participants, - CONST.EXPENSIFY_EMAILS, + CONST.EXPENSIFY_ACCOUNT_IDS, ); this.state = { @@ -148,7 +149,7 @@ class MoneyRequestParticipantsSplitSelector extends Component { this.props.betas, searchTerm, this.props.participants, - CONST.EXPENSIFY_EMAILS, + CONST.EXPENSIFY_ACCOUNT_IDS, ); this.setState({ searchTerm, @@ -189,8 +190,7 @@ class MoneyRequestParticipantsSplitSelector extends Component { this.props.betas, isOptionInList ? prevState.searchTerm : '', newSelectedOptions, - // TODO: need to update :D - CONST.EXPENSIFY_EMAILS, + CONST.EXPENSIFY_ACCOUNT_IDS, ); return { recentReports, diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 76a4e86e0a67..86ed5da35de4 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -78,7 +78,7 @@ const TaskAssigneeSelectorModal = (props) => { const [filteredCurrentUserOption, setFilteredCurrentUserOption] = useState(null); useEffect(() => { - const results = OptionsListUtils.getNewChatOptions(props.reports, props.personalDetails, props.betas, '', [], CONST.EXPENSIFY_EMAILS, false); + const results = OptionsListUtils.getNewChatOptions(props.reports, props.personalDetails, props.betas, '', [], CONST.EXPENSIFY_ACCOUNT_IDS, false); setFilteredRecentReports(results.recentReports); setFilteredPersonalDetails(results.personalDetails); @@ -93,7 +93,7 @@ const TaskAssigneeSelectorModal = (props) => { props.betas, searchValue.trim(), [], - CONST.EXPENSIFY_EMAILS, + CONST.EXPENSIFY_ACCOUNT_IDS, false, ); diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 0eaaba65b3ca..374d99629129 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -364,9 +364,7 @@ describe('actions/IOU', () => { reportID: iouReportID, chatReportID, type: CONST.REPORT.TYPE.IOU, - ownerEmail: RORY_EMAIL, ownerAccountID: RORY_ACCOUNT_ID, - managerEmail: CARLOS_EMAIL, managerID: CARLOS_ACCOUNT_ID, currency: CONST.CURRENCY.USD, total: existingTransaction.amount, @@ -778,6 +776,7 @@ describe('actions/IOU', () => { describe('split bill', () => { it('creates and updates new chats and IOUs as needed', () => { + jest.setTimeout(10 * 1000); /* * Given that: * - Rory and Carlos have chatted before @@ -828,9 +827,7 @@ describe('actions/IOU', () => { reportID: julesIOUReportID, chatReportID: julesChatReport.reportID, type: CONST.REPORT.TYPE.IOU, - ownerEmail: RORY_EMAIL, ownerAccountID: RORY_ACCOUNT_ID, - managerEmail: JULES_EMAIL, managerID: JULES_ACCOUNT_ID, currency: CONST.CURRENCY.USD, total: julesExistingTransaction.amount, @@ -895,7 +892,9 @@ describe('actions/IOU', () => { fetch.pause(); IOU.splitBill( // TODO: Migrate after the backend accepts accountIDs - _.map([CARLOS_EMAIL, JULES_EMAIL, VIT_EMAIL], (email) => ({login: email})), + _.map([ + [CARLOS_EMAIL, CARLOS_ACCOUNT_ID], [JULES_EMAIL, JULES_ACCOUNT_ID], [VIT_EMAIL, VIT_ACCOUNT_ID] + ], ([email, accountID]) => ({login: email, accountID})), RORY_EMAIL, amount, comment, @@ -913,6 +912,8 @@ describe('actions/IOU', () => { Onyx.disconnect(connectionID); // There should now be 7 reports + // FAIL IS HERE ============================================================================= + console.log('ALLREPORTS', allReports); expect(_.size(allReports)).toBe(7); // 1. The chat report with Rory + Carlos diff --git a/tests/unit/IOUUtilsTest.js b/tests/unit/IOUUtilsTest.js index 2f6901ca47a2..d9db649bb8d7 100644 --- a/tests/unit/IOUUtilsTest.js +++ b/tests/unit/IOUUtilsTest.js @@ -10,7 +10,9 @@ import currencyList from './currencyList.json'; let iouReport; let reportActions; const ownerEmail = 'owner@iou.com'; +const ownerAccountID = 5; const managerEmail = 'manager@iou.com'; +const managerID = 10; function createIOUReportAction(type, amount, currency, isOffline = false, IOUTransactionID = NumberUtils.rand64()) { const moneyRequestAction = ReportUtils.buildOptimisticIOUReportAction(type, amount, currency, 'Test comment', [managerEmail], IOUTransactionID, '', iouReport.reportID); @@ -52,7 +54,7 @@ describe('IOUUtils', () => { const amount = 1000; const currency = 'USD'; - iouReport = ReportUtils.buildOptimisticIOUReport(ownerEmail, managerEmail, amount, chatReportID, currency); + iouReport = ReportUtils.buildOptimisticIOUReport(ownerEmail, managerID, amount, chatReportID, currency); // The starting point of all tests is the IOUReport containing a single non-pending transaction in USD // All requests in the tests are assumed to be online, unless isOffline is specified From fe3d585f89cc2e3a54218a64366bd37e6e89910f Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 8 Jun 2023 10:41:34 -0400 Subject: [PATCH 56/60] More iOU updates --- src/libs/IOUUtils.js | 6 +++--- src/libs/ReportUtils.js | 13 ++++++++----- src/libs/actions/IOU.js | 31 ++++++++++++++++-------------- src/pages/iou/MoneyRequestModal.js | 6 +++--- tests/actions/IOUTest.js | 11 ++++++----- tests/unit/IOUUtilsTest.js | 2 +- 6 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/libs/IOUUtils.js b/src/libs/IOUUtils.js index 5d722d4fd261..7f7782dee996 100644 --- a/src/libs/IOUUtils.js +++ b/src/libs/IOUUtils.js @@ -29,13 +29,13 @@ function calculateAmount(numberOfParticipants, total, isDefaultUser = false) { * If user1 requests $17 from user2, then we have: {ownerEmail: user1, managerEmail: user2, total: $7 (still a positive amount, but now owed to user1)} * * @param {Object} iouReport - * @param {String} actorEmail + * @param {Number} actorAccountID * @param {Number} amount * @param {String} currency * @param {String} type * @returns {Object} */ -function updateIOUOwnerAndTotal(iouReport, actorEmail, amount, currency, type = CONST.IOU.REPORT_ACTION_TYPE.CREATE) { +function updateIOUOwnerAndTotal(iouReport, actorAccountID, amount, currency, type = CONST.IOU.REPORT_ACTION_TYPE.CREATE) { if (currency !== iouReport.currency) { return iouReport; } @@ -43,7 +43,7 @@ function updateIOUOwnerAndTotal(iouReport, actorEmail, amount, currency, type = // Make a copy so we don't mutate the original object const iouReportUpdate = {...iouReport}; - if (actorEmail === iouReport.ownerEmail) { + if (actorAccountID === iouReport.ownerAccountID) { iouReportUpdate.total += type === CONST.IOU.REPORT_ACTION_TYPE.DELETE ? -amount : amount; } else { iouReportUpdate.total += type === CONST.IOU.REPORT_ACTION_TYPE.DELETE ? amount : -amount; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 4321708c2941..bd76e55a1ccf 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1202,6 +1202,7 @@ function buildOptimisticTaskCommentReportAction(taskReportID, taskTitle, taskAss * Builds an optimistic IOU report with a randomly generated reportID * * @param {String} payeeEmail - Email of the person generating the IOU. + * @param {Number} payeeAccountID - AccountID of the person generating the IOU. * @param {Number} payerAccountID - AccountID of the other person participating in the IOU. * @param {Number} total - IOU amount in the smallest unit of the currency. * @param {String} chatReportID - Report ID of the chat where the IOU is. @@ -1210,10 +1211,10 @@ function buildOptimisticTaskCommentReportAction(taskReportID, taskTitle, taskAss * * @returns {Object} */ -function buildOptimisticIOUReport(payeeEmail, payerAccountID, total, chatReportID, currency, isSendingMoney = false) { +function buildOptimisticIOUReport(payeeEmail, payeeAccountID, payerAccountID, total, chatReportID, currency, isSendingMoney = false) { const formattedTotal = CurrencyUtils.convertToDisplayString(total, currency); - // TODO: REPLACE ME - const payerEmail = 'REPLACE ME WITH PERSONAL DETAILS'; + // TODO: GET ME + const payerEmail = 'GET ME WITH PERSONAL DETAILS'; return { // If we're sending money, hasOutstandingIOU should be false hasOutstandingIOU: !isSendingMoney, @@ -1223,7 +1224,7 @@ function buildOptimisticIOUReport(payeeEmail, payerAccountID, total, chatReportI currency, managerID: payerAccountID, ownerEmail: payeeEmail, - // ownerAccountID: 0, + ownerAccountID: payeeAccountID, reportID: generateReportID(), state: CONST.REPORT.STATE.SUBMITTED, stateNum: isSendingMoney ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.PROCESSING, @@ -1240,12 +1241,13 @@ function buildOptimisticIOUReport(payeeEmail, payerAccountID, total, chatReportI * @param {String} chatReportID - Report ID of the PolicyExpenseChat where the Expense Report is * @param {String} policyID - The policy ID of the PolicyExpenseChat * @param {String} payeeEmail - Email of the employee (payee) + * @param {Number} payeeAccountID - AccountID of the employee (payee) * @param {Number} total - Amount in cents * @param {String} currency * * @returns {Object} */ -function buildOptimisticExpenseReport(chatReportID, policyID, payeeEmail, total, currency) { +function buildOptimisticExpenseReport(chatReportID, policyID, payeeEmail, payeeAccountID, total, currency) { // The amount for Expense reports are stored as negative value in the database const storedTotal = total * -1; const policyName = getPolicyName(allReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]); @@ -1260,6 +1262,7 @@ function buildOptimisticExpenseReport(chatReportID, policyID, payeeEmail, total, policyID, type: CONST.REPORT.TYPE.EXPENSE, ownerEmail: payeeEmail, + ownerAccountID: payeeAccountID, hasOutstandingIOU: true, currency: outputCurrency, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index c4a3e36859ba..103140556748 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -257,10 +257,11 @@ function buildOnyxDataForMoneyRequest( * @param {Number} amount - always in the smallest unit of the currency * @param {String} currency * @param {String} payeeEmail + * @param {Number} payeeAccountID * @param {Object} participant * @param {String} comment */ -function requestMoney(report, amount, currency, payeeEmail, participant, comment) { +function requestMoney(report, amount, currency, payeeEmail, payeeAccountID, participant, comment) { const payerEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login); const payerAccountID = participant.accountID; const isPolicyExpenseChat = participant.isPolicyExpenseChat || participant.isOwnPolicyExpenseChat; @@ -296,12 +297,12 @@ function requestMoney(report, amount, currency, payeeEmail, participant, comment // Because of the Expense reports are stored as negative values, we substract the total from the amount iouReport.total -= amount; } else { - iouReport = IOUUtils.updateIOUOwnerAndTotal(iouReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`], payeeEmail, amount, currency); + iouReport = IOUUtils.updateIOUOwnerAndTotal(iouReports[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`], payeeAccountID, amount, currency); } } else { iouReport = isPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID, payeeEmail, amount, currency) - : ReportUtils.buildOptimisticIOUReport(payeeEmail, payerAccountID, amount, chatReport.reportID, currency); + ? ReportUtils.buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID, payeeEmail, payeeAccountID, amount, currency) + : ReportUtils.buildOptimisticIOUReport(payeeEmail, payeeAccountID, payerAccountID, amount, chatReport.reportID, currency); } // STEP 3: Build optimistic transaction @@ -381,6 +382,7 @@ function requestMoney(report, amount, currency, payeeEmail, participant, comment * ] * @param {Array} participants * @param {String} currentUserLogin + * @param {Number} currentUserAccountID * @param {Number} amount - always in the smallest unit of the currency * @param {String} comment * @param {String} currency @@ -388,7 +390,7 @@ function requestMoney(report, amount, currency, payeeEmail, participant, comment * * @return {Object} */ -function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, existingGroupChatReportID = '') { +function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingGroupChatReportID = '') { const currentUserEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); const participantLogins = _.map(participants, (participant) => OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase()); const participantAccountIDs = _.map(participants, (participant) => participant.accountID); @@ -529,9 +531,9 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment const isNewOneOnOneIOUReport = !oneOnOneChatReport.iouReportID; let oneOnOneIOUReport; if (!isNewOneOnOneIOUReport) { - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReports[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`], currentUserEmail, splitAmount, currency); + oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReports[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`], currentUserAccountID, splitAmount, currency); } else { - oneOnOneIOUReport = ReportUtils.buildOptimisticIOUReport(currentUserEmail, accountID, splitAmount, oneOnOneChatReport.reportID, currency); + oneOnOneIOUReport = ReportUtils.buildOptimisticIOUReport(currentUserEmail, currentUserAccountID, accountID, splitAmount, oneOnOneChatReport.reportID, currency); } // STEP 3: Build optimistic transaction @@ -651,12 +653,13 @@ function splitBill(participants, currentUserLogin, amount, comment, currency, ex /** * @param {Array} participants * @param {String} currentUserLogin + * @param {Number} currentUserAccountID * @param {Number} amount - always in smallest currency unit * @param {String} comment * @param {String} currency */ -function splitBillAndOpenReport(participants, currentUserLogin, amount, comment, currency) { - const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency); +function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency) { + const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency); API.write( 'SplitBillAndOpenReport', @@ -699,7 +702,7 @@ function deleteMoneyRequest(chatReportID, iouReportID, moneyRequestAction, shoul iouReportID, ); - const currentUserEmail = optimisticIOUAction.actorEmail; + const currentUserAccountID = optimisticIOUAction.actorAccountID; let updatedIOUReport = {}; if (ReportUtils.isExpenseReport(iouReportID)) { updatedIOUReport = {...iouReport}; @@ -707,7 +710,7 @@ function deleteMoneyRequest(chatReportID, iouReportID, moneyRequestAction, shoul // Because of the Expense reports are stored as negative values, we add the total from the amount updatedIOUReport.total += amount; } else { - updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, currentUserEmail, amount, moneyRequestAction.originalMessage.currency, CONST.IOU.REPORT_ACTION_TYPE.DELETE); + updatedIOUReport = IOUUtils.updateIOUOwnerAndTotal(iouReport, currentUserAccountID, amount, moneyRequestAction.originalMessage.currency, CONST.IOU.REPORT_ACTION_TYPE.DELETE); } updatedIOUReport.lastMessageText = optimisticIOUAction.message[0].text; updatedIOUReport.lastMessageHtml = optimisticIOUAction.message[0].html; @@ -836,13 +839,13 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType let chatReport = report.reportID ? report : null; let isNewChat = false; if (!chatReport) { - chatReport = ReportUtils.getChatByParticipants([recipientEmail]); + chatReport = ReportUtils.getChatByParticipants([recipientAccountID]); } if (!chatReport) { - chatReport = ReportUtils.buildOptimisticChatReport([recipientEmail]); + chatReport = ReportUtils.buildOptimisticChatReport([recipientAccountID]); isNewChat = true; } - const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerID, amount, chatReport.reportID, currency, true); + const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, recipientAccountID, managerID, amount, chatReport.reportID, currency, true); const optimisticTransaction = TransactionUtils.buildOptimisticTransaction(amount * 100, currency, optimisticIOUReport.reportID, comment); const optimisticTransactionData = { diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index d3058dcc1798..9eb264b5ecd3 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -276,17 +276,17 @@ const MoneyRequestModal = (props) => { // IOUs created from a group report will have a reportID param in the route. // Since the user is already viewing the report, we don't need to navigate them to the report if (props.hasMultipleParticipants && CONST.REGEX.NUMBER.test(reportID)) { - IOU.splitBill(selectedParticipants, props.currentUserPersonalDetails.login, amount, trimmedComment, props.iou.selectedCurrencyCode, reportID); + IOU.splitBill(selectedParticipants, props.currentUserPersonalDetails.login, props.currentUserPersonalDetails.accountID, amount, trimmedComment, props.iou.selectedCurrencyCode, reportID); return; } // If the request is created from the global create menu, we also navigate the user to the group report if (props.hasMultipleParticipants) { - IOU.splitBillAndOpenReport(selectedParticipants, props.currentUserPersonalDetails.login, amount, trimmedComment, props.iou.selectedCurrencyCode); + IOU.splitBillAndOpenReport(selectedParticipants, props.currentUserPersonalDetails.login, props.currentUserPersonalDetails.accountID, amount, trimmedComment, props.iou.selectedCurrencyCode); return; } - IOU.requestMoney(props.report, amount, props.iou.selectedCurrencyCode, props.currentUserPersonalDetails.login, selectedParticipants[0], trimmedComment); + IOU.requestMoney(props.report, amount, props.iou.selectedCurrencyCode, props.currentUserPersonalDetails.login, props.currentUserPersonalDetails.accountID, selectedParticipants[0], trimmedComment); }, [amount, props.iou.comment, props.currentUserPersonalDetails.login, props.hasMultipleParticipants, props.iou.selectedCurrencyCode, props.report, props.route], ); diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 374d99629129..d5bd6b60d205 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -40,7 +40,7 @@ describe('actions/IOU', () => { let iouAction; let transactionID; fetch.pause(); - IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); + IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve() .then( () => @@ -205,7 +205,7 @@ describe('actions/IOU', () => { }), ) .then(() => { - IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); + IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve(); }) .then( @@ -398,7 +398,7 @@ describe('actions/IOU', () => { ) .then(() => Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${existingTransaction.transactionID}`, existingTransaction)) .then(() => { - IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); + IOU.requestMoney(chatReport, amount, CONST.CURRENCY.USD, RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve(); }) .then( @@ -530,7 +530,7 @@ describe('actions/IOU', () => { let iouAction; let transactionID; fetch.pause(); - IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); + IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return ( waitForPromisesToResolve() .then( @@ -896,6 +896,7 @@ describe('actions/IOU', () => { [CARLOS_EMAIL, CARLOS_ACCOUNT_ID], [JULES_EMAIL, JULES_ACCOUNT_ID], [VIT_EMAIL, VIT_ACCOUNT_ID] ], ([email, accountID]) => ({login: email, accountID})), RORY_EMAIL, + RORY_ACCOUNT_ID, amount, comment, CONST.CURRENCY.USD, @@ -1164,7 +1165,7 @@ describe('actions/IOU', () => { let createIOUAction; let payIOUAction; let transaction; - IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); + IOU.requestMoney({}, amount, CONST.CURRENCY.USD, RORY_EMAIL, RORY_ACCOUNT_ID, {login: CARLOS_EMAIL, accountID: CARLOS_ACCOUNT_ID}, comment); return waitForPromisesToResolve() .then( () => diff --git a/tests/unit/IOUUtilsTest.js b/tests/unit/IOUUtilsTest.js index d9db649bb8d7..d080a1e900c9 100644 --- a/tests/unit/IOUUtilsTest.js +++ b/tests/unit/IOUUtilsTest.js @@ -54,7 +54,7 @@ describe('IOUUtils', () => { const amount = 1000; const currency = 'USD'; - iouReport = ReportUtils.buildOptimisticIOUReport(ownerEmail, managerID, amount, chatReportID, currency); + iouReport = ReportUtils.buildOptimisticIOUReport(ownerEmail, ownerAccountID, managerID, amount, chatReportID, currency); // The starting point of all tests is the IOUReport containing a single non-pending transaction in USD // All requests in the tests are assumed to be online, unless isOffline is specified From 37548867e5912322aac18a0ed4ab2e875d351ee8 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 8 Jun 2023 10:45:58 -0400 Subject: [PATCH 57/60] A bit of cleanup --- src/pages/home/report/ReportActionItemSingle.js | 4 ++-- tests/actions/IOUTest.js | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 3eba4c6e74d9..0b2c56a275c8 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -89,7 +89,7 @@ const ReportActionItemSingle = (props) => { style={[styles.alignSelfStart, styles.mr3]} onPressIn={ControlSelection.block} onPressOut={ControlSelection.unblock} - onPress={() => showUserDetails(accountID)} + onPress={() => showUserDetails(actorAccountID)} > {props.shouldShowSubscriptAvatar ? ( @@ -119,7 +119,7 @@ const ReportActionItemSingle = (props) => { style={[styles.flexShrink1, styles.mr1]} onPressIn={ControlSelection.block} onPressOut={ControlSelection.unblock} - onPress={() => showUserDetails(accountID)} + onPress={() => showUserDetails(actorAccountID)} > {_.map(personArray, (fragment, index) => ( { Onyx.disconnect(connectionID); // There should now be 7 reports - // FAIL IS HERE ============================================================================= - console.log('ALLREPORTS', allReports); expect(_.size(allReports)).toBe(7); // 1. The chat report with Rory + Carlos From 7fe728c8af73b2549ff99375b83ee8b01ee0fdaa Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 8 Jun 2023 11:53:49 -0400 Subject: [PATCH 58/60] Many task edits --- .../ReportActionItem/MoneyRequestAction.js | 6 +-- src/libs/ReportUtils.js | 28 ++++++++----- src/libs/actions/IOU.js | 12 +++--- src/libs/actions/Policy.js | 9 +++-- src/libs/actions/Report.js | 11 +++-- src/libs/actions/Task.js | 40 ++++++++++--------- src/pages/DetailsPage.js | 2 +- src/pages/NewChatPage.js | 10 +++-- src/pages/ProfilePage.js | 2 +- src/pages/SearchPage.js | 3 +- src/pages/tasks/NewTaskPage.js | 2 +- src/pages/tasks/TaskAssigneeSelectorModal.js | 10 +++-- src/pages/tasks/TaskDescriptionPage.js | 2 +- src/pages/tasks/TaskTitlePage.js | 2 +- tests/actions/IOUTest.js | 2 + 15 files changed, 81 insertions(+), 60 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js index 1f11eeae780e..90833843139e 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.js @@ -103,10 +103,9 @@ const MoneyRequestAction = (props) => { // If the childReportID is not present, we need to create a new thread const childReportID = lodashGet(props.action, 'childReportID', '0'); if (childReportID === '0') { - const participants = _.uniq([props.session.email, props.action.actorEmail]); - const formattedUserLogins = _.map(participants, (login) => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); + const participantAccountIDs = _.uniq([props.session.accountID, props.action.actorAccountID]); const thread = ReportUtils.buildOptimisticChatReport( - formattedUserLogins, + participantAccountIDs, props.translate(ReportActionsUtils.isSentMoneyReportAction(props.action) ? 'iou.threadSentMoneyReportName' : 'iou.threadRequestReportName', { formattedAmount: ReportActionsUtils.getFormattedAmount(props.action), comment: props.action.originalMessage.comment, @@ -114,6 +113,7 @@ const MoneyRequestAction = (props) => { '', CONST.POLICY.OWNER_EMAIL_FAKE, CONST.POLICY.OWNER_EMAIL_FAKE, + 0, false, '', undefined, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index bd76e55a1ccf..986746ed8c23 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1172,12 +1172,12 @@ function buildOptimisticAddCommentReportAction(text, file) { * Builds an optimistic reportAction for the parent report when a task is created * @param {String} taskReportID - Report ID of the task * @param {String} taskTitle - Title of the task - * @param {String} taskAssignee - Email of the person assigned to the task + * @param {String} taskAssigneeAccountID - AccountID of the person assigned to the task * @param {String} text - Text of the comment * @param {String} parentReportID - Report ID of the parent report * @returns {Object} */ -function buildOptimisticTaskCommentReportAction(taskReportID, taskTitle, taskAssignee, text, parentReportID) { +function buildOptimisticTaskCommentReportAction(taskReportID, taskTitle, taskAssigneeAccountID, text, parentReportID) { const reportAction = buildOptimisticAddCommentReportAction(text); reportAction.reportAction.message[0].taskReportID = taskReportID; @@ -1192,6 +1192,7 @@ function buildOptimisticTaskCommentReportAction(taskReportID, taskTitle, taskAss reportAction.reportAction.childType = CONST.REPORT.TYPE.TASK; reportAction.reportAction.childReportName = taskTitle; reportAction.reportAction.childManagerEmail = taskAssignee; + reportAction.reportAction.childManagerAccountID = taskAssigneeAccountID; reportAction.reportAction.childStatusNum = CONST.REPORT.STATUS.OPEN; reportAction.reportAction.childStateNum = CONST.REPORT.STATE_NUM.OPEN; @@ -1455,11 +1456,12 @@ function buildOptimisticTaskReportAction(taskReportID, actionName, message = '') /** * Builds an optimistic chat report with a randomly generated reportID and as much information as we currently have * - * @param {Array} participantList + * @param {Array} participantList Array of participant accountIDs * @param {String} reportName * @param {String} chatType * @param {String} policyID * @param {String} ownerEmail + * @param {Number} ownerAccountID * @param {Boolean} isOwnPolicyExpenseChat * @param {String} oldPolicyName * @param {String} visibility @@ -1474,6 +1476,7 @@ function buildOptimisticChatReport( chatType = '', policyID = CONST.POLICY.OWNER_EMAIL_FAKE, ownerEmail = CONST.REPORT.OWNER_EMAIL_FAKE, + ownerAccountID = 0, isOwnPolicyExpenseChat = false, oldPolicyName = '', visibility = undefined, @@ -1497,10 +1500,9 @@ function buildOptimisticChatReport( notificationPreference, oldPolicyName, ownerEmail: ownerEmail || CONST.REPORT.OWNER_EMAIL_FAKE, - // ownerAccountID: ownerAccountID || 0, + ownerAccountID: ownerAccountID || 0, parentReportActionID, parentReportID, - participants: participantList, participantAccountIDs: participantList, policyID, reportID: generateReportID(), @@ -1641,11 +1643,12 @@ function buildOptimisticClosedReportAction(ownerEmail, policyName, reason = CONS */ function buildOptimisticWorkspaceChats(policyID, policyName) { const announceChatData = buildOptimisticChatReport( - [currentUserEmail], + [currentUserAccountID], CONST.REPORT.WORKSPACE_CHAT_ROOMS.ANNOUNCE, CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID, null, + 0, false, policyName, null, @@ -1659,14 +1662,14 @@ function buildOptimisticWorkspaceChats(policyID, policyName) { [announceCreatedAction.reportActionID]: announceCreatedAction, }; - const adminsChatData = buildOptimisticChatReport([currentUserEmail], CONST.REPORT.WORKSPACE_CHAT_ROOMS.ADMINS, CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, policyID, null, false, policyName); + const adminsChatData = buildOptimisticChatReport([currentUserAccountID], CONST.REPORT.WORKSPACE_CHAT_ROOMS.ADMINS, CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, policyID, null, 0, false, policyName); const adminsChatReportID = adminsChatData.reportID; const adminsCreatedAction = buildOptimisticCreatedReportAction(adminsChatData.ownerEmail); const adminsReportActionData = { [adminsCreatedAction.reportActionID]: adminsCreatedAction, }; - const expenseChatData = buildOptimisticChatReport([currentUserEmail], '', CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, policyID, currentUserEmail, true, policyName); + const expenseChatData = buildOptimisticChatReport([currentUserAccountID], '', CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, policyID, currentUserEmail, currentUserAccountID, true, policyName); const expenseChatReportID = expenseChatData.reportID; const expenseReportCreatedAction = buildOptimisticCreatedReportAction(expenseChatData.ownerEmail); const expenseReportActionData = { @@ -1693,7 +1696,8 @@ function buildOptimisticWorkspaceChats(policyID, policyName) { * Builds an optimistic Task Report with a randomly generated reportID * * @param {String} ownerEmail - Email of the person generating the Task. - * @param {String} assignee - Email of the other person participating in the Task. + * @param {Number} ownerAccountID - Account ID of the person generating the Task. + * @param {String} assigneeAccountID - AccountID of the other person participating in the Task. * @param {String} parentReportID - Report ID of the chat where the Task is. * @param {String} title - Task title. * @param {String} description - Task description. @@ -1701,13 +1705,15 @@ function buildOptimisticWorkspaceChats(policyID, policyName) { * @returns {Object} */ -function buildOptimisticTaskReport(ownerEmail, assignee = null, parentReportID, title, description) { +function buildOptimisticTaskReport(ownerEmail, ownerAccountID, assigneeAccountID = 0, parentReportID, title, description) { return { reportID: generateReportID(), reportName: title, description, ownerEmail, - managerEmail: assignee, + ownerAccountID, + // managerEmail: assignee, + managerID: assigneeAccountID, type: CONST.REPORT.TYPE.TASK, parentReportID, stateNum: CONST.REPORT.STATE_NUM.OPEN, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 103140556748..4fe53aedb646 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -392,12 +392,11 @@ function requestMoney(report, amount, currency, payeeEmail, payeeAccountID, part */ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingGroupChatReportID = '') { const currentUserEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin); - const participantLogins = _.map(participants, (participant) => OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase()); const participantAccountIDs = _.map(participants, (participant) => participant.accountID); const existingGroupChatReport = existingGroupChatReportID ? chatReports[`${ONYXKEYS.COLLECTION.REPORT}${existingGroupChatReportID}`] : ReportUtils.getChatByParticipants(participantAccountIDs); - const groupChatReport = existingGroupChatReport || ReportUtils.buildOptimisticChatReport(participantLogins); + const groupChatReport = existingGroupChatReport || ReportUtils.buildOptimisticChatReport(participantAccountIDs); // ReportID is -2 (aka "deleted") on the group transaction: https://github.com/Expensify/Auth/blob/3fa2698654cd4fbc30f9de38acfca3fbeb7842e4/auth/command/SplitTransaction.cpp#L24-L27 const formattedParticipants = Localize.arrayToString([currentUserLogin, ..._.map(participants, (participant) => participant.login)]); @@ -524,7 +523,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco if (!oneOnOneChatReport) { isNewOneOnOneChatReport = true; - oneOnOneChatReport = ReportUtils.buildOptimisticChatReport([email]); + oneOnOneChatReport = ReportUtils.buildOptimisticChatReport([accountID]); } // STEP 2: Get existing IOU report and update its total OR build a new optimistic one @@ -588,6 +587,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco const splitData = { email, + accountID, amount: splitAmount, iouReportID: oneOnOneIOUReport.reportID, chatReportID: oneOnOneChatReport.reportID, @@ -624,13 +624,14 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco /** * @param {Array} participants * @param {String} currentUserLogin + * @param {Number} currentUserAccountID * @param {Number} amount - always in smallest currency unit * @param {String} comment * @param {String} currency * @param {String} existingGroupChatReportID */ -function splitBill(participants, currentUserLogin, amount, comment, currency, existingGroupChatReportID = '') { - const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, amount, comment, currency, existingGroupChatReportID); +function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingGroupChatReportID = '') { + const {groupData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingGroupChatReportID); API.write( 'SplitBill', @@ -832,6 +833,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType amount, currency, requestorEmail: recipientEmail, + requestorAccountID: recipientAccountID, comment, idempotencyKey: Str.guid(), }); diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 69c492880a98..833b7359acb6 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -51,10 +51,12 @@ Onyx.connect({ }); let sessionEmail = ''; +let sessionAccountID = 0; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { sessionEmail = lodashGet(val, 'email', ''); + sessionAccountID = lodashGet(val, 'accountID', 0); }, }); @@ -248,11 +250,12 @@ function createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, betas) { return workspaceMembersChats; } - _.each(members, (login) => { - const oldChat = ReportUtils.getChatByParticipantsAndPolicy([sessionEmail, login], policyID); + _.each(invitedEmailsToAccountIDs, (accountID, login) => { + const oldChat = ReportUtils.getChatByParticipantsAndPolicy([sessionAccountID, accountID], policyID); // If the chat already exists, we don't want to create a new one - just make sure it's not archived if (oldChat) { + // TODO: figure out if we need to use accountID keys here workspaceMembersChats.reportCreationData[login] = { reportID: oldChat.reportID, }; @@ -266,7 +269,7 @@ function createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, betas) { }); return; } - const optimisticReport = ReportUtils.buildOptimisticChatReport([sessionEmail, login], undefined, CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, policyID, login); + const optimisticReport = ReportUtils.buildOptimisticChatReport([sessionAccountID, accountID], undefined, CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, policyID, login, accountID); const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(optimisticReport.ownerEmail); workspaceMembersChats.reportCreationData[login] = { diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index fa4bd6b89bfa..152a56f56853 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -448,14 +448,13 @@ function openReport(reportID, participantList = [], newReportObject = {}, parent /** * This will find an existing chat, or create a new one if none exists, for the given user or set of users. It will then navigate to this chat. * - * @param {Array} userLogins list of user logins. + * @param {Array} userAccountIDs list of user accountIDs. */ -function navigateToAndOpenReport(userLogins) { - const formattedUserLogins = _.map(userLogins, (login) => OptionsListUtils.addSMSDomainIfPhoneNumber(login).toLowerCase()); +function navigateToAndOpenReport(userAccountIDs) { let newChat = {}; - const chat = ReportUtils.getChatByParticipants(formattedUserLogins); + const chat = ReportUtils.getChatByParticipants(userAccountIDs); if (!chat) { - newChat = ReportUtils.buildOptimisticChatReport(formattedUserLogins); + newChat = ReportUtils.buildOptimisticChatReport(userAccountIDs); } const reportID = chat ? chat.reportID : newChat.reportID; @@ -1150,7 +1149,7 @@ function navigateToConciergeChat() { // we need to ensure that the server data has been successfully pulled Welcome.serverDataIsReadyPromise().then(() => { // If we don't have a chat with Concierge then create it - navigateToAndOpenReport([CONST.EMAIL.CONCIERGE]); + navigateToAndOpenReport([CONST.ACCOUNT_ID.CONCIERGE]); }); } else { Navigation.navigate(ROUTES.getReportRoute(conciergeChatReportID)); diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 0b3204ee53da..9f3abcfcf5f4 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -23,29 +23,30 @@ function clearOutTaskInfo() { * Function title is createTask for consistency with the rest of the actions * and also because we can create a task without assigning it to anyone * @param {String} currentUserEmail + * @param {Number} currentUserAccountID * @param {String} parentReportID * @param {String} title * @param {String} description - * @param {String} assignee + * @param {Number} assigneeAccountID * */ -function createTaskAndNavigate(currentUserEmail, parentReportID, title, description, assignee = '') { +function createTaskAndNavigate(currentUserEmail, currentUserAccountID, parentReportID, title, description, assigneeAccountID = 0) { // Create the task report - const optimisticTaskReport = ReportUtils.buildOptimisticTaskReport(currentUserEmail, assignee, parentReportID, title, description); + const optimisticTaskReport = ReportUtils.buildOptimisticTaskReport(currentUserEmail, currentUserAccountID, assigneeAccountID, parentReportID, title, description); // Grab the assigneeChatReportID if there is an assignee and if it's not the same as the parentReportID // then we create an optimistic add comment report action on the assignee's chat to notify them of the task - const assigneeChatReportID = lodashGet(ReportUtils.getChatByParticipants([assignee]), 'reportID'); + const assigneeChatReportID = lodashGet(ReportUtils.getChatByParticipants([assigneeAccountID]), 'reportID'); const taskReportID = optimisticTaskReport.reportID; let optimisticAssigneeAddComment; if (assigneeChatReportID && assigneeChatReportID !== parentReportID) { - optimisticAssigneeAddComment = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assignee, `Assigned a task to you: ${title}`, parentReportID); + optimisticAssigneeAddComment = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeAccountID, `Assigned a task to you: ${title}`, parentReportID); } // Create the CreatedReportAction on the task const optimisticTaskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(optimisticTaskReport.reportID); - const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assignee, `Created a task: ${title}`, parentReportID); + const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeAccountID, `Created a task: ${title}`, parentReportID); const currentTime = DateUtils.getDBTime(); @@ -55,6 +56,7 @@ function createTaskAndNavigate(currentUserEmail, parentReportID, title, descript lastVisibleActionCreated: currentTime, lastMessageText: Str.htmlDecode(lastCommentText), lastActorEmail: currentUserEmail, + lastActorAccountID: currentUserAccountID, lastReadTime: currentTime, }; @@ -125,6 +127,7 @@ function createTaskAndNavigate(currentUserEmail, parentReportID, title, descript lastVisibleActionCreated: currentTime, lastMessageText: Str.htmlDecode(lastAssigneeCommentText), lastActorEmail: currentUserEmail, + lastActorAccountID: currentUserAccountID, lastReadTime: currentTime, }; @@ -158,7 +161,7 @@ function createTaskAndNavigate(currentUserEmail, parentReportID, title, descript reportName: optimisticTaskReport.reportName, title: optimisticTaskReport.reportName, description: optimisticTaskReport.description, - assignee, + assigneeAccountID, assigneeChatReportID, assigneeChatReportActionID: optimisticAssigneeAddComment ? optimisticAssigneeAddComment.reportAction.reportActionID : 0, }, @@ -237,6 +240,7 @@ function reopenTask(taskReportID, taskTitle) { lastVisibleActionCreated: reopenedTaskReportAction.created, lastMessageText: message, lastActorEmail: reopenedTaskReportAction.actorEmail, + lastActorAccountID: reopenedTaskReportAction.actorAccountID, lastReadTime: reopenedTaskReportAction.created, }, }, @@ -277,15 +281,16 @@ function reopenTask(taskReportID, taskTitle) { /** * @function editTask * @param {object} report - * @param {string} ownerEmail + * @param {String} ownerEmail + * @param {Number} ownerAccountID * @param {string} title * @param {string} description - * @param {string} assignee + * @param {Number} assigneeAccountID * @returns {object} action * */ -function editTaskAndNavigate(report, ownerEmail, title, description, assignee) { +function editTaskAndNavigate(report, ownerEmail, ownerAccountID, title, description, assigneeAccountID) { // Create the EditedReportAction on the task const editTaskReportAction = ReportUtils.buildOptimisticEditedTaskReportAction(ownerEmail); @@ -295,9 +300,9 @@ function editTaskAndNavigate(report, ownerEmail, title, description, assignee) { // If we make a change to the assignee, we want to add a comment to the assignee's chat let optimisticAssigneeAddComment; let assigneeChatReportID; - if (assignee && assignee !== report.managerEmail) { - assigneeChatReportID = ReportUtils.getChatByParticipants([assignee]).reportID; - optimisticAssigneeAddComment = ReportUtils.buildOptimisticTaskCommentReportAction(report.reportID, reportName, assignee, `Assigned a task to you: ${reportName}`); + if (assigneeAccountID && assigneeAccountID !== report.managerID) { + assigneeChatReportID = ReportUtils.getChatByParticipants([assigneeAccountID]).reportID; + optimisticAssigneeAddComment = ReportUtils.buildOptimisticTaskCommentReportAction(report.reportID, reportName, assigneeAccountID, `Assigned a task to you: ${reportName}`); } const optimisticData = [ @@ -312,7 +317,7 @@ function editTaskAndNavigate(report, ownerEmail, title, description, assignee) { value: { reportName, description: description.trim(), - managerEmail: assignee || report.managerEmail, + managerID: assigneeAccountID || report.managerID, }, }, ]; @@ -326,7 +331,7 @@ function editTaskAndNavigate(report, ownerEmail, title, description, assignee) { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, - value: {reportName: report.reportName, description: report.description, assignee: report.managerEmail}, + value: {reportName: report.reportName, description: report.description, assignee: report.managerEmail, assigneeAccountID: report.managerID}, }, ]; @@ -337,7 +342,7 @@ function editTaskAndNavigate(report, ownerEmail, title, description, assignee) { const optimisticAssigneeReport = { lastVisibleActionCreated: currentTime, lastMessageText: Str.htmlDecode(lastAssigneeCommentText), - lastActorEmail: ownerEmail, + lastActorAccountID: ownerAccountID, lastReadTime: currentTime, }; @@ -368,6 +373,7 @@ function editTaskAndNavigate(report, ownerEmail, title, description, assignee) { title: reportName, description: (description || report.description).trim(), assignee: assignee || report.managerEmail, + assigneeAccountID: assigneeAccountID || report.managerID, editedTaskReportActionID: editTaskReportAction.reportActionID, assigneeChatReportActionID: optimisticAssigneeAddComment ? optimisticAssigneeAddComment.reportAction.reportActionID : 0, }, @@ -391,7 +397,6 @@ function setTaskReport(report) { * @param {string} title * @param {string} description */ - function setDetailsValue(title, description) { // This is only needed for creation of a new task and so it should only be stored locally Onyx.merge(ONYXKEYS.TASK, {title: title.trim(), description: description.trim()}); @@ -455,7 +460,6 @@ function setAssigneeValue(assignee, shareDestination, isCurrentUser = false) { * Sets the parentReportID value for the task * @param {string} parentReportID */ - function setParentReportID(parentReportID) { // This is only needed for creation of a new task and so it should only be stored locally Onyx.merge(ONYXKEYS.TASK, {parentReportID}); diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index 40df151dacf1..dff2260201ee 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -203,7 +203,7 @@ class DetailsPage extends React.PureComponent { Report.navigateToAndOpenReport([details.login])} + onPress={() => Report.navigateToAndOpenReport([details.accountID])} wrapperStyle={styles.breakAll} shouldShowRightIcon /> diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js index 98522e691d55..c4f4b81ade64 100755 --- a/src/pages/NewChatPage.js +++ b/src/pages/NewChatPage.js @@ -194,7 +194,8 @@ class NewChatPage extends Component { * @param {Object} option */ createChat(option) { - Report.navigateToAndOpenReport([option.login]); + // TODO: do we need to generate an optimistic accountID here? + Report.navigateToAndOpenReport([option.accountID]); } /** @@ -206,11 +207,12 @@ class NewChatPage extends Component { return; } - const userLogins = _.pluck(this.state.selectedOptions, 'login'); - if (userLogins.length < 1) { + // TODO: do we need to generate an optimistic accountID here? + const userAccountIDs = _.pluck(this.state.selectedOptions, 'accountID'); + if (userAccountIDs.length < 1) { return; } - Report.navigateToAndOpenReport(userLogins); + Report.navigateToAndOpenReport(userAccountIDs); } render() { diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js index 932f489be5f4..f2b8d66e5e87 100755 --- a/src/pages/ProfilePage.js +++ b/src/pages/ProfilePage.js @@ -202,7 +202,7 @@ function ProfilePage(props) { Report.navigateToAndOpenReport([login])} + onPress={() => Report.navigateToAndOpenReport([accountID])} wrapperStyle={styles.breakAll} shouldShowRightIcon /> diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index 17ca3a0c0be4..1911c5787d27 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -160,7 +160,8 @@ class SearchPage extends Component { }, ); } else { - Report.navigateToAndOpenReport([option.login]); + // TODO: do we need to create an optimistic accountID here? + Report.navigateToAndOpenReport([option.accountID]); } } diff --git a/src/pages/tasks/NewTaskPage.js b/src/pages/tasks/NewTaskPage.js index 579806a3b3f3..3ceb54892e65 100644 --- a/src/pages/tasks/NewTaskPage.js +++ b/src/pages/tasks/NewTaskPage.js @@ -119,7 +119,7 @@ const NewTaskPage = (props) => { return; } - TaskUtils.createTaskAndNavigate(props.session.email, parentReport.reportID, props.task.title, props.task.description, props.task.assignee); + TaskUtils.createTaskAndNavigate(props.session.email, props.session.accountID, parentReport.reportID, props.task.title, props.task.description, props.task.assignee); } if (!Permissions.canUseTasks(props.betas)) { diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 86ed5da35de4..5b434c8167f8 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -170,10 +170,11 @@ const TaskAssigneeSelectorModal = (props) => { // Check to see if we're creating a new task // If there's no route params, we're creating a new task - if (!props.route.params && option.login) { + if (!props.route.params && option.accountID) { // Clear out the state value, set the assignee and navigate back to the NewTaskPage setSearchValue(''); - TaskUtils.setAssigneeValue(option.login, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); + // TODO: create optimistic accountID if we don't have an accountID? + TaskUtils.setAssigneeValue(option.accountID, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); return Navigation.goBack(); } @@ -181,9 +182,10 @@ const TaskAssigneeSelectorModal = (props) => { if (props.route.params.reportID && props.task.report.reportID === props.route.params.reportID) { // There was an issue where sometimes a new assignee didn't have a DM thread // This would cause the app to crash, so we need to make sure we have a DM thread - TaskUtils.setAssigneeValue(option.login, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); + // TODO: create optimistic accountID if we don't have an accountID? + TaskUtils.setAssigneeValue(option.accountID, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); // Pass through the selected assignee - TaskUtils.editTaskAndNavigate(props.task.report, props.session.email, '', '', option.login); + TaskUtils.editTaskAndNavigate(props.task.report, props.session.email, props.session.accountID, '', '', option.accountID); } }; diff --git a/src/pages/tasks/TaskDescriptionPage.js b/src/pages/tasks/TaskDescriptionPage.js index 1c894886d291..bad08e76ab17 100644 --- a/src/pages/tasks/TaskDescriptionPage.js +++ b/src/pages/tasks/TaskDescriptionPage.js @@ -41,7 +41,7 @@ function TaskDescriptionPage(props) { (values) => { // Set the description of the report in the store and then call TaskUtils.editTaskReport // to update the description of the report on the server - TaskUtils.editTaskAndNavigate(props.task.report, props.session.email, '', values.description, ''); + TaskUtils.editTaskAndNavigate(props.task.report, props.session.email, props.session.accountID, '', values.description, ''); }, [props], ); diff --git a/src/pages/tasks/TaskTitlePage.js b/src/pages/tasks/TaskTitlePage.js index 333c7135e46b..fb55acdaffd7 100644 --- a/src/pages/tasks/TaskTitlePage.js +++ b/src/pages/tasks/TaskTitlePage.js @@ -59,7 +59,7 @@ function TaskTitlePage(props) { // Set the description of the report in the store and then call TaskUtils.editTaskReport // to update the description of the report on the server - TaskUtils.editTaskAndNavigate(props.task.report, props.session.email, values.title, '', ''); + TaskUtils.editTaskAndNavigate(props.task.report, props.session.email, props.session.accountID, values.title, '', ''); }, [props], ); diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index f201e3753274..e44e34dfd8b4 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -915,6 +915,8 @@ describe('actions/IOU', () => { // There should now be 7 reports expect(_.size(allReports)).toBe(7); + console.log('ALL REPORTS', allReports); + // 1. The chat report with Rory + Carlos carlosChatReport = _.find(allReports, (report) => report.reportID === carlosChatReport.reportID); expect(_.isEmpty(carlosChatReport)).toBe(false); From 69939e8a9454fad61a81adfcaf06ded04e9fe1e6 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 8 Jun 2023 12:33:19 -0400 Subject: [PATCH 59/60] Fix iOU test and more migration --- src/libs/ReportUtils.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 986746ed8c23..46ed72d37f23 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1765,11 +1765,11 @@ function hasOutstandingIOU(report, iouReports) { } const iouReport = iouReports && iouReports[`${ONYXKEYS.COLLECTION.REPORT}${report.iouReportID}`]; - if (!iouReport || !iouReport.ownerEmail) { + if (!iouReport || !iouReport.ownerAccountID) { return false; } - if (iouReport.ownerEmail === currentUserEmail) { + if (iouReport.ownerAccountID === currentUserAccountID) { return false; } @@ -1786,7 +1786,7 @@ function isIOUOwnedByCurrentUser(report, iouReports = {}) { if (report.hasOutstandingIOU) { const iouReport = iouReports[`${ONYXKEYS.COLLECTION.REPORT}${report.iouReportID}`]; if (iouReport) { - return iouReport.ownerEmail === currentUserEmail; + return iouReport.ownerAccountID === currentUserAccountID; } } return false; @@ -1813,11 +1813,13 @@ function canSeeDefaultRoom(report, policies, betas) { } // Include domain rooms with Partner Managers (Expensify accounts) in them for accounts that are on a domain with an Approved Accountant + // TODO: figure out how we can determine accountIDs of "expensify emails" if (isDomainRoom(report) && doesDomainHaveApprovedAccountant && hasExpensifyEmails(lodashGet(report, ['participants'], []))) { return true; } // If the room has an assigned guide, it can be seen. + // TODO: figure out how we can determine accountIDs of "expensify emails" if (hasExpensifyGuidesEmails(lodashGet(report, ['participants'], []))) { return true; } From 79cca497992c3c10b831039c17b27ab807ffb3f7 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Thu, 8 Jun 2023 12:42:47 -0400 Subject: [PATCH 60/60] Fix reportUtilsTest --- tests/unit/ReportUtilsTest.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index 7527c30bb385..1fb9f4f3fc64 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -302,7 +302,7 @@ describe('ReportUtils', () => { const iouReports = { report_1: { reportID: '1', - ownerEmail: 'a@a.com', + ownerAccountID: 99, }, }; expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(false); @@ -316,7 +316,7 @@ describe('ReportUtils', () => { const iouReports = { report_1: { reportID: '1', - ownerEmail: 'a@a.com', + ownerAccountID: 99, }, }; expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(true); @@ -330,7 +330,7 @@ describe('ReportUtils', () => { const iouReports = { report_1: { reportID: '1', - ownerEmail: 'a@a.com', + ownerAccountID: 99, }, }; expect(ReportUtils.hasOutstandingIOU(report, iouReports)).toBe(false);