diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 16413f1da16ae..0c5eb0869f499 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -7855,6 +7855,8 @@ type BuildOptimisticChatReportParams = { optimisticReportID?: string; isPinned?: boolean; chatReportID?: string; + // TODO: This'll be required eventually. Refactor issue: https://github.com/Expensify/App/issues/66412 + currentUserAccountID?: number; }; function buildOptimisticChatReport({ @@ -7875,12 +7877,13 @@ function buildOptimisticChatReport({ optimisticReportID = '', isPinned = false, chatReportID = undefined, + currentUserAccountID = deprecatedCurrentUserAccountID, }: BuildOptimisticChatReportParams): OptimisticChatReport { const isWorkspaceChatType = chatType && isWorkspaceChat(chatType); const participants = participantList.reduce((reportParticipants: Participants, accountID: number) => { const participant: ReportParticipant = { notificationPreference, - ...(!isWorkspaceChatType && {role: accountID === deprecatedCurrentUserAccountID ? CONST.REPORT.ROLE.ADMIN : CONST.REPORT.ROLE.MEMBER}), + ...(!isWorkspaceChatType && {role: accountID === currentUserAccountID ? CONST.REPORT.ROLE.ADMIN : CONST.REPORT.ROLE.MEMBER}), }; // eslint-disable-next-line no-param-reassign reportParticipants[accountID] = participant; diff --git a/src/libs/actions/IOU/PerDiem.ts b/src/libs/actions/IOU/PerDiem.ts index f358aead8ec58..9dd822bfd1401 100644 --- a/src/libs/actions/IOU/PerDiem.ts +++ b/src/libs/actions/IOU/PerDiem.ts @@ -356,6 +356,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI isNewChatReport = true; chatReport = buildOptimisticChatReport({ participantList: [payerAccountID, payeeAccountID], + currentUserAccountID: currentUserAccountIDParam, }); } diff --git a/src/libs/actions/IOU/SendInvoice.ts b/src/libs/actions/IOU/SendInvoice.ts index deffc971dfa7e..1d7e6ee883502 100644 --- a/src/libs/actions/IOU/SendInvoice.ts +++ b/src/libs/actions/IOU/SendInvoice.ts @@ -619,6 +619,7 @@ function getSendInvoiceInformation({ participantList: [receiverAccountID, currentUserAccountID], chatType: CONST.REPORT.CHAT_TYPE.INVOICE, policyID: senderWorkspaceID, + currentUserAccountID, }); } diff --git a/src/libs/actions/IOU/SendMoney.ts b/src/libs/actions/IOU/SendMoney.ts index 381ef30260d69..590d3cc088fd4 100644 --- a/src/libs/actions/IOU/SendMoney.ts +++ b/src/libs/actions/IOU/SendMoney.ts @@ -72,6 +72,7 @@ function getSendMoneyParams({ created, merchant, receipt, + currentUserAccountID, }: { report: OnyxEntry; quickAction: OnyxEntry; @@ -84,6 +85,7 @@ function getSendMoneyParams({ created?: string; merchant?: string; receipt?: Receipt; + currentUserAccountID: number; }): SendMoneyParamsData { const recipientEmail = addSMSDomainIfPhoneNumber(recipient.login ?? ''); const recipientAccountID = Number(recipient.accountID); @@ -104,6 +106,7 @@ function getSendMoneyParams({ if (!chatReport) { chatReport = buildOptimisticChatReport({ participantList: [recipientAccountID, managerID], + currentUserAccountID, }); isNewChat = true; } @@ -503,6 +506,7 @@ function sendMoneyElsewhere( created, merchant, receipt, + currentUserAccountID, }); startSpan(CONST.TELEMETRY.SPAN_SUBMIT_TO_DESTINATION_VISIBLE, { name: 'submit-to-destination-visible', @@ -550,6 +554,7 @@ function sendMoneyWithWallet( created, merchant, receipt, + currentUserAccountID, }); startSpan(CONST.TELEMETRY.SPAN_SUBMIT_TO_DESTINATION_VISIBLE, { name: 'submit-to-destination-visible', diff --git a/src/libs/actions/IOU/Split.ts b/src/libs/actions/IOU/Split.ts index 8fb23c4d86445..2a9368a72c8d5 100644 --- a/src/libs/actions/IOU/Split.ts +++ b/src/libs/actions/IOU/Split.ts @@ -860,6 +860,7 @@ function completeSplitBill( existingChatReport ?? buildOptimisticChatReport({ participantList: participant.accountID ? [participant.accountID, sessionAccountID] : [], + currentUserAccountID: sessionAccountID, }); } diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index 7b22962ecd85a..cf8e85951900d 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -3326,6 +3326,7 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma chatReport = buildOptimisticChatReport({ participantList: [payerAccountID, payeeAccountID], optimisticReportID: optimisticChatReportID, + currentUserAccountID: currentUserAccountIDParam, }); } @@ -7034,6 +7035,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string reportName: '', chatType: CONST.REPORT.CHAT_TYPE.GROUP, notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + currentUserAccountID, }); return {existingSplitChatReport: null, splitChatReport}; @@ -7042,6 +7044,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string // Otherwise, create a new 1:1 chat report const splitChatReport = buildOptimisticChatReport({ participantList: participantAccountIDs, + currentUserAccountID, }); return {existingSplitChatReport: null, splitChatReport}; } @@ -7361,6 +7364,7 @@ function createSplitsAndOnyxData({ existingChatReport ?? buildOptimisticChatReport({ participantList: [accountID, currentUserAccountID], + currentUserAccountID, }); } diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 6217dbbcdae69..e91eed2c5ca5b 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -1600,6 +1600,7 @@ function createPolicyExpenseChats( policyID, ownerAccountID: cleanAccountID, notificationPreference, + currentUserAccountID: deprecatedSessionAccountID, }); // Set correct notification preferences: visible for the submitter, hidden for others until there's activity diff --git a/src/libs/actions/Report/index.ts b/src/libs/actions/Report/index.ts index 0c7779bf56c41..1f3f0161c52c5 100644 --- a/src/libs/actions/Report/index.ts +++ b/src/libs/actions/Report/index.ts @@ -1873,6 +1873,7 @@ function getOptimisticChatReport(accountID: number, currentUserAccountID: number return buildOptimisticChatReport({ participantList: [accountID, currentUserAccountID], notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + currentUserAccountID, }); } @@ -1986,6 +1987,7 @@ function navigateToAndOpenReport( newChat = buildOptimisticChatReport({ participantList: [...participantAccountIDs, currentUserAccountID], notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + currentUserAccountID, }); // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server openReport({reportID: newChat?.reportID, introSelected, reportActionID: '', participantLoginList: userLogins, newReportObject: newChat, isSelfTourViewed, betas}); @@ -2027,6 +2029,7 @@ function navigateToAndOpenReportWithAccountIDs(participantAccountIDs: number[], if (!chat) { newChat = buildOptimisticChatReport({ participantList: [...participantAccountIDs, currentUserAccountID], + currentUserAccountID, }); // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server openReport({ @@ -2092,6 +2095,7 @@ function createChildReport( parentReportActionID: parentReportAction.reportActionID, parentReportID: parentReport?.reportID, optimisticReportID: parentReportAction.childReportID, + currentUserAccountID, }); const childReportID = childReport?.reportID ?? parentReportAction.childReportID; @@ -2993,6 +2997,7 @@ function toggleSubscribeToChildReport( notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, parentReportActionID: parentReportAction.reportActionID, parentReportID: parentReport?.reportID, + currentUserAccountID, }); const participantLogins = PersonalDetailsUtils.getLoginsByAccountIDs(participantAccountIDs); diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index cb643bb224901..5011db30bbb66 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -924,6 +924,7 @@ function setNewOptimisticAssignee(currentUserAccountID: number, assigneePersonal policyID: CONST.POLICY.OWNER_EMAIL_FAKE, ownerAccountID: CONST.POLICY.OWNER_ACCOUNT_ID_FAKE, notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + currentUserAccountID, }); Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, report); diff --git a/src/libs/actions/TeachersUnite.ts b/src/libs/actions/TeachersUnite.ts index 3e838ae157de0..c46cb86988ca3 100644 --- a/src/libs/actions/TeachersUnite.ts +++ b/src/libs/actions/TeachersUnite.ts @@ -23,12 +23,13 @@ type ExpenseReportActionData = Record; /** * @param publicRoomReportID - This is the global reportID for the public room, we'll ignore the optimistic one */ -function referTeachersUniteVolunteer(partnerUserID: string, firstName: string, lastName: string, policyID: string, publicRoomReportID: string) { +function referTeachersUniteVolunteer(partnerUserID: string, firstName: string, lastName: string, policyID: string, publicRoomReportID: string, currentUserAccountID: number) { const optimisticPublicRoom = buildOptimisticChatReport({ participantList: [], reportName: CONST.TEACHERS_UNITE.PUBLIC_ROOM_NAME, chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, policyID, + currentUserAccountID, }); const optimisticData: Array> = [ { @@ -86,6 +87,7 @@ function addSchoolPrincipal( isOwnPolicyExpenseChat: true, oldPolicyName: policyName, optimisticReportID, + currentUserAccountID: sessionAccountID, }); const expenseChatReportID = expenseChatData.reportID; const expenseReportCreatedAction = buildOptimisticCreatedReportAction(sessionEmail); diff --git a/src/pages/TeachersUnite/KnowATeacherPage.tsx b/src/pages/TeachersUnite/KnowATeacherPage.tsx index 15e149520ff86..bca5edab92401 100644 --- a/src/pages/TeachersUnite/KnowATeacherPage.tsx +++ b/src/pages/TeachersUnite/KnowATeacherPage.tsx @@ -8,6 +8,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useEnvironment from '@hooks/useEnvironment'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -27,6 +28,7 @@ function KnowATeacherPage() { const {isProduction} = useEnvironment(); const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE); + const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); /** * Submit form to pass firstName, partnerUserID and lastName */ @@ -39,7 +41,7 @@ function KnowATeacherPage() { const policyID = isProduction ? CONST.TEACHERS_UNITE.PROD_POLICY_ID : CONST.TEACHERS_UNITE.TEST_POLICY_ID; const publicRoomReportID = isProduction ? CONST.TEACHERS_UNITE.PROD_PUBLIC_ROOM_ID : CONST.TEACHERS_UNITE.TEST_PUBLIC_ROOM_ID; - TeachersUnite.referTeachersUniteVolunteer(contactMethod, firstName, lastName, policyID, publicRoomReportID); + TeachersUnite.referTeachersUniteVolunteer(contactMethod, firstName, lastName, policyID, publicRoomReportID, currentUserAccountID); }; /** diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 22c009ce2832a..6f0e88ae2c190 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -118,7 +118,8 @@ function WorkspaceNewRoomPage({ref}: WorkspaceNewRoomPageProps) { */ const submit = (values: FormOnyxValues) => { setNewRoomFormLoading(); - const participants = [session?.accountID ?? CONST.DEFAULT_NUMBER_ID]; + const currentUserAccountID = session?.accountID ?? CONST.DEFAULT_NUMBER_ID; + const participants = [currentUserAccountID]; const parsedDescription = getParsedComment(values.reportDescription ?? '', {policyID}); const policyReport = buildOptimisticChatReport({ participantList: participants, @@ -130,6 +131,7 @@ function WorkspaceNewRoomPage({ref}: WorkspaceNewRoomPageProps) { writeCapability: writeCapability || CONST.REPORT.WRITE_CAPABILITIES.ALL, notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.DAILY, description: parsedDescription, + currentUserAccountID, }); // eslint-disable-next-line @typescript-eslint/no-deprecated diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index 1b2bf20b294b5..3318f39e5e89b 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -6263,9 +6263,53 @@ describe('ReportUtils', () => { it('should always set isPinned to false', () => { const result = buildOptimisticChatReport({ participantList: [1, 2, 3], + currentUserAccountID: 1, }); expect(result.isPinned).toBe(false); }); + + it('should assign ADMIN role to currentUserAccountID and MEMBER role to others for non-workspace chats', () => { + const currentUser = 100; + const result = buildOptimisticChatReport({ + participantList: [currentUser, 200, 300], + currentUserAccountID: currentUser, + }); + expect(result.participants?.[currentUser]?.role).toBe(CONST.REPORT.ROLE.ADMIN); + expect(result.participants?.[200]?.role).toBe(CONST.REPORT.ROLE.MEMBER); + expect(result.participants?.[300]?.role).toBe(CONST.REPORT.ROLE.MEMBER); + }); + + it('should assign ADMIN role based on the provided currentUserAccountID, not the deprecated global value', () => { + const explicitCurrentUser = 999; + const result = buildOptimisticChatReport({ + participantList: [explicitCurrentUser, 1, 2], + currentUserAccountID: explicitCurrentUser, + }); + expect(result.participants?.[explicitCurrentUser]?.role).toBe(CONST.REPORT.ROLE.ADMIN); + expect(result.participants?.[1]?.role).toBe(CONST.REPORT.ROLE.MEMBER); + expect(result.participants?.[2]?.role).toBe(CONST.REPORT.ROLE.MEMBER); + }); + + it('should not assign role for workspace chat types', () => { + const currentUser = 100; + const result = buildOptimisticChatReport({ + participantList: [currentUser, 200], + chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, + currentUserAccountID: currentUser, + }); + expect(result.participants?.[currentUser]?.role).toBeUndefined(); + expect(result.participants?.[200]?.role).toBeUndefined(); + }); + + it('should assign all participants as MEMBER when currentUserAccountID is not in the participant list', () => { + const result = buildOptimisticChatReport({ + participantList: [1, 2, 3], + currentUserAccountID: 999, + }); + expect(result.participants?.[1]?.role).toBe(CONST.REPORT.ROLE.MEMBER); + expect(result.participants?.[2]?.role).toBe(CONST.REPORT.ROLE.MEMBER); + expect(result.participants?.[3]?.role).toBe(CONST.REPORT.ROLE.MEMBER); + }); }); describe('getWorkspaceNameUpdatedMessage', () => {