Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,6 @@ const ONYXKEYS = {
REPORT_ATTRIBUTES: 'reportAttributes',
REPORT_TRANSACTIONS_AND_VIOLATIONS: 'reportTransactionsAndViolations',
OUTSTANDING_REPORTS_BY_POLICY_ID: 'outstandingReportsByPolicyID',
VISIBLE_REPORT_ACTIONS: 'visibleReportActions',
NON_PERSONAL_AND_WORKSPACE_CARD_LIST: 'nonPersonalAndWorkspaceCardList',
PERSONAL_AND_WORKSPACE_CARD_LIST: 'personalAndWorkspaceCardList',
CARD_FEED_ERRORS: 'cardFeedErrors',
Expand Down Expand Up @@ -1434,7 +1433,6 @@ type OnyxDerivedValuesMapping = {
[ONYXKEYS.DERIVED.REPORT_ATTRIBUTES]: OnyxTypes.ReportAttributesDerivedValue;
[ONYXKEYS.DERIVED.REPORT_TRANSACTIONS_AND_VIOLATIONS]: OnyxTypes.ReportTransactionsAndViolationsDerivedValue;
[ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID]: OnyxTypes.OutstandingReportsByPolicyIDDerivedValue;
[ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS]: OnyxTypes.VisibleReportActionsDerivedValue;
[ONYXKEYS.DERIVED.NON_PERSONAL_AND_WORKSPACE_CARD_LIST]: OnyxTypes.NonPersonalAndWorkspaceCardListDerivedValue;
[ONYXKEYS.DERIVED.PERSONAL_AND_WORKSPACE_CARD_LIST]: OnyxTypes.PersonalAndWorkspaceCardListDerivedValue;
[ONYXKEYS.DERIVED.CARD_FEED_ERRORS]: OnyxTypes.CardFeedErrorsDerivedValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import type {OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type {Attachment} from '@components/Attachments/types';
import {getFileName, splitExtensionFromFileName} from '@libs/fileDownload/FileUtils';
import {getHtmlWithAttachmentID, getReportActionHtml, getReportActionMessage, getSortedReportActions, isMoneyRequestAction, isReportActionVisible} from '@libs/ReportActionsUtils';
import {getHtmlWithAttachmentID, getReportActionHtml, getReportActionMessage, getSortedReportActions, isMoneyRequestAction, shouldReportActionBeVisible} from '@libs/ReportActionsUtils';
import {canUserPerformWriteAction} from '@libs/ReportUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import CONST from '@src/CONST';
import type {Report, ReportAction, ReportActions, VisibleReportActionsDerivedValue} from '@src/types/onyx';
import type {Report, ReportAction, ReportActions} from '@src/types/onyx';
import type {Note} from '@src/types/onyx/Report';

/**
Expand All @@ -22,15 +22,13 @@ function extractAttachments(
reportActions,
report,
isReportArchived,
visibleReportActionsData,
}: {
privateNotes?: Record<number, Note>;
accountID?: number;
parentReportAction?: OnyxEntry<ReportAction>;
reportActions?: OnyxEntry<ReportActions>;
report: OnyxEntry<Report>;
isReportArchived: boolean | undefined;
visibleReportActionsData?: VisibleReportActionsDerivedValue;
},
) {
const targetNote = privateNotes?.[Number(accountID)]?.note ?? '';
Expand Down Expand Up @@ -117,13 +115,9 @@ function extractAttachments(
return attachments.reverse();
}

const reportID = report?.reportID;
if (!reportID) {
return attachments.reverse();
}
const actions = [...(parentReportAction ? [parentReportAction] : []), ...getSortedReportActions(Object.values(reportActions ?? {}))];
for (const action of actions) {
if (!isReportActionVisible(action, reportID, canUserPerformAction, visibleReportActionsData) || isMoneyRequestAction(action)) {
for (const [key, action] of actions.entries()) {
if (!shouldReportActionBeVisible(action, key, canUserPerformAction) || isMoneyRequestAction(action)) {
continue;
}

Expand Down
70 changes: 44 additions & 26 deletions src/components/LHNOptionsList/LHNOptionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses';
import usePrevious from '@hooks/usePrevious';
import useReportAttributes from '@hooks/useReportAttributes';
import useRootNavigationState from '@hooks/useRootNavigationState';
Expand All @@ -24,14 +25,15 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import getPlatform from '@libs/getPlatform';
import Log from '@libs/Log';
import {getIOUReportIDOfLastAction} from '@libs/OptionsListUtils';
import {getLastVisibleActionIncludingTransactionThread, getOriginalMessage, isActionableTrackExpense, isInviteOrRemovedAction, isMoneyRequestAction} from '@libs/ReportActionsUtils';
import {getMovedReportID} from '@libs/ModifiedExpenseMessage';
import {getIOUReportIDOfLastAction, getLastMessageTextForReport} from '@libs/OptionsListUtils';
import {findLastReportActions, getOriginalMessage, isInviteOrRemovedAction, isMoneyRequestAction} from '@libs/ReportActionsUtils';
import {canUserPerformWriteAction as canUserPerformWriteActionUtil} from '@libs/ReportUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Report} from '@src/types/onyx';
import type {PersonalDetails, Report} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import OptionRowLHNData from './OptionRowLHNData';
import OptionRowRendererComponent from './OptionRowRendererComponent';
Expand All @@ -51,6 +53,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
const reportAttributes = useReportAttributes();
const [reportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS);
const [reportMetadataCollection] = useOnyx(ONYXKEYS.COLLECTION.REPORT_METADATA);
const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
const [policy] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
Expand All @@ -61,8 +64,8 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
const [onboarding] = useOnyx(ONYXKEYS.NVP_ONBOARDING);
const [isFullscreenVisible] = useOnyx(ONYXKEYS.FULLSCREEN_VISIBILITY);
const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS);
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
const {policyForMovingExpensesID} = usePolicyForMovingExpenses();

const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -181,6 +184,9 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
}
const itemInvoiceReceiverPolicy = policy?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiverPolicyID}`];

const iouReportIDOfLastAction = getIOUReportIDOfLastAction(item);
const itemIouReportReportActions = iouReportIDOfLastAction ? reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportIDOfLastAction}`] : undefined;

const itemPolicy = policy?.[`${ONYXKEYS.COLLECTION.POLICY}${item?.policyID}`];
const transactionID = isMoneyRequestAction(itemParentReportAction)
? (getOriginalMessage(itemParentReportAction)?.IOUTransactionID ?? CONST.DEFAULT_NUMBER_ID)
Expand All @@ -192,29 +198,42 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio

const isReportArchived = !!itemReportNameValuePairs?.private_isArchived;
const canUserPerformWrite = canUserPerformWriteActionUtil(item, isReportArchived);
const {lastVisibleAction: lastReportAction, lastActionForDisplay: lastAction} = findLastReportActions(itemReportActions, canUserPerformWrite);

const lastAction = getLastVisibleActionIncludingTransactionThread(
reportID,
canUserPerformWrite,
reportActions,
visibleReportActionsData,
itemOneTransactionThreadReport?.reportID,
);

const iouReportIDOfLastAction = getIOUReportIDOfLastAction(item, visibleReportActionsData, lastAction);
const itemIouReportReportActions = iouReportIDOfLastAction ? reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportIDOfLastAction}`] : undefined;

const lastReportActionTransactionID = isMoneyRequestAction(lastAction) ? (getOriginalMessage(lastAction)?.IOUTransactionID ?? CONST.DEFAULT_NUMBER_ID) : CONST.DEFAULT_NUMBER_ID;
// Get the transaction for the last report action
const lastReportActionTransactionID = isMoneyRequestAction(lastReportAction)
? (getOriginalMessage(lastReportAction)?.IOUTransactionID ?? CONST.DEFAULT_NUMBER_ID)
: CONST.DEFAULT_NUMBER_ID;
const lastReportActionTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${lastReportActionTransactionID}`];

// Only override lastMessageTextFromReport when a track expense whisper's transaction has been deleted, to prevent showing stale text.
let lastMessageTextFromReport: string | undefined;
if (isActionableTrackExpense(lastAction)) {
const whisperTransactionID = getOriginalMessage(lastAction)?.transactionID;
if (whisperTransactionID && !transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${whisperTransactionID}`]) {
lastMessageTextFromReport = '';
}
// SidebarUtils.getOptionData in OptionRowLHNData does not get re-evaluated when the linked task report changes, so we have the lastMessageTextFromReport evaluation logic here
let lastActorDetails: Partial<PersonalDetails> | null = item?.lastActorAccountID && personalDetails?.[item.lastActorAccountID] ? personalDetails[item.lastActorAccountID] : null;
if (!lastActorDetails && lastReportAction) {
const lastActorDisplayName = lastReportAction?.person?.[0]?.text;
lastActorDetails = lastActorDisplayName
? {
displayName: lastActorDisplayName,
accountID: item?.lastActorAccountID,
}
: null;
}
const movedFromReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastReportAction, CONST.REPORT.MOVE_TYPE.FROM)}`];
const movedToReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastReportAction, CONST.REPORT.MOVE_TYPE.TO)}`];
const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item?.chatReportID}`];
const itemReportMetadata = reportMetadataCollection?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`];
const lastMessageTextFromReport = getLastMessageTextForReport({
translate,
report: item,
lastActorDetails,
movedFromReport,
movedToReport,
policy: itemPolicy,
isReportArchived: !!itemReportNameValuePairs?.private_isArchived,
policyForMovingExpensesID,
reportMetadata: itemReportMetadata,
chatReport,
reportAttributesDerived: reportAttributes,
});

const shouldShowRBRorGBRTooltip = firstReportIDWithGBRorRBR === reportID;

Expand Down Expand Up @@ -270,12 +289,14 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
reports,
reportNameValuePairs,
reportActions,
reportMetadataCollection,
isOffline,
reportAttributes,
policy,
transactions,
draftComments,
personalDetails,
policyForMovingExpensesID,
firstReportIDWithGBRorRBR,
optionMode,
shouldDisableFocusOptions,
Expand All @@ -291,7 +312,6 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
isScreenFocused,
localeCompare,
translate,
visibleReportActionsData,
currentUserAccountID,
],
);
Expand All @@ -313,7 +333,6 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
isOffline,
isScreenFocused,
isReportsSplitNavigatorLast,
visibleReportActionsData,
],
[
reportActions,
Expand All @@ -331,7 +350,6 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
isOffline,
isScreenFocused,
isReportsSplitNavigatorLast,
visibleReportActionsData,
],
);

Expand Down
6 changes: 3 additions & 3 deletions src/components/LHNOptionsList/OptionRowLHNData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function OptionRowLHNData({

const [movedFromReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastAction, CONST.REPORT.MOVE_TYPE.FROM)}`);
const [movedToReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(lastAction, CONST.REPORT.MOVE_TYPE.TO)}`);
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${fullReport?.chatReportID}`);
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
// Check the report errors equality to avoid re-rendering when there are no changes
const prevReportErrors = usePrevious(reportAttributes?.reportErrors);
Expand Down Expand Up @@ -81,6 +82,7 @@ function OptionRowLHNData({
movedFromReport,
movedToReport,
currentUserAccountID,
chatReport,
reportAttributesDerived,
});
if (deepEqual(item, optionItemRef.current)) {
Expand All @@ -92,7 +94,6 @@ function OptionRowLHNData({
return item;
// Listen parentReportAction to update title of thread report when parentReportAction changed
// Listen to transaction to update title of transaction report when transaction changed
// Listen to lastAction to update when action is deleted or gets pendingAction
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
fullReport,
Expand All @@ -114,14 +115,13 @@ function OptionRowLHNData({
invoiceReceiverPolicy,
lastMessageTextFromReport,
card,
lastAction,
lastActionReport,
translate,
localeCompare,
isReportArchived,
movedFromReport,
movedToReport,
currentUserAccountID,
chatReport,
reportAttributesDerived,
]);

Expand Down
2 changes: 1 addition & 1 deletion src/components/LHNOptionsList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ type OptionRowLHNDataProps = {
viewMode?: OptionMode;

/** The last message text from the report */
lastMessageTextFromReport?: string;
lastMessageTextFromReport: string;

/** A function that is called when an option is selected. Selected option is passed as a param */
onSelectRow?: (optionItem: OptionData, popoverAnchor: RefObject<View | null>) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import {
isCurrentActionUnread,
isDeletedParentAction,
isIOUActionMatchingTransactionList,
isReportActionVisible,
shouldReportActionBeVisible,
wasMessageReceivedWhileOffline,
} from '@libs/ReportActionsUtils';
import {canUserPerformWriteAction, chatIncludesChronosWithID, getOriginalReportID, getReportLastVisibleActionCreated, isHarvestCreatedExpenseReport, isUnread} from '@libs/ReportUtils';
Expand Down Expand Up @@ -186,7 +186,6 @@ function MoneyRequestReportActionsList({

const isReportArchived = useReportIsArchived(reportID);
const canPerformWriteAction = canUserPerformWriteAction(report, isReportArchived);
const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS);

const {shouldUseNarrowLayout} = useResponsiveLayoutOnWideRHP();

Expand Down Expand Up @@ -318,29 +317,17 @@ function MoneyRequestReportActionsList({
const visibleReportActions = useMemo(() => {
const filteredActions = reportActions.filter((reportAction) => {
const isActionVisibleOnMoneyReport = isActionVisibleOnMoneyRequestReport(reportAction, shouldShowHarvestCreatedAction);
if (!isActionVisibleOnMoneyReport) {
return false;
}

const passesOfflineCheck = isOffline || isDeletedParentAction(reportAction) || reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || reportAction.errors;
if (!passesOfflineCheck) {
return false;
}

const actionReportID = reportAction.reportID ?? reportID;
if (!isReportActionVisible(reportAction, actionReportID, canPerformWriteAction, visibleReportActionsData)) {
return false;
}

if (!isIOUActionMatchingTransactionList(reportAction, reportTransactionIDs)) {
return false;
}

return true;
return (
isActionVisibleOnMoneyReport &&
(isOffline || isDeletedParentAction(reportAction) || reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || reportAction.errors) &&
shouldReportActionBeVisible(reportAction, reportAction.reportActionID, canPerformWriteAction) &&
isIOUActionMatchingTransactionList(reportAction, reportTransactionIDs)
);
});

return filteredActions.toReversed();
}, [reportActions, isOffline, canPerformWriteAction, reportTransactionIDs, shouldShowHarvestCreatedAction, visibleReportActionsData, reportID]);
}, [reportActions, isOffline, canPerformWriteAction, reportTransactionIDs, shouldShowHarvestCreatedAction]);

const shouldShowOpenReportLoadingSkeleton = !isOffline && !!showReportActionsLoadingState && visibleReportActions.length === 0;
useEffect(() => {
Expand Down
5 changes: 2 additions & 3 deletions src/components/ParentNavigationSubtitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName';
import Navigation from '@libs/Navigation/Navigation';
import type {RightModalNavigatorParamList} from '@libs/Navigation/types';
import {getReportAction, isReportActionVisible} from '@libs/ReportActionsUtils';
import {getReportAction, shouldReportActionBeVisible} from '@libs/ReportActionsUtils';
import {canUserPerformWriteAction as canUserPerformWriteActionReportUtils, isMoneyRequestReport} from '@libs/ReportUtils';
import CONST from '@src/CONST';
import type {ParentNavigationSummaryParams} from '@src/languages/params';
Expand Down Expand Up @@ -88,7 +88,6 @@ function ParentNavigationSubtitle({
const {translate} = useLocalize();
const [currentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`);
const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS);
const isReportArchived = useReportIsArchived(report?.reportID);
const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report, isReportArchived);
const isReportInRHP = currentRoute.name === SCREENS.RIGHT_MODAL.SEARCH_REPORT;
Expand Down Expand Up @@ -117,7 +116,7 @@ function ParentNavigationSubtitle({

const onPress = () => {
const parentAction = getReportAction(parentReportID, parentReportActionID);
const isVisibleAction = isReportActionVisible(parentAction, parentReportID, canUserPerformWriteAction, visibleReportActionsData);
const isVisibleAction = shouldReportActionBeVisible(parentAction, parentAction?.reportActionID ?? CONST.DEFAULT_NUMBER_ID, canUserPerformWriteAction);

const focusedNavigatorState = currentFocusedNavigator?.state;
const currentReportIndex = focusedNavigatorState?.index;
Expand Down
Loading
Loading