Skip to content

Commit f9ff2cf

Browse files
authored
Merge pull request Expensify#67132 from nkdengineer/fix/67091
fix: remove call to getReportNameValuePairs() in method findLastAccessedReport
2 parents c1fe251 + 18436be commit f9ff2cf

17 files changed

Lines changed: 209 additions & 88 deletions

File tree

src/hooks/useLastAccessedReport.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {useMemo} from 'react';
2+
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
3+
import {findLastAccessedReport} from '@src/libs/ReportUtils';
4+
import ONYXKEYS from '@src/ONYXKEYS';
5+
import type {Policy, Report, ReportMetadata, ReportNameValuePairs} from '@src/types/onyx';
6+
import mapOnyxCollectionItems from '@src/utils/mapOnyxCollectionItems';
7+
import useOnyx from './useOnyx';
8+
9+
// Optimized selectors based on complete field usage analysis in findLastAccessedReport
10+
type ReportSelector = Pick<Report, 'reportID' | 'lastReadTime' | 'chatType' | 'type' | 'participants' | 'invoiceReceiver' | 'ownerAccountID' | 'parentReportActionID' | 'policyID'>;
11+
12+
type PolicySelector = Pick<Policy, 'id' | 'employeeList'>;
13+
14+
type ReportMetadataSelector = Pick<ReportMetadata, 'lastVisitTime'>;
15+
16+
type ReportNameValuePairsSelector = Pick<ReportNameValuePairs, 'private_isArchived'>;
17+
18+
const reportSelector = (report: OnyxEntry<Report>): ReportSelector =>
19+
(report && {
20+
reportID: report.reportID,
21+
lastReadTime: report.lastReadTime,
22+
chatType: report.chatType,
23+
type: report.type,
24+
participants: report.participants,
25+
invoiceReceiver: report.invoiceReceiver,
26+
ownerAccountID: report.ownerAccountID,
27+
parentReportActionID: report.parentReportActionID,
28+
policyID: report.policyID,
29+
}) as ReportSelector;
30+
31+
const policySelector = (policy: OnyxEntry<Policy>): PolicySelector =>
32+
(policy && {
33+
id: policy.id,
34+
employeeList: policy.employeeList,
35+
}) as PolicySelector;
36+
37+
const reportNameValuePairsSelector = (reportNameValuePairs: OnyxEntry<ReportNameValuePairs>): ReportNameValuePairsSelector =>
38+
(reportNameValuePairs && {
39+
private_isArchived: reportNameValuePairs.private_isArchived,
40+
}) as ReportNameValuePairsSelector;
41+
42+
const reportMetadataSelector = (reportMetadata: OnyxEntry<ReportMetadata>): ReportMetadataSelector =>
43+
(reportMetadata && {
44+
lastVisitTime: reportMetadata.lastVisitTime,
45+
}) as ReportMetadataSelector;
46+
47+
function useLastAccessedReport(ignoreDomainRooms: boolean, openOnAdminRoom = false, policyID?: string, excludeReportID?: string) {
48+
const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {
49+
canBeMissing: true,
50+
selector: (c) => mapOnyxCollectionItems(c, reportSelector),
51+
});
52+
53+
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {
54+
canBeMissing: true,
55+
selector: (c) => mapOnyxCollectionItems(c, policySelector),
56+
});
57+
58+
const [allReportNameValuePairs] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, {
59+
canBeMissing: true,
60+
selector: (c) => mapOnyxCollectionItems(c, reportNameValuePairsSelector),
61+
});
62+
63+
const [allReportMetadata] = useOnyx(ONYXKEYS.COLLECTION.REPORT_METADATA, {
64+
canBeMissing: true,
65+
selector: (c) => mapOnyxCollectionItems(c, reportMetadataSelector),
66+
});
67+
68+
const lastAccessReport = useMemo(() => {
69+
return findLastAccessedReport(
70+
allReports,
71+
allPolicies as OnyxCollection<OnyxEntry<Policy>>,
72+
allReportMetadata,
73+
allReportNameValuePairs,
74+
ignoreDomainRooms,
75+
openOnAdminRoom,
76+
policyID,
77+
excludeReportID,
78+
);
79+
}, [allReports, allPolicies, allReportMetadata, allReportNameValuePairs, ignoreDomainRooms, openOnAdminRoom, policyID, excludeReportID]);
80+
81+
return {lastAccessReport, lastAccessReportID: lastAccessReport?.reportID};
82+
}
83+
84+
export default useLastAccessedReport;

src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, {useState} from 'react';
2+
import useLastAccessedReport from '@hooks/useLastAccessedReport';
23
import usePermissions from '@hooks/usePermissions';
34
import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator';
45
import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper';
@@ -7,7 +8,6 @@ import getCurrentUrl from '@libs/Navigation/currentUrl';
78
import shouldOpenOnAdminRoom from '@libs/Navigation/helpers/shouldOpenOnAdminRoom';
89
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
910
import type {AuthScreensParamList, ReportsSplitNavigatorParamList} from '@libs/Navigation/types';
10-
import * as ReportUtils from '@libs/ReportUtils';
1111
import CONST from '@src/CONST';
1212
import type NAVIGATORS from '@src/NAVIGATORS';
1313
import SCREENS from '@src/SCREENS';
@@ -24,6 +24,7 @@ const Split = createSplitNavigator<ReportsSplitNavigatorParamList>();
2424
function ReportsSplitNavigator({route}: PlatformStackScreenProps<AuthScreensParamList, typeof NAVIGATORS.REPORTS_SPLIT_NAVIGATOR>) {
2525
const {isBetaEnabled} = usePermissions();
2626
const splitNavigatorScreenOptions = useSplitNavigatorScreenOptions();
27+
const {lastAccessReportID} = useLastAccessedReport(!isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS), shouldOpenOnAdminRoom());
2728

2829
const [initialReportID] = useState(() => {
2930
const currentURL = getCurrentUrl();
@@ -32,9 +33,8 @@ function ReportsSplitNavigator({route}: PlatformStackScreenProps<AuthScreensPara
3233
return reportIdFromPath;
3334
}
3435

35-
const initialReport = ReportUtils.findLastAccessedReport(!isBetaEnabled(CONST.BETAS.DEFAULT_ROOMS), shouldOpenOnAdminRoom());
3636
// eslint-disable-next-line rulesdir/no-default-id-values
37-
return initialReport?.reportID ?? '';
37+
return lastAccessReportID ?? '';
3838
});
3939

4040
return (

src/libs/ReportUtils.ts

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,16 +1969,25 @@ function getMostRecentlyVisitedReport(reports: Array<OnyxEntry<Report>>, reportM
19691969
return lodashMaxBy(filteredReports, (a) => [reportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${a?.reportID}`]?.lastVisitTime ?? '', a?.lastReadTime ?? '']);
19701970
}
19711971

1972-
function findLastAccessedReport(ignoreDomainRooms: boolean, openOnAdminRoom = false, policyID?: string, excludeReportID?: string): OnyxEntry<Report> {
1972+
function findLastAccessedReport(
1973+
reports: OnyxCollection<OnyxEntry<Report>>,
1974+
policies: OnyxCollection<OnyxEntry<Policy>>,
1975+
reportMetadata: OnyxCollection<ReportMetadata>,
1976+
reportNameValuePairs: OnyxCollection<ReportNameValuePairs>,
1977+
ignoreDomainRooms: boolean,
1978+
openOnAdminRoom = false,
1979+
policyID?: string,
1980+
excludeReportID?: string,
1981+
): OnyxEntry<Report> {
19731982
// If it's the user's first time using New Expensify, then they could either have:
19741983
// - just a Concierge report, if so we'll return that
19751984
// - their Concierge report, and a separate report that must have deeplinked them to the app before they created their account.
19761985
// If it's the latter, we'll use the deeplinked report over the Concierge report,
19771986
// since the Concierge report would be incorrectly selected over the deep-linked report in the logic below.
19781987

1979-
const policyMemberAccountIDs = getPolicyEmployeeListByIdWithoutCurrentUser(allPolicies, policyID, currentUserAccountID);
1988+
const policyMemberAccountIDs = getPolicyEmployeeListByIdWithoutCurrentUser(policies, policyID, currentUserAccountID);
19801989

1981-
let reportsValues = Object.values(allReports ?? {});
1990+
let reportsValues = Object.values(reports ?? {});
19821991

19831992
if (!!policyID || policyMemberAccountIDs.length > 0) {
19841993
reportsValues = filterReportsByPolicyIDAndMemberAccountIDs(reportsValues, policyMemberAccountIDs, policyID);
@@ -2018,24 +2027,29 @@ function findLastAccessedReport(ignoreDomainRooms: boolean, openOnAdminRoom = fa
20182027
// and it prompts the user to use the Concierge chat instead.
20192028
reportsValues =
20202029
reportsValues.filter((report) => {
2021-
// This will get removed as part of https://github.com/Expensify/App/issues/59961
2022-
// eslint-disable-next-line deprecation/deprecation
2023-
const reportNameValuePairs = getReportNameValuePairs(report?.reportID);
2024-
2025-
return !isSystemChat(report) && !isArchivedReport(reportNameValuePairs);
2030+
return !isSystemChat(report) && !isArchivedReport(reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`]);
20262031
}) ?? [];
20272032

20282033
// At least two reports remain: self DM and Concierge chat.
20292034
// Return the most recently visited report. Get the last read report from the report metadata.
20302035
// If allReportMetadata is empty we'll return most recent report owned by user
2031-
if (isEmptyObject(allReportMetadata)) {
2036+
if (isEmptyObject(reportMetadata)) {
20322037
const ownedReports = reportsValues.filter((report) => report?.ownerAccountID === currentUserAccountID);
20332038
if (ownedReports.length > 0) {
20342039
return lodashMaxBy(ownedReports, (a) => a?.lastReadTime ?? '');
20352040
}
20362041
return lodashMaxBy(reportsValues, (a) => a?.lastReadTime ?? '');
20372042
}
2038-
return getMostRecentlyVisitedReport(reportsValues, allReportMetadata);
2043+
return getMostRecentlyVisitedReport(reportsValues, reportMetadata);
2044+
}
2045+
2046+
/**
2047+
* This function is used to retrieve the last accessed report in background
2048+
* It's used in the case we need to get the last accessed report in a listener like openReportFromDeepLink
2049+
* Please use useLastAccessedReport hook instead if we need to get the last accessed report from the UI
2050+
*/
2051+
function findLastAccessedReportWithoutView(ignoreDomainRooms: boolean, openOnAdminRoom = false, policyID?: string, excludeReportID?: string): OnyxEntry<Report> {
2052+
return findLastAccessedReport(allReports, allPolicies, allReportMetadata, allReportNameValuePair, ignoreDomainRooms, openOnAdminRoom, policyID, excludeReportID);
20392053
}
20402054

20412055
/**
@@ -11671,6 +11685,7 @@ export {
1167111685
isWorkspaceTaskReport,
1167211686
isWorkspaceThread,
1167311687
getReportStatusTranslation,
11688+
findLastAccessedReportWithoutView,
1167411689
};
1167511690

1167611691
export type {

src/libs/actions/Report.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ import {
114114
buildOptimisticSelfDMReport,
115115
buildOptimisticUnreportedTransactionAction,
116116
canUserPerformWriteAction as canUserPerformWriteActionReportUtils,
117-
findLastAccessedReport,
117+
findLastAccessedReportWithoutView,
118118
findSelfDMReportID,
119119
formatReportLastMessageText,
120120
generateReportID,
@@ -3412,7 +3412,7 @@ function openReportFromDeepLink(
34123412
// Navigate to the report after sign-in/sign-up.
34133413
InteractionManager.runAfterInteractions(() => {
34143414
waitForUserSignIn().then(() => {
3415-
const connection = Onyx.connect({
3415+
const connection = Onyx.connectWithoutView({
34163416
key: ONYXKEYS.NVP_ONBOARDING,
34173417
callback: (val) => {
34183418
if (!val && !isAnonymousUser()) {
@@ -3458,7 +3458,7 @@ function openReportFromDeepLink(
34583458
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
34593459
// If the report does not exist, navigate to the last accessed report or Concierge chat
34603460
if (reportID && !report) {
3461-
const lastAccessedReportID = findLastAccessedReport(false, shouldOpenOnAdminRoom(), undefined, reportID)?.reportID;
3461+
const lastAccessedReportID = findLastAccessedReportWithoutView(false, shouldOpenOnAdminRoom(), undefined, reportID)?.reportID;
34623462
if (lastAccessedReportID) {
34633463
const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID);
34643464
Navigation.navigate(lastAccessedReportRoute);
@@ -3504,9 +3504,7 @@ function getCurrentUserEmail(): string | undefined {
35043504
return currentUserEmail;
35053505
}
35063506

3507-
function navigateToMostRecentReport(currentReport: OnyxEntry<Report>) {
3508-
const lastAccessedReportID = findLastAccessedReport(false, false, undefined, currentReport?.reportID)?.reportID;
3509-
3507+
function navigateToMostRecentReport(currentReport: OnyxEntry<Report>, lastAccessedReportID: string | undefined) {
35103508
if (lastAccessedReportID) {
35113509
const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID);
35123510
Navigation.goBack(lastAccessedReportRoute);
@@ -3522,8 +3520,7 @@ function navigateToMostRecentReport(currentReport: OnyxEntry<Report>) {
35223520
}
35233521
}
35243522

3525-
function getMostRecentReportID(currentReport: OnyxEntry<Report>) {
3526-
const lastAccessedReportID = findLastAccessedReport(false, false, undefined, currentReport?.reportID)?.reportID;
3523+
function getMostRecentReportID(lastAccessedReportID: string | undefined) {
35273524
return lastAccessedReportID ?? conciergeReportID;
35283525
}
35293526

@@ -3540,7 +3537,7 @@ function joinRoom(report: OnyxEntry<Report>) {
35403537
);
35413538
}
35423539

3543-
function leaveGroupChat(reportID: string) {
3540+
function leaveGroupChat(reportID: string, lastAccessedReportID: string | undefined) {
35443541
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
35453542
if (!report) {
35463543
Log.warn('Attempting to leave Group Chat that does not existing locally');
@@ -3592,12 +3589,12 @@ function leaveGroupChat(reportID: string) {
35923589
},
35933590
];
35943591

3595-
navigateToMostRecentReport(report);
3592+
navigateToMostRecentReport(report, lastAccessedReportID);
35963593
API.write(WRITE_COMMANDS.LEAVE_GROUP_CHAT, {reportID}, {optimisticData, successData, failureData});
35973594
}
35983595

35993596
/** Leave a report by setting the state to submitted and closed */
3600-
function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = false) {
3597+
function leaveRoom(reportID: string, lastAccessedReportID: string | undefined, isWorkspaceMemberLeavingWorkspaceRoom = false) {
36013598
const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
36023599

36033600
if (!report) {
@@ -3704,7 +3701,7 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal
37043701
return;
37053702
}
37063703
// In other cases, the report is deleted and we should move the user to another report.
3707-
navigateToMostRecentReport(report);
3704+
navigateToMostRecentReport(report, lastAccessedReportID);
37083705
}
37093706

37103707
function buildInviteToRoomOnyxData(reportID: string, inviteeEmailsToAccountIDs: InvitedEmailsToAccountIDs, formatPhoneNumber: LocaleContextProps['formatPhoneNumber']) {

src/libs/actions/Task.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ function getParentReport(report: OnyxEntry<OnyxTypes.Report>): OnyxEntry<OnyxTyp
10451045
* @param report - The task report being deleted
10461046
* @returns The URL to navigate to
10471047
*/
1048-
function getNavigationUrlOnTaskDelete(report: OnyxEntry<OnyxTypes.Report>): string | undefined {
1048+
function getNavigationUrlOnTaskDelete(report: OnyxEntry<OnyxTypes.Report>, lastAccessedReportID: string | undefined): string | undefined {
10491049
if (!report) {
10501050
return undefined;
10511051
}
@@ -1062,7 +1062,7 @@ function getNavigationUrlOnTaskDelete(report: OnyxEntry<OnyxTypes.Report>): stri
10621062
}
10631063

10641064
// If no parent report, try to navigate to most recent report
1065-
const mostRecentReportID = getMostRecentReportID(report);
1065+
const mostRecentReportID = getMostRecentReportID(lastAccessedReportID);
10661066
if (mostRecentReportID) {
10671067
return ROUTES.REPORT_WITH_ID.getRoute(mostRecentReportID);
10681068
}
@@ -1073,7 +1073,7 @@ function getNavigationUrlOnTaskDelete(report: OnyxEntry<OnyxTypes.Report>): stri
10731073
/**
10741074
* Cancels a task by setting the report state to SUBMITTED and status to CLOSED
10751075
*/
1076-
function deleteTask(report: OnyxEntry<OnyxTypes.Report>) {
1076+
function deleteTask(report: OnyxEntry<OnyxTypes.Report>, lastAccessedReportID: string | undefined) {
10771077
if (!report) {
10781078
return;
10791079
}
@@ -1212,7 +1212,7 @@ function deleteTask(report: OnyxEntry<OnyxTypes.Report>) {
12121212
API.write(WRITE_COMMANDS.CANCEL_TASK, parameters, {optimisticData, successData, failureData});
12131213
notifyNewAction(report.reportID, currentUserAccountID);
12141214

1215-
const urlToNavigateBack = getNavigationUrlOnTaskDelete(report);
1215+
const urlToNavigateBack = getNavigationUrlOnTaskDelete(report, lastAccessedReportID);
12161216
if (urlToNavigateBack) {
12171217
Navigation.goBack();
12181218
return urlToNavigateBack;

src/libs/navigateAfterOnboarding.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import type {OnyxEntry} from 'react-native-onyx';
12
import ROUTES from '@src/ROUTES';
3+
import type {Report} from '@src/types/onyx';
24
import {setDisableDismissOnEscape} from './actions/Modal';
3-
import shouldOpenOnAdminRoom from './Navigation/helpers/shouldOpenOnAdminRoom';
45
import Navigation from './Navigation/Navigation';
5-
import {findLastAccessedReport, isConciergeChatReport} from './ReportUtils';
6+
import {isConciergeChatReport} from './ReportUtils';
67

78
const navigateAfterOnboarding = (
89
isSmallScreenWidth: boolean,
9-
canUseDefaultRooms: boolean | undefined,
10+
lastAccessedReport: OnyxEntry<Report>,
1011
onboardingPolicyID?: string,
1112
onboardingAdminsChatReportID?: string,
1213
shouldPreventOpenAdminRoom = false,
@@ -24,7 +25,6 @@ const navigateAfterOnboarding = (
2425
reportID = onboardingAdminsChatReportID;
2526
}
2627
} else {
27-
const lastAccessedReport = findLastAccessedReport(!canUseDefaultRooms, shouldOpenOnAdminRoom() && !shouldPreventOpenAdminRoom);
2828
const lastAccessedReportID = lastAccessedReport?.reportID;
2929
// we don't want to navigate to newly created workspaces after onboarding is completed.
3030
if (lastAccessedReportID && lastAccessedReport.policyID !== onboardingPolicyID && !isConciergeChatReport(lastAccessedReport)) {
@@ -52,13 +52,13 @@ const navigateAfterOnboarding = (
5252

5353
const navigateAfterOnboardingWithMicrotaskQueue = (
5454
isSmallScreenWidth: boolean,
55-
canUseDefaultRooms: boolean | undefined,
55+
lastAccessedReport: OnyxEntry<Report>,
5656
onboardingPolicyID?: string,
5757
onboardingAdminsChatReportID?: string,
5858
shouldPreventOpenAdminRoom = false,
5959
) => {
6060
Navigation.setNavigationActionToMicrotaskQueue(() => {
61-
navigateAfterOnboarding(isSmallScreenWidth, canUseDefaultRooms, onboardingPolicyID, onboardingAdminsChatReportID, shouldPreventOpenAdminRoom);
61+
navigateAfterOnboarding(isSmallScreenWidth, lastAccessedReport, onboardingPolicyID, onboardingAdminsChatReportID, shouldPreventOpenAdminRoom);
6262
});
6363
};
6464

0 commit comments

Comments
 (0)