From ebb0330ca92a456593c77b1eaaa70530e0fe3dc3 Mon Sep 17 00:00:00 2001 From: parasharrajat Date: Fri, 21 Nov 2025 22:44:41 +0530 Subject: [PATCH 1/4] Revert "Revert "Trigger whisper when user invites a member to the chat "" --- src/libs/ReportActionsUtils.ts | 7 ++++++ src/libs/actions/Report.ts | 8 +++++++ src/pages/RoomInvitePage.tsx | 22 ++++++++++++++----- .../home/report/PureReportActionItem.tsx | 8 +++++-- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 4a4578c212c9..0c0d4ecb12ed 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -3338,6 +3338,12 @@ function getSubmittedTo(action: OnyxEntry): string | undefined { return getOriginalMessage(action)?.to; } +function isSystemUserMentioned(action: OnyxInputOrEntry>): boolean { + const mentionedUsers = getOriginalMessage(action)?.inviteeAccountIDs; + const systemAccountIDs = new Set(Object.values(CONST.ACCOUNT_ID)); + return mentionedUsers?.some((accountID) => systemAccountIDs.has(accountID)) ?? false; +} + export { doesReportHaveVisibleActions, extractLinksFromMessageHtml, @@ -3519,6 +3525,7 @@ export { isPendingHide, filterOutDeprecatedReportActions, getActionableCardFraudAlertMessage, + isSystemUserMentioned, }; export type {LastVisibleMessage}; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 12484f9a5d6e..d8a495edc178 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3853,6 +3853,13 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails API.write(WRITE_COMMANDS.INVITE_TO_ROOM, parameters, {optimisticData, successData, failureData}); } +/** Invites people to a room via concierge whisper */ +function inviteToRoomAction(reportID: string, ancestors: Ancestor[], inviteeEmailsToAccountIDs: InvitedEmailsToAccountIDs, timezoneParam: Timezone) { + const inviteeEmails = Object.keys(inviteeEmailsToAccountIDs); + + addComment(reportID, reportID, ancestors, inviteeEmails.map((login) => `@${login}`).join(' '), timezoneParam, false); +} + function clearAddRoomMemberError(reportID: string, invitedAccountID: string) { const reportMetadata = getReportMetadata(reportID); Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { @@ -6082,6 +6089,7 @@ export { inviteToGroupChat, buildInviteToRoomOnyxData, inviteToRoom, + inviteToRoomAction, joinRoom, leaveGroupChat, leaveRoom, diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 3740053d382e..01eca5ddfae7 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -12,12 +12,14 @@ import InviteMemberListItem from '@components/SelectionListWithSections/InviteMe import type {Section} from '@components/SelectionListWithSections/types'; import withNavigationTransitionEnd from '@components/withNavigationTransitionEnd'; import type {WithNavigationTransitionEndProps} from '@components/withNavigationTransitionEnd'; +import useAncestors from '@hooks/useAncestors'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; -import {inviteToRoom, searchInServer} from '@libs/actions/Report'; +import {inviteToRoomAction, searchInServer} from '@libs/actions/Report'; import {clearUserSearchPhrase, updateUserSearchPhrase} from '@libs/actions/RoomMembersUserSearchPhrase'; import {READ_COMMANDS} from '@libs/API/types'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; @@ -55,13 +57,14 @@ function RoomInvitePage({ }, }: RoomInvitePageProps) { const styles = useThemeStyles(); - const {translate, formatPhoneNumber} = useLocalize(); + const {translate} = useLocalize(); const [userSearchPhrase] = useOnyx(ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE, {canBeMissing: true}); const [countryCode = CONST.DEFAULT_COUNTRY_CODE] = useOnyx(ONYXKEYS.COUNTRY_CODE, {canBeMissing: false}); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(userSearchPhrase ?? ''); const [selectedOptions, setSelectedOptions] = useState([]); const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false, canBeMissing: true}); const isReportArchived = useReportIsArchived(report.reportID); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const {options, areOptionsInitialized} = useOptionsList(); @@ -192,6 +195,9 @@ function RoomInvitePage({ return reportID && (!isPolicyEmployee || isReportArchived ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID, backTo) : ROUTES.ROOM_MEMBERS.getRoute(reportID, backTo)); }, [isPolicyEmployee, reportID, backTo, isReportArchived]); const reportName = useMemo(() => getReportName(report), [report]); + + const ancestors = useAncestors(report); + const inviteUsers = useCallback(() => { HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS); @@ -208,11 +214,15 @@ function RoomInvitePage({ invitedEmailsToAccountIDs[login] = Number(accountID); } if (reportID) { - inviteToRoom(reportID, invitedEmailsToAccountIDs, formatPhoneNumber); + inviteToRoomAction(reportID, ancestors, invitedEmailsToAccountIDs, currentUserPersonalDetails.timezone ?? CONST.DEFAULT_TIME_ZONE); + clearUserSearchPhrase(); + if (backTo) { + Navigation.goBack(backTo); + } else { + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(reportID)); + } } - clearUserSearchPhrase(); - Navigation.goBack(backRoute); - }, [selectedOptions, backRoute, reportID, validate, formatPhoneNumber]); + }, [validate, selectedOptions, ancestors, reportID, currentUserPersonalDetails.timezone, backTo]); const goBack = useCallback(() => { Navigation.goBack(backRoute); diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 6b68c52ef9a0..703075cd9da3 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -58,7 +58,7 @@ import {isReportMessageAttachment} from '@libs/isReportMessageAttachment'; import Navigation from '@libs/Navigation/Navigation'; import Permissions from '@libs/Permissions'; import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; -import {getCleanedTagName, getPersonalPolicy, isPolicyAdmin, isPolicyOwner} from '@libs/PolicyUtils'; +import {getCleanedTagName, getPersonalPolicy, isPolicyAdmin, isPolicyOwner, isPolicyUser} from '@libs/PolicyUtils'; import { extractLinksFromMessageHtml, getActionableCardFraudAlertMessage, @@ -132,6 +132,7 @@ import { isRenamedAction, isResolvedConciergeCategoryOptions, isSplitBillAction as isSplitBillActionReportActionsUtils, + isSystemUserMentioned, isTagModificationAction, isTaskAction, isTrackExpenseAction as isTrackExpenseActionReportActionsUtils, @@ -906,7 +907,10 @@ function PureReportActionItem({ const actionableMentionWhisperOptions = []; const isReportInPolicy = !!report?.policyID && report.policyID !== CONST.POLICY.ID_FAKE && getPersonalPolicy()?.id !== report.policyID; - if (isReportInPolicy && (isPolicyAdmin(policy) || isPolicyOwner(policy, currentUserAccountID))) { + // Show the invite to submit expense button even if one of the mentioned users is a not a policy member + const hasMentionedPolicyMembers = getOriginalMessage(action)?.inviteeEmails?.every((login) => isPolicyUser(policy, login)) ?? false; + + if ((isPolicyAdmin(policy) || isPolicyOwner(policy, currentUserAccountID)) && isReportInPolicy && !isSystemUserMentioned(action) && !hasMentionedPolicyMembers) { actionableMentionWhisperOptions.push({ text: 'actionableMentionWhisperOptions.inviteToSubmitExpense', key: `${action.reportActionID}-actionableMentionWhisper-${CONST.REPORT.ACTIONABLE_MENTION_WHISPER_RESOLUTION.INVITE_TO_SUBMIT_EXPENSE}`, From 284036d5b7d962730f0d1336673e0880d26b3808 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Mon, 1 Dec 2025 11:41:31 +0530 Subject: [PATCH 2/4] Use Correct member method --- .../home/report/PureReportActionItem.tsx | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index 8cfe8f7685b0..eb2110869d1e 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -58,7 +58,7 @@ import {isReportMessageAttachment} from '@libs/isReportMessageAttachment'; import Navigation from '@libs/Navigation/Navigation'; import Permissions from '@libs/Permissions'; import {getDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; -import {getCleanedTagName, getPersonalPolicy, isPolicyAdmin, isPolicyOwner, isPolicyUser} from '@libs/PolicyUtils'; +import {getCleanedTagName, getPersonalPolicy, isPolicyAdmin, isPolicyMember, isPolicyOwner} from '@libs/PolicyUtils'; import { extractLinksFromMessageHtml, getActionableCardFraudAlertMessage, @@ -941,7 +941,7 @@ function PureReportActionItem({ const isReportInPolicy = !!report?.policyID && report.policyID !== CONST.POLICY.ID_FAKE && getPersonalPolicy()?.id !== report.policyID; // Show the invite to submit expense button even if one of the mentioned users is a not a policy member - const hasMentionedPolicyMembers = getOriginalMessage(action)?.inviteeEmails?.every((login) => isPolicyUser(policy, login)) ?? false; + const hasMentionedPolicyMembers = getOriginalMessage(action)?.inviteeEmails?.every((login) => isPolicyMember(policy, login)) ?? false; if ((isPolicyAdmin(policy) || isPolicyOwner(policy, currentUserAccountID)) && isReportInPolicy && !isSystemUserMentioned(action) && !hasMentionedPolicyMembers) { actionableMentionWhisperOptions.push({ @@ -968,28 +968,7 @@ function PureReportActionItem({ }, ); return actionableMentionWhisperOptions; - }, [ - action, - userBillingFundID, - originalReportID, - reportID, - isActionableWhisper, - report?.policyID, - policy, - currentUserAccountID, - personalDetail.timezone, - createDraftTransactionAndNavigateToParticipantSelector, - isRestrictedToPreferredPolicy, - preferredPolicyID, - dismissTrackExpenseActionableWhisper, - translate, - resolveActionableReportMentionWhisper, - isReportArchived, - formatPhoneNumber, - isOriginalReportArchived, - resolveActionableMentionWhisper, - introSelected, - ]); + }, [action, userBillingFundID, originalReportID, reportID, isActionableWhisper, report?.policyID, policy, currentUserAccountID, personalDetail.timezone, createDraftTransactionAndNavigateToParticipantSelector, isRestrictedToPreferredPolicy, preferredPolicyID, dismissTrackExpenseActionableWhisper, translate, resolveActionableReportMentionWhisper, isReportArchived, isOriginalReportArchived, resolveActionableMentionWhisper, introSelected]); /** * Get the content of ReportActionItem From 0aa2338f4cfc75fb3264b029a0cb063045e587a6 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Mon, 1 Dec 2025 14:09:59 +0530 Subject: [PATCH 3/4] prettier fix --- .../home/report/PureReportActionItem.tsx | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/PureReportActionItem.tsx b/src/pages/home/report/PureReportActionItem.tsx index eb2110869d1e..806c4f9531fe 100644 --- a/src/pages/home/report/PureReportActionItem.tsx +++ b/src/pages/home/report/PureReportActionItem.tsx @@ -968,7 +968,27 @@ function PureReportActionItem({ }, ); return actionableMentionWhisperOptions; - }, [action, userBillingFundID, originalReportID, reportID, isActionableWhisper, report?.policyID, policy, currentUserAccountID, personalDetail.timezone, createDraftTransactionAndNavigateToParticipantSelector, isRestrictedToPreferredPolicy, preferredPolicyID, dismissTrackExpenseActionableWhisper, translate, resolveActionableReportMentionWhisper, isReportArchived, isOriginalReportArchived, resolveActionableMentionWhisper, introSelected]); + }, [ + action, + userBillingFundID, + originalReportID, + reportID, + isActionableWhisper, + report?.policyID, + policy, + currentUserAccountID, + personalDetail.timezone, + createDraftTransactionAndNavigateToParticipantSelector, + isRestrictedToPreferredPolicy, + preferredPolicyID, + dismissTrackExpenseActionableWhisper, + translate, + resolveActionableReportMentionWhisper, + isReportArchived, + isOriginalReportArchived, + resolveActionableMentionWhisper, + introSelected, + ]); /** * Get the content of ReportActionItem From 4cb566d850a8f45345efcb26026c19a3b3a2b926 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 10 Dec 2025 23:02:52 +0530 Subject: [PATCH 4/4] Fix lint --- src/pages/RoomInvitePage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index 51e9558e2276..3f005c9b174a 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -194,6 +194,8 @@ function RoomInvitePage({ const backRoute = useMemo(() => { return reportID && (!isPolicyEmployee || isReportArchived ? ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID, backTo) : ROUTES.ROOM_MEMBERS.getRoute(reportID, backTo)); }, [isPolicyEmployee, reportID, backTo, isReportArchived]); + + // eslint-disable-next-line @typescript-eslint/no-deprecated const reportName = useMemo(() => getReportName(report), [report]); const ancestors = useAncestors(report);