Skip to content

Commit

Permalink
Merge pull request #50247 from bernhardoj/fix/49824-new-message-shows…
Browse files Browse the repository at this point in the history
…-after-resolving-whisper
  • Loading branch information
dangrous authored Jan 23, 2025
2 parents 62b85e8 + 3528073 commit d930fea
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 63 deletions.
4 changes: 1 addition & 3 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ import {
isReimbursementDeQueuedAction,
isReimbursementQueuedAction,
isReportPreviewAction,
isResolvedActionTrackExpense,
isTaskAction,
isThreadParentMessage,
isUnapprovedAction,
Expand Down Expand Up @@ -381,8 +380,7 @@ Onyx.connect({
shouldReportActionBeVisible(reportAction, actionKey, isWriteActionAllowed) &&
!isWhisperAction(reportAction) &&
reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED &&
reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE &&
!isResolvedActionTrackExpense(reportAction),
reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
);
const reportActionForDisplay = reportActionsForDisplay.at(0);
if (!reportActionForDisplay) {
Expand Down
77 changes: 40 additions & 37 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,39 @@ function isReportActionDeprecated(reportAction: OnyxEntry<ReportAction>, key: st
return false;
}

/**
* Checks if a given report action corresponds to an actionable mention whisper.
* @param reportAction
*/
function isActionableMentionWhisper(reportAction: OnyxEntry<ReportAction>): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER> {
return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER);
}

/**
* Checks if a given report action corresponds to an actionable report mention whisper.
* @param reportAction
*/
function isActionableReportMentionWhisper(reportAction: OnyxEntry<ReportAction>): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER> {
return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER);
}

/**
* Checks whether an action is actionable track expense.
*/
function isActionableTrackExpense(reportAction: OnyxInputOrEntry<ReportAction>): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER> {
return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER);
}

function isActionableWhisper(
reportAction: OnyxEntry<ReportAction>,
): reportAction is ReportAction<
| typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER
| typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER
| typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER
> {
return isActionableMentionWhisper(reportAction) || isActionableTrackExpense(reportAction) || isActionableReportMentionWhisper(reportAction);
}

const {POLICY_CHANGE_LOG: policyChangelogTypes, ROOM_CHANGE_LOG: roomChangeLogTypes, ...otherActionTypes} = CONST.REPORT.ACTIONS.TYPE;
const supportedActionTypes: ReportActionName[] = [...Object.values(otherActionTypes), ...Object.values(policyChangelogTypes), ...Object.values(roomChangeLogTypes)];

Expand Down Expand Up @@ -686,6 +719,11 @@ function shouldReportActionBeVisible(reportAction: OnyxEntry<ReportAction>, key:
return true;
}

// If action is actionable whisper and resolved by user, then we don't want to render anything
if (isActionableWhisper(reportAction) && getOriginalMessage(reportAction)?.resolution) {
return false;
}

// All other actions are displayed except thread parents, deleted, or non-pending actions
const isDeleted = isDeletedAction(reportAction);
const isPending = !!reportAction.pendingAction;
Expand All @@ -703,24 +741,6 @@ function shouldHideNewMarker(reportAction: OnyxEntry<ReportAction>): boolean {
return !isNetworkOffline && reportAction.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
}

/**
* Checks whether an action is actionable track expense.
*
*/
function isActionableTrackExpense(reportAction: OnyxInputOrEntry<ReportAction>): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER> {
return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_TRACK_EXPENSE_WHISPER);
}

/**
* Checks whether an action is actionable track expense and resolved.
*
*/
function isResolvedActionTrackExpense(reportAction: OnyxEntry<ReportAction>): boolean {
const originalMessage = getOriginalMessage(reportAction);
const resolution = originalMessage && typeof originalMessage === 'object' && 'resolution' in originalMessage ? originalMessage?.resolution : null;
return isActionableTrackExpense(reportAction) && !!resolution;
}

/**
* Checks if a reportAction is fit for display as report last action, meaning that
* it satisfies shouldReportActionBeVisible, it's not whisper action and not deleted.
Expand All @@ -739,8 +759,7 @@ function shouldReportActionBeVisibleAsLastAction(reportAction: OnyxInputOrEntry<
return (
shouldReportActionBeVisible(reportAction, reportAction.reportActionID, canUserPerformWriteAction) &&
!(isWhisperAction(reportAction) && !isReportPreviewAction(reportAction) && !isMoneyRequestAction(reportAction)) &&
!(isDeletedAction(reportAction) && !isDeletedParentAction(reportAction)) &&
!isResolvedActionTrackExpense(reportAction)
!(isDeletedAction(reportAction) && !isDeletedParentAction(reportAction))
);
}

Expand Down Expand Up @@ -1451,22 +1470,6 @@ function hasRequestFromCurrentAccount(reportID: string, currentAccountID: number
return reportActions.some((action) => action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && action.actorAccountID === currentAccountID);
}

/**
* Checks if a given report action corresponds to an actionable mention whisper.
* @param reportAction
*/
function isActionableMentionWhisper(reportAction: OnyxEntry<ReportAction>): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER> {
return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_MENTION_WHISPER);
}

/**
* Checks if a given report action corresponds to an actionable report mention whisper.
* @param reportAction
*/
function isActionableReportMentionWhisper(reportAction: OnyxEntry<ReportAction>): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER> {
return isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_REPORT_MENTION_WHISPER);
}

/**
* Constructs a message for an actionable mention whisper report action.
* @param reportAction
Expand Down Expand Up @@ -1927,6 +1930,7 @@ export {
getWhisperedTo,
hasRequestFromCurrentAccount,
isActionOfType,
isActionableWhisper,
isActionableJoinRequest,
isActionableJoinRequestPending,
isActionableMentionWhisper,
Expand Down Expand Up @@ -1960,7 +1964,6 @@ export {
isReportActionAttachment,
isReportActionDeprecated,
isReportPreviewAction,
isResolvedActionTrackExpense,
isReversedTransaction,
isRoomChangeLogAction,
isSentMoneyReportAction,
Expand Down
23 changes: 0 additions & 23 deletions src/pages/home/report/PureReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import Text from '@components/Text';
import UnreadActionIndicator from '@components/UnreadActionIndicator';
import useLocalize from '@hooks/useLocalize';
import usePrevious from '@hooks/usePrevious';
import useReportScrollManager from '@hooks/useReportScrollManager';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
Expand Down Expand Up @@ -372,19 +371,14 @@ function PureReportActionItem({
const downloadedPreviews = useRef<string[]>([]);
const prevDraftMessage = usePrevious(draftMessage);
const isReportActionLinked = linkedReportActionID && action.reportActionID && linkedReportActionID === action.reportActionID;
const reportScrollManager = useReportScrollManager();
const isActionableWhisper = isActionableMentionWhisper(action) || isActionableTrackExpense(action) || isActionableReportMentionWhisper(action);
const originalMessage = getOriginalMessage(action);

const highlightedBackgroundColorIfNeeded = useMemo(
() => (isReportActionLinked ? StyleUtils.getBackgroundColorStyle(theme.messageHighlightBG) : {}),
[StyleUtils, isReportActionLinked, theme.messageHighlightBG],
);

const isDeletedParentAction = isDeletedParentActionUtils(action);
const isOriginalMessageAnObject = originalMessage && typeof originalMessage === 'object';
const hasResolutionInOriginalMessage = isOriginalMessageAnObject && 'resolution' in originalMessage;
const prevActionResolution = usePrevious(isActionableWhisper && hasResolutionInOriginalMessage ? originalMessage?.resolution : null);

// IOUDetails only exists when we are sending money
const isSendingMoney = isMoneyRequestAction(action) && getOriginalMessage(action)?.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && getOriginalMessage(action)?.IOUDetails;
Expand Down Expand Up @@ -552,18 +546,6 @@ function PureReportActionItem({
],
);

// Handles manual scrolling to the bottom of the chat when the last message is an actionable whisper and it's resolved.
// This fixes an issue where InvertedFlatList fails to auto scroll down and results in an empty space at the bottom of the chat in IOS.
useEffect(() => {
if (index !== 0 || !isActionableWhisper) {
return;
}

if (prevActionResolution !== (hasResolutionInOriginalMessage ? originalMessage.resolution : null)) {
reportScrollManager.scrollToIndex(index);
}
}, [index, originalMessage, prevActionResolution, reportScrollManager, isActionableWhisper, hasResolutionInOriginalMessage]);

const toggleReaction = useCallback(
(emoji: Emoji, ignoreSkinToneOnCompare?: boolean) => {
toggleEmojiReaction(reportID, action, emoji, emojiReactions, undefined, ignoreSkinToneOnCompare);
Expand Down Expand Up @@ -1102,11 +1084,6 @@ function PureReportActionItem({
return null;
}

// If action is actionable whisper and resolved by user, then we don't want to render anything
if (isActionableWhisper && (hasResolutionInOriginalMessage ? originalMessage.resolution : null)) {
return null;
}

// We currently send whispers to all report participants and hide them in the UI for users that shouldn't see them.
// This is a temporary solution needed for comment-linking.
// The long term solution will leverage end-to-end encryption and only targeted users will be able to decrypt.
Expand Down

0 comments on commit d930fea

Please sign in to comment.