Skip to content
Merged
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
32 changes: 5 additions & 27 deletions src/components/LHNOptionsList/LHNOptionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,13 @@
import Log from '@libs/Log';
import {getMovedReportID} from '@libs/ModifiedExpenseMessage';
import {getIOUReportIDOfLastAction, getLastMessageTextForReport} from '@libs/OptionsListUtils';
import {
getOneTransactionThreadReportID,
getOriginalMessage,
getSortedReportActions,
getSortedReportActionsForDisplay,
isInviteOrRemovedAction,
isMoneyRequestAction,
shouldReportActionBeVisibleAsLastAction,
} from '@libs/ReportActionsUtils';
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 {PersonalDetails, Report, ReportAction} 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 Down Expand Up @@ -175,14 +167,13 @@
const renderItem = useCallback(
({item, index}: RenderItemProps): ReactElement => {
const reportID = item.reportID;
const itemReportAttributes = reportAttributes?.[reportID];
const itemParentReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.parentReportID}`];
const itemReportNameValuePairs = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`];
const chatReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.chatReportID}`];
const itemReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`];
const itemOneTransactionThreadReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getOneTransactionThreadReportID(item, chatReport, itemReportActions, isOffline)}`];
const itemOneTransactionThreadReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${itemReportAttributes?.oneTransactionThreadReportID}`];
Comment thread
BartekObudzinski marked this conversation as resolved.
const itemParentReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${item?.parentReportID}`];
const itemParentReportAction = item?.parentReportActionID ? itemParentReportActions?.[item?.parentReportActionID] : undefined;
const itemReportAttributes = reportAttributes?.[reportID];

let invoiceReceiverPolicyID = '-1';
if (item?.invoiceReceiver && 'policyID' in item.invoiceReceiver) {
Expand All @@ -207,8 +198,7 @@

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

// Get the transaction for the last report action
const lastReportActionTransactionID = isMoneyRequestAction(lastReportAction)
Expand Down Expand Up @@ -245,18 +235,6 @@

const shouldShowRBRorGBRTooltip = firstReportIDWithGBRorRBR === reportID;

let lastAction: ReportAction | undefined;
if (!itemReportActions || !item) {
lastAction = undefined;
} else {
const canUserPerformWriteAction = canUserPerformWriteActionUtil(item, isReportArchived);
const actionsArray = getSortedReportActions(Object.values(itemReportActions));
const reportActionsForDisplay = actionsArray.filter(
(reportAction) => shouldReportActionBeVisibleAsLastAction(reportAction, canUserPerformWriteAction) && reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED,
);
lastAction = reportActionsForDisplay.at(-1);
}

let lastActionReport: OnyxEntry<Report> | undefined;
if (isInviteOrRemovedAction(lastAction)) {
const lastActionOriginalMessage = lastAction?.actionName ? getOriginalMessage(lastAction) : null;
Expand Down Expand Up @@ -305,7 +283,7 @@
/>
);
},
[

Check warning on line 286 in src/components/LHNOptionsList/LHNOptionsList.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useCallback has an unnecessary dependency: 'isOffline'. Either exclude it or remove the dependency array

Check warning on line 286 in src/components/LHNOptionsList/LHNOptionsList.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

React Hook useCallback has an unnecessary dependency: 'isOffline'. Either exclude it or remove the dependency array
reports,
reportNameValuePairs,
reportActions,
Expand Down
7 changes: 2 additions & 5 deletions src/libs/OptionsListUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,13 @@
*/

let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
Onyx.connect({

Check warning on line 201 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function

Check warning on line 201 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (value) => (allPersonalDetails = isEmptyObject(value) ? {} : value),
});

const policies: OnyxCollection<Policy> = {};
Onyx.connect({

Check warning on line 207 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function

Check warning on line 207 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
callback: (policy, key) => {
if (!policy || !key || !policy.name) {
Expand All @@ -216,7 +216,7 @@
});

let allReports: OnyxCollection<Report>;
Onyx.connect({

Check warning on line 219 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function

Check warning on line 219 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -225,7 +225,7 @@
});

let allReportNameValuePairsOnyxConnect: OnyxCollection<ReportNameValuePairs>;
Onyx.connect({

Check warning on line 228 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -237,7 +237,7 @@
const allSortedReportActions: Record<string, ReportAction[]> = {};
let allReportActions: OnyxCollection<ReportActions>;
const lastVisibleReportActions: ReportActions = {};
Onyx.connect({

Check warning on line 240 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand All @@ -260,8 +260,8 @@
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.chatReportID}`];

// If the report is a one-transaction report and has , we need to return the combined reportActions so that the LHN can display modifications
// to the transaction thread or the report itself
// If the report is a one-transaction report, we need to return the combined reportActions so that the LHN can display modifications
// to the transaction thread or the report itself.
const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, actions[reportActions[0]]);
if (transactionThreadReportID) {
const transactionThreadReportActionsArray = Object.values(actions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`] ?? {});
Expand Down Expand Up @@ -299,7 +299,7 @@
});

let activePolicyID: OnyxEntry<string>;
Onyx.connect({

Check warning on line 302 in src/libs/OptionsListUtils/index.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_ACTIVE_POLICY_ID,
callback: (value) => (activePolicyID = value),
});
Expand Down Expand Up @@ -542,9 +542,6 @@
return isSearchStringMatch(searchValue.trim(), memberDetails.toLowerCase());
}

/**
* Get IOU report ID of report last action if the action is report action preview
*/
function getIOUReportIDOfLastAction(report: OnyxEntry<Report>): string | undefined {
if (!report?.reportID) {
return;
Expand Down
71 changes: 71 additions & 0 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
}

let allReportActions: OnyxCollection<ReportActions>;
Onyx.connect({

Check warning on line 80 in src/libs/ReportActionsUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand All @@ -89,7 +89,7 @@
});

let allReports: OnyxCollection<Report>;
Onyx.connect({

Check warning on line 92 in src/libs/ReportActionsUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -98,7 +98,7 @@
});

let isNetworkOffline = false;
Onyx.connect({

Check warning on line 101 in src/libs/ReportActionsUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NETWORK,
callback: (val) => (isNetworkOffline = val?.isOffline ?? false),
});
Expand Down Expand Up @@ -1387,6 +1387,75 @@
return getSortedReportActions(withDEWRoutedActionsArray(baseURLAdjustedReportActions), true);
}

/**
* Returns true if action `a` is newer than action `b`,
* matching getSortedReportActions order (descending by timestamp, with CREATED always oldest).
*/
function isNewerReportAction(a: ReportAction, b: ReportAction): boolean {
Comment thread
JS00001 marked this conversation as resolved.
if (a.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) {
return false;
}
if (b.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) {
return true;
}

// Undefined created is treated as oldest (mirrors getSortedReportActions which places undefined first in ascending order)
if (a.created === undefined && b.created !== undefined) {
return false;
}
if (a.created !== undefined && b.created === undefined) {
return true;
}

if (a.created !== b.created) {
return a.created > b.created;
}

if (a.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && b.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) {
return true;
}
if (b.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && a.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW) {
return false;
}

return a.reportActionID > b.reportActionID;
}

/**
* Finds the newest report action matching each of two filter criteria in a single pass.
* Returns:
* - lastVisibleAction: newest visible action
* - lastActionForDisplay: newest displayable action (not CREATED)
*/
function findLastReportActions(reportActions: OnyxEntry<ReportActions>, canUserPerformWriteAction?: boolean) {
if (!reportActions) {
return {lastVisibleAction: undefined, lastActionForDisplay: undefined};
}

let lastVisibleAction: ReportAction | undefined;
let lastActionForDisplay: ReportAction | undefined;

for (const [key, action] of Object.entries(reportActions)) {
if (!action) {
continue;
}

if (shouldReportActionBeVisible(action, key, canUserPerformWriteAction)) {
if (!lastVisibleAction || isNewerReportAction(action, lastVisibleAction)) {
lastVisibleAction = action;
}
}

if (shouldReportActionBeVisibleAsLastAction(action, canUserPerformWriteAction) && action.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED) {
if (!lastActionForDisplay || isNewerReportAction(action, lastActionForDisplay)) {
lastActionForDisplay = action;
}
}
}

return {lastVisibleAction, lastActionForDisplay};
}

/**
* The first visible action is the second last action in sortedReportActions which satisfy following conditions:
* 1. That is not pending deletion as pending deletion actions are kept in sortedReportActions in memory.
Expand Down Expand Up @@ -4159,6 +4228,7 @@
isAddCommentAction,
isApprovedOrSubmittedReportAction,
isIOURequestReportAction,
isNewerReportAction,
isChronosOOOListAction,
isClosedAction,
isConsecutiveActionMadeByPreviousActor,
Expand Down Expand Up @@ -4244,6 +4314,7 @@
getCardIssuedMessage,
getRemovedConnectionMessage,
getActionableJoinRequestPendingReportAction,
findLastReportActions,
getFilteredReportActionsForReportView,
wasMessageReceivedWhileOffline,
shouldShowAddMissingDetails,
Expand Down
3 changes: 2 additions & 1 deletion src/libs/actions/OnyxDerived/configs/reportAttributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export default createOnyxDerivedValueConfig({
const reportNameValuePair = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`];
const reportActionsList = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`];
const isReportArchived = isArchivedReport(reportNameValuePair);
const {hasAnyViolations, requiresAttention, reportErrors} = generateReportAttributes({
const {hasAnyViolations, requiresAttention, reportErrors, oneTransactionThreadReportID} = generateReportAttributes({
report,
chatReport,
reportActions,
Expand All @@ -227,6 +227,7 @@ export default createOnyxDerivedValueConfig({
brickRoadStatus,
requiresAttention,
reportErrors,
oneTransactionThreadReportID,
};

return acc;
Expand Down
4 changes: 4 additions & 0 deletions src/types/onyx/DerivedValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ type ReportAttributes = {
* The errors of the report.
*/
reportErrors: Errors;
/**
* The reportID of the one-transaction thread report, if applicable.
*/
oneTransactionThreadReportID?: string;
};

/**
Expand Down
Loading
Loading