diff --git a/.github/workflows/reassurePerformanceTests.yml b/.github/workflows/reassurePerformanceTests.yml index a695c0acf942..a2aadc331f19 100644 --- a/.github/workflows/reassurePerformanceTests.yml +++ b/.github/workflows/reassurePerformanceTests.yml @@ -48,12 +48,12 @@ jobs: git fetch origin "$BASELINE_BRANCH" --no-tags --depth=1 git switch "$BASELINE_BRANCH" npm install --force - npx reassure --baseline + NODE_OPTIONS=--experimental-vm-modules npx reassure --baseline git switch --force --detach - git merge --no-commit --allow-unrelated-histories "$BASELINE_BRANCH" -X ours git checkout --ours . npm install --force - npx reassure --branch + NODE_OPTIONS=--experimental-vm-modules npx reassure --branch - name: Validate output.json id: validateReassureOutput diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index a90793857293..6059af105a77 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -3,7 +3,6 @@ import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import {getPolicyEmployeeListByIdWithoutCurrentUser} from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; -import * as ReportUtils from '@libs/ReportUtils'; import SidebarUtils from '@libs/SidebarUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -13,7 +12,6 @@ import useActiveWorkspace from './useActiveWorkspace'; import useCurrentReportID from './useCurrentReportID'; import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; -type ChatReportSelector = OnyxTypes.Report & {isUnreadWithMention: boolean}; type PolicySelector = Pick; type ReportActionsSelector = Array>; @@ -25,56 +23,19 @@ type ReportIDsContextProviderProps = { type ReportIDsContextValue = { orderedReportIDs: string[]; currentReportID: string; + policyMemberAccountIDs: number[]; }; const ReportIDsContext = createContext({ orderedReportIDs: [], currentReportID: '', + policyMemberAccountIDs: [], }); /** * This function (and the few below it), narrow down the data from Onyx to just the properties that we want to trigger a re-render of the component. This helps minimize re-rendering * and makes the entire component more performant because it's not re-rendering when a bunch of properties change which aren't ever used in the UI. */ -const chatReportSelector = (report: OnyxEntry): ChatReportSelector => - (report && { - reportID: report.reportID, - participants: report.participants, - isPinned: report.isPinned, - isHidden: report.isHidden, - notificationPreference: report.notificationPreference, - errorFields: { - addWorkspaceRoom: report.errorFields?.addWorkspaceRoom, - }, - lastMessageText: report.lastMessageText, - lastVisibleActionCreated: report.lastVisibleActionCreated, - iouReportID: report.iouReportID, - total: report.total, - nonReimbursableTotal: report.nonReimbursableTotal, - hasOutstandingChildRequest: report.hasOutstandingChildRequest, - isWaitingOnBankAccount: report.isWaitingOnBankAccount, - statusNum: report.statusNum, - stateNum: report.stateNum, - chatType: report.chatType, - type: report.type, - policyID: report.policyID, - visibility: report.visibility, - lastReadTime: report.lastReadTime, - // Needed for name sorting: - reportName: report.reportName, - policyName: report.policyName, - oldPolicyName: report.oldPolicyName, - // Other less obvious properites considered for sorting: - ownerAccountID: report.ownerAccountID, - currency: report.currency, - managerID: report.managerID, - // Other important less obivous properties for filtering: - parentReportActionID: report.parentReportActionID, - parentReportID: report.parentReportID, - isDeletedParentAction: report.isDeletedParentAction, - isUnreadWithMention: ReportUtils.isUnreadWithMention(report), - }) as ChatReportSelector; - const reportActionsSelector = (reportActions: OnyxEntry): ReportActionsSelector => (reportActions && Object.values(reportActions) @@ -118,7 +79,7 @@ function ReportIDsContextProvider({ currentReportIDForTests, }: ReportIDsContextProviderProps) { const [priorityMode] = useOnyx(ONYXKEYS.NVP_PRIORITY_MODE, {initialValue: CONST.PRIORITY_MODE.DEFAULT}); - const [chatReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {selector: chatReportSelector}); + const [chatReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: policySelector}); const [allReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {selector: reportActionsSelector}); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); @@ -130,7 +91,7 @@ function ReportIDsContextProvider({ const derivedCurrentReportID = currentReportIDForTests ?? currentReportIDValue?.currentReportID; const {activeWorkspaceID} = useActiveWorkspace(); - const policyMemberAccountIDs = getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID); + const policyMemberAccountIDs = useMemo(() => getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID), [policies, activeWorkspaceID, accountID]); const getOrderedReportIDs = useCallback( (currentReportID?: string) => @@ -157,15 +118,16 @@ function ReportIDsContextProvider({ // we first generate the list as if there was no current report, then we check if // the current report is missing from the list, which should very rarely happen. In this // case we re-generate the list a 2nd time with the current report included. - if (derivedCurrentReportID && !orderedReportIDs.includes(derivedCurrentReportID)) { - return {orderedReportIDs: getOrderedReportIDs(derivedCurrentReportID), currentReportID: derivedCurrentReportID ?? '-1'}; + if (derivedCurrentReportID && derivedCurrentReportID !== '-1' && orderedReportIDs.indexOf(derivedCurrentReportID) === -1) { + return {orderedReportIDs: getOrderedReportIDs(derivedCurrentReportID), currentReportID: derivedCurrentReportID ?? '-1', policyMemberAccountIDs}; } return { orderedReportIDs, currentReportID: derivedCurrentReportID ?? '-1', + policyMemberAccountIDs, }; - }, [getOrderedReportIDs, orderedReportIDs, derivedCurrentReportID]); + }, [getOrderedReportIDs, orderedReportIDs, derivedCurrentReportID, policyMemberAccountIDs]); return {children}; } @@ -175,4 +137,4 @@ function useReportIDs() { } export {ReportIDsContext, ReportIDsContextProvider, policySelector, useReportIDs}; -export type {ChatReportSelector, PolicySelector, ReportActionsSelector}; +export type {PolicySelector, ReportActionsSelector}; diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts index dda5427e9c9f..a85db2bc28d8 100644 --- a/src/libs/DistanceRequestUtils.ts +++ b/src/libs/DistanceRequestUtils.ts @@ -1,15 +1,16 @@ -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import type {LocaleContextProps} from '@components/LocaleContextProvider'; import type {RateAndUnit} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {LastSelectedDistanceRates, OnyxInputOrEntry, Report} from '@src/types/onyx'; +import type {LastSelectedDistanceRates, OnyxInputOrEntry} from '@src/types/onyx'; import type {Unit} from '@src/types/onyx/Policy'; import type Policy from '@src/types/onyx/Policy'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as CurrencyUtils from './CurrencyUtils'; import * as PolicyUtils from './PolicyUtils'; +import * as ReportConnection from './ReportConnection'; import * as ReportUtils from './ReportUtils'; type MileageRate = { @@ -28,13 +29,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - const METERS_TO_KM = 0.001; // 1 kilometer is 1000 meters const METERS_TO_MILES = 0.000621371; // There are approximately 0.000621371 miles in a meter @@ -251,6 +245,7 @@ function convertToDistanceInMeters(distance: number, unit: Unit): number { * Returns custom unit rate ID for the distance transaction */ function getCustomUnitRateID(reportID: string) { + const allReports = ReportConnection.getAllReports(); const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; const policy = PolicyUtils.getPolicy(report?.policyID ?? parentReport?.policyID ?? '-1'); diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index efcba4c23204..38562edb7704 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -2,12 +2,13 @@ import Onyx from 'react-native-onyx'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PolicyTagList, Report, ReportAction} from '@src/types/onyx'; +import type {PolicyTagList, ReportAction} from '@src/types/onyx'; import * as CurrencyUtils from './CurrencyUtils'; import DateUtils from './DateUtils'; import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; +import * as ReportConnection from './ReportConnection'; import * as TransactionUtils from './TransactionUtils'; let allPolicyTags: OnyxCollection = {}; @@ -23,13 +24,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - /** * Builds the partial message fragment for a modified field on the expense. */ @@ -116,7 +110,7 @@ function getForReportAction(reportID: string | undefined, reportAction: OnyxEntr return ''; } const reportActionOriginalMessage = ReportActionsUtils.getOriginalMessage(reportAction); - const policyID = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.policyID ?? '-1'; + const policyID = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.policyID ?? '-1'; const removalFragments: string[] = []; const setFragments: string[] = []; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index e9bfb7227403..15d4ac6e4b31 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,10 +1,10 @@ import {findFocusedRoute} from '@react-navigation/core'; import type {EventArg, NavigationContainerEventMap} from '@react-navigation/native'; import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import Onyx from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import Log from '@libs/Log'; import {isCentralPaneName, removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -35,13 +35,6 @@ let pendingRoute: Route | null = null; let shouldPopAllStateOnUP = false; -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - /** * Inform the navigation that next time user presses UP we should pop all the state back to LHN. */ @@ -69,7 +62,7 @@ const dismissModal = (reportID?: string, ref = navigationRef) => { originalDismissModal(ref); return; } - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; originalDismissModalWithReport({reportID, ...report}, ref); }; // Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. diff --git a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts index 18099f157d6a..d60e66f8d535 100644 --- a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts +++ b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts @@ -1,5 +1,4 @@ import Onyx from 'react-native-onyx'; -import type {OnyxCollection} from 'react-native-onyx'; import applyOnyxUpdatesReliably from '@libs/actions/applyOnyxUpdatesReliably'; import * as ActiveClientManager from '@libs/ActiveClientManager'; import Log from '@libs/Log'; @@ -7,13 +6,14 @@ import Navigation from '@libs/Navigation/Navigation'; import type {ReportActionPushNotificationData} from '@libs/Notification/PushNotification/NotificationType'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import {extractPolicyIDFromPath} from '@libs/PolicyUtils'; +import * as ReportConnection from '@libs/ReportConnection'; import {doesReportBelongToWorkspace} from '@libs/ReportUtils'; import Visibility from '@libs/Visibility'; import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {OnyxUpdatesFromServer, Report} from '@src/types/onyx'; +import type {OnyxUpdatesFromServer} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import PushNotification from '..'; @@ -28,13 +28,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - function getLastUpdateIDAppliedToClient(): Promise { return new Promise((resolve) => { Onyx.connect({ @@ -82,7 +75,7 @@ function navigateToReport({reportID, reportActionID}: ReportActionPushNotificati Log.info('[PushNotification] Navigating to report', false, {reportID, reportActionID}); const policyID = lastVisitedPath && extractPolicyIDFromPath(lastVisitedPath); - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const policyEmployeeAccountIDs = policyID ? getPolicyEmployeeAccountIDs(policyID) : []; const reportBelongsToWorkspace = policyID && !isEmptyObject(report) && doesReportBelongToWorkspace(report, policyEmployeeAccountIDs, policyID); diff --git a/src/libs/OnyxAwareParser.ts b/src/libs/OnyxAwareParser.ts index c058775341c2..51ea39ef972a 100644 --- a/src/libs/OnyxAwareParser.ts +++ b/src/libs/OnyxAwareParser.ts @@ -1,23 +1,12 @@ import {ExpensiMark} from 'expensify-common'; import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; +import * as ReportConnection from './ReportConnection'; const parser = new ExpensiMark(); -const reportIDToNameMap: Record = {}; const accountIDToNameMap: Record = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - callback: (report) => { - if (!report) { - return; - } - - reportIDToNameMap[report.reportID] = report.reportName ?? report.displayName ?? report.reportID; - }, -}); - Onyx.connect({ key: ONYXKEYS.PERSONAL_DETAILS_LIST, callback: (personalDetailsList) => { @@ -37,7 +26,11 @@ function parseHtmlToMarkdown( accountIDToName?: Record, cacheVideoAttributes?: (videoSource: string, videoAttrs: string) => void, ): string { - return parser.htmlToMarkdown(html, {reportIDToName: reportIDToName ?? reportIDToNameMap, accountIDToName: accountIDToName ?? accountIDToNameMap, cacheVideoAttributes}); + return parser.htmlToMarkdown(html, { + reportIDToName: reportIDToName ?? ReportConnection.getAllReportsNameMap(), + accountIDToName: accountIDToName ?? accountIDToNameMap, + cacheVideoAttributes, + }); } function parseHtmlToText( @@ -46,7 +39,7 @@ function parseHtmlToText( accountIDToName?: Record, cacheVideoAttributes?: (videoSource: string, videoAttrs: string) => void, ): string { - return parser.htmlToText(html, {reportIDToName: reportIDToName ?? reportIDToNameMap, accountIDToName: accountIDToName ?? accountIDToNameMap, cacheVideoAttributes}); + return parser.htmlToText(html, {reportIDToName: reportIDToName ?? ReportConnection.getAllReportsNameMap(), accountIDToName: accountIDToName ?? accountIDToNameMap, cacheVideoAttributes}); } export {parseHtmlToMarkdown, parseHtmlToText}; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index fc73c85b0354..2c96c526ceea 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -53,6 +53,7 @@ import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as PhoneNumber from './PhoneNumber'; import * as PolicyUtils from './PolicyUtils'; import * as ReportActionUtils from './ReportActionsUtils'; +import * as ReportConnection from './ReportConnection'; import * as ReportUtils from './ReportUtils'; import * as TaskUtils from './TaskUtils'; import * as TransactionUtils from './TransactionUtils'; @@ -339,13 +340,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - let allReportsDraft: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_DRAFT, @@ -357,6 +351,7 @@ Onyx.connect({ * Get the report or draft report given a reportID */ function getReportOrDraftReport(reportID: string | undefined): OnyxEntry { + const allReports = ReportConnection.getAllReports(); if (!allReports && !allReportsDraft) { return undefined; } diff --git a/src/libs/PersonalDetailsUtils.ts b/src/libs/PersonalDetailsUtils.ts index 8bdf0cb1d5fe..9beb3d382696 100644 --- a/src/libs/PersonalDetailsUtils.ts +++ b/src/libs/PersonalDetailsUtils.ts @@ -32,11 +32,16 @@ Onyx.connect({ }, }); +const hiddenTranslation = Localize.translateLocal('common.hidden'); +const youTranslation = Localize.translateLocal('common.you').toLowerCase(); + +const regexMergedAccount = new RegExp(CONST.REGEX.MERGED_ACCOUNT_PREFIX); + function getDisplayNameOrDefault(passedPersonalDetails?: Partial | null, defaultValue = '', shouldFallbackToHidden = true, shouldAddCurrentUserPostfix = false): string { let displayName = passedPersonalDetails?.displayName ?? ''; // If the displayName starts with the merged account prefix, remove it. - if (new RegExp(CONST.REGEX.MERGED_ACCOUNT_PREFIX).test(displayName)) { + if (regexMergedAccount.test(displayName)) { // Remove the merged account prefix from the displayName. displayName = displayName.replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); } @@ -48,7 +53,7 @@ function getDisplayNameOrDefault(passedPersonalDetails?: Partial = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (reports) => { - allReports = reports; - }, -}); - let allReportActions: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS, @@ -378,7 +370,7 @@ function getCombinedReportActions( // Filter out request money actions because we don't want to show any preview actions for one transaction reports const filteredTransactionThreadReportActions = transactionThreadReportActions?.filter((action) => action.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED); - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const isSelfDM = report?.chatType === CONST.REPORT.CHAT_TYPE.SELF_DM; // Filter out request and send money request actions because we don't want to show any preview actions for one transaction reports const filteredReportActions = [...reportActions, ...filteredTransactionThreadReportActions].filter((action) => { @@ -672,8 +664,13 @@ function replaceBaseURLInPolicyChangeLogAction(reportAction: ReportAction): Repo } function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection | OnyxCollectionInputValue = {}): OnyxEntry { - const reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true)); - const visibleReportActions = Object.values(reportActions ?? {}).filter((action): action is ReportAction => shouldReportActionBeVisibleAsLastAction(action)); + let reportActions: Array = []; + if (!_.isEmpty(actionsToMerge)) { + reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true)); + } else { + reportActions = Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}); + } + const visibleReportActions = reportActions.filter((action): action is ReportAction => shouldReportActionBeVisibleAsLastAction(action)); const sortedReportActions = getSortedReportActions(visibleReportActions, true); if (sortedReportActions.length === 0) { return undefined; @@ -835,7 +832,7 @@ function getMostRecentReportActionLastModified(): string { // We might not have actions so we also look at the report objects to see if any have a lastVisibleActionLastModified that is more recent. We don't need to get // any reports that have been updated before either a recently updated report or reportAction as we should be up to date on these - Object.values(allReports ?? {}).forEach((report) => { + Object.values(ReportConnection.getAllReports() ?? {}).forEach((report) => { const reportLastVisibleActionLastModified = report?.lastVisibleActionLastModified ?? report?.lastVisibleActionCreated; if (!reportLastVisibleActionLastModified || reportLastVisibleActionLastModified < mostRecentReportActionLastModified) { return; @@ -906,7 +903,7 @@ function isTaskAction(reportAction: OnyxEntry): boolean { */ function getOneTransactionThreadReportID(reportID: string, reportActions: OnyxEntry | ReportAction[], isOffline: boolean | undefined = undefined): string | undefined { // If the report is not an IOU, Expense report, or Invoice, it shouldn't be treated as one-transaction report. - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (report?.type !== CONST.REPORT.TYPE.IOU && report?.type !== CONST.REPORT.TYPE.EXPENSE && report?.type !== CONST.REPORT.TYPE.INVOICE) { return; } @@ -1337,8 +1334,7 @@ function isActionableJoinRequest(reportAction: OnyxEntry): reportA * @param reportID */ function isActionableJoinRequestPending(reportID: string): boolean { - const sortedReportActions = getSortedReportActions(Object.values(getAllReportActions(reportID))); - const findPendingRequest = sortedReportActions.find( + const findPendingRequest = Object.values(getAllReportActions(reportID)).find( (reportActionItem) => isActionableJoinRequest(reportActionItem) && getOriginalMessage(reportActionItem)?.choice === ('' as JoinWorkspaceResolution), ); return !!findPendingRequest; @@ -1384,7 +1380,7 @@ function wasActionTakenByCurrentUser(reportAction: OnyxInputOrEntry { - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const reportActions = getAllReportActions(report?.reportID ?? ''); const action = Object.values(reportActions ?? {})?.find((reportAction) => { const IOUTransactionID = isMoneyRequestAction(reportAction) ? getOriginalMessage(reportAction)?.IOUTransactionID : -1; diff --git a/src/libs/ReportConnection.ts b/src/libs/ReportConnection.ts new file mode 100644 index 000000000000..86e73229e84b --- /dev/null +++ b/src/libs/ReportConnection.ts @@ -0,0 +1,47 @@ +import type {OnyxCollection} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Report} from '@src/types/onyx'; +import * as PriorityModeActions from './actions/PriorityMode'; +import * as ReportHelperActions from './actions/Report'; + +// Dynamic Import to avoid circular dependency +const UnreadIndicatorUpdaterHelper = () => import('./UnreadIndicatorUpdater'); + +const reportIDToNameMap: Record = {}; +let allReports: OnyxCollection; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (value) => { + allReports = value; + UnreadIndicatorUpdaterHelper().then((module) => { + module.triggerUnreadUpdate(); + }); + // Each time a new report is added we will check to see if the user should be switched + PriorityModeActions.autoSwitchToFocusMode(); + + if (!value) { + return; + } + Object.values(value).forEach((report) => { + if (!report) { + return; + } + reportIDToNameMap[report.reportID] = report.reportName ?? report.displayName ?? report.reportID; + ReportHelperActions.handleReportChanged(report); + }); + }, +}); + +// This function is used to get all reports +function getAllReports() { + return allReports; +} + +// This function is used to get all reports name map +function getAllReportsNameMap() { + return reportIDToNameMap; +} + +export {getAllReports, getAllReportsNameMap}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 342e2439ed66..c90910050ad8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -70,6 +70,7 @@ import * as PhoneNumber from './PhoneNumber'; import * as PolicyUtils from './PolicyUtils'; import type {LastVisibleMessage} from './ReportActionsUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; +import * as ReportConnection from './ReportConnection'; import StringUtils from './StringUtils'; import * as SubscriptionUtils from './SubscriptionUtils'; import * as TransactionUtils from './TransactionUtils'; @@ -473,7 +474,6 @@ let isAnonymousUser = false; const parsedReportActionMessageCache: Record = {}; const defaultAvatarBuildingIconTestID = 'SvgDefaultAvatarBuilding Icon'; - Onyx.connect({ key: ONYXKEYS.SESSION, callback: (value) => { @@ -501,13 +501,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - let allReportsDraft: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_DRAFT, @@ -552,23 +545,6 @@ Onyx.connect({ }, }); -let lastUpdatedReport: OnyxEntry; - -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - callback: (value) => { - if (!value) { - return; - } - - lastUpdatedReport = value; - }, -}); - -function getLastUpdatedReport(): OnyxEntry { - return lastUpdatedReport; -} - function getCurrentUserAvatar(): AvatarSource | undefined { return currentUserPersonalDetails?.avatar; } @@ -585,6 +561,7 @@ function getChatType(report: OnyxInputOrEntry | Participant): ValueOf { + const allReports = ReportConnection.getAllReports(); if (!allReports && !allReportsDraft) { return undefined; } @@ -611,7 +588,7 @@ function getParentReport(report: OnyxEntry): OnyxEntry { if (!report?.parentReportID) { return undefined; } - return allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]; + return ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`]; } /** @@ -652,17 +629,18 @@ function getPolicyType(report: OnyxInputOrEntry, policies: OnyxCollectio return policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]?.type ?? ''; } +const unavailableTranslation = Localize.translateLocal('workspace.common.unavailable'); /** * Get the policy name from a given report */ function getPolicyName(report: OnyxInputOrEntry, returnEmptyIfNotFound = false, policy?: OnyxInputOrEntry): string { - const noPolicyFound = returnEmptyIfNotFound ? '' : Localize.translateLocal('workspace.common.unavailable'); + const noPolicyFound = returnEmptyIfNotFound ? '' : unavailableTranslation; if (isEmptyObject(report)) { return noPolicyFound; } if ((!allPolicies || Object.keys(allPolicies).length === 0) && !report?.policyName) { - return Localize.translateLocal('workspace.common.unavailable'); + return unavailableTranslation; } const finalPolicy = policy ?? allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; @@ -706,7 +684,7 @@ function isExpenseReport(report: OnyxInputOrEntry): boolean { * Checks if a report is an IOU report using report or reportID */ function isIOUReport(reportOrID: OnyxInputOrEntry | string): boolean { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; return report?.type === CONST.REPORT.TYPE.IOU; } @@ -771,7 +749,7 @@ function isReportManager(report: OnyxEntry): boolean { * Checks if the supplied report has been approved */ function isReportApproved(reportOrID: OnyxInputOrEntry | string, parentReportAction: OnyxEntry = undefined): boolean { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; if (!report) { return parentReportAction?.childStateNum === CONST.REPORT.STATE_NUM.APPROVED && parentReportAction?.childStatusNum === CONST.REPORT.STATUS_NUM.APPROVED; } @@ -808,6 +786,7 @@ function hasParticipantInArray(report: OnyxEntry, memberAccountIDs: numb * Whether the Money Request report is settled */ function isSettled(reportID: string | undefined): boolean { + const allReports = ReportConnection.getAllReports(); if (!allReports || !reportID) { return false; } @@ -829,6 +808,7 @@ function isSettled(reportID: string | undefined): boolean { * Whether the current user is the submitter of the report */ function isCurrentUserSubmitter(reportID: string): boolean { + const allReports = ReportConnection.getAllReports(); if (!allReports) { return false; } @@ -891,7 +871,7 @@ function isInvoiceRoom(report: OnyxEntry): boolean { function isInvoiceRoomWithID(reportID?: string): boolean { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; return isInvoiceRoom(report); } @@ -1011,7 +991,7 @@ function isWorkspaceTaskReport(report: OnyxEntry): boolean { if (!isTaskReport(report)) { return false; } - const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; return isPolicyExpenseChat(parentReport); } @@ -1052,13 +1032,12 @@ function isSystemChat(report: OnyxEntry): boolean { * Only returns true if this is our main 1:1 DM report with Concierge. */ function isConciergeChatReport(report: OnyxInputOrEntry): boolean { - const participantAccountIDs = Object.keys(report?.participants ?? {}) - .map(Number) - .filter((accountID) => accountID !== currentUserAccountID); - return participantAccountIDs.length === 1 && participantAccountIDs[0] === CONST.ACCOUNT_ID.CONCIERGE && !isChatThread(report); + const participantAccountIDs = Object.keys(report?.participants ?? {}); + return participantAccountIDs.length === 1 && Number(participantAccountIDs[0]) === CONST.ACCOUNT_ID.CONCIERGE && !isChatThread(report); } function findSelfDMReportID(): string | undefined { + const allReports = ReportConnection.getAllReports(); if (!allReports) { return; } @@ -1266,7 +1245,7 @@ function isArchivedRoom(report: OnyxInputOrEntry, reportNameValuePairs?: */ function isArchivedRoomWithID(reportID?: string) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; return isArchivedRoom(report); } @@ -1398,7 +1377,7 @@ function isChildReport(report: OnyxEntry): boolean { function isExpenseRequest(report: OnyxInputOrEntry): boolean { if (isThread(report)) { const parentReportAction = ReportActionsUtils.getParentReportAction(report); - const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; return isExpenseReport(parentReport) && !isEmptyObject(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction); } return false; @@ -1411,7 +1390,7 @@ function isExpenseRequest(report: OnyxInputOrEntry): boolean { function isIOURequest(report: OnyxInputOrEntry): boolean { if (isThread(report)) { const parentReportAction = ReportActionsUtils.getParentReportAction(report); - const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; return isIOUReport(parentReport) && !isEmptyObject(parentReportAction) && ReportActionsUtils.isTransactionThread(parentReportAction); } return false; @@ -1433,7 +1412,7 @@ function isTrackExpenseReport(report: OnyxInputOrEntry): boolean { * Checks if a report is an IOU or expense request. */ function isMoneyRequest(reportOrID: OnyxEntry | string): boolean { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; return isIOURequest(report) || isExpenseRequest(report); } @@ -1441,7 +1420,7 @@ function isMoneyRequest(reportOrID: OnyxEntry | string): boolean { * Checks if a report is an IOU or expense report. */ function isMoneyRequestReport(reportOrID: OnyxInputOrEntry | string): boolean { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; return isIOUReport(report) || isExpenseReport(report); } @@ -1668,7 +1647,7 @@ function getReportRecipientAccountIDs(report: OnyxEntry, currentLoginAcc // In 1:1 chat threads, the participants will be the same as parent report. If a report is specifically a 1:1 chat thread then we will // get parent report and use its participants array. if (isThread(report) && !(isTaskReport(report) || isMoneyRequestReport(report))) { - const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; + const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`]; if (isOneOnOneChat(parentReport)) { finalReport = parentReport; } @@ -1857,6 +1836,7 @@ function getPersonalDetailsForAccountID(accountID: number): Partial | string, shouldUseShortDisplayName = true, ): string { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; const submitterDisplayName = getDisplayNameForParticipant(report?.ownerAccountID, shouldUseShortDisplayName) ?? ''; const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); let messageKey: TranslationPaths; @@ -2238,7 +2218,7 @@ function getReimbursementDeQueuedActionMessage( reportOrID: OnyxEntry | string, isLHNPreview = false, ): string { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction); const amount = originalMessage?.amount; const currency = originalMessage?.currency; @@ -2392,7 +2372,7 @@ function hasNonReimbursableTransactions(iouReportID: string | undefined): boolea } function getMoneyRequestSpendBreakdown(report: OnyxInputOrEntry, allReportsDict?: OnyxCollection): SpendBreakdown { - const allAvailableReports = allReportsDict ?? allReports; + const allAvailableReports = allReportsDict ?? ReportConnection.getAllReports(); let moneyRequestReport; if (isMoneyRequestReport(report) || isInvoiceReport(report)) { moneyRequestReport = report; @@ -2739,7 +2719,7 @@ function canEditFieldOfMoneyRequest(reportAction: OnyxInputOrEntry } const iouMessage = ReportActionsUtils.getOriginalMessage(reportAction); - const moneyRequestReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); + const moneyRequestReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${iouMessage?.IOUReportID}`] ?? ({} as Report); const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${iouMessage?.IOUTransactionID}`] ?? ({} as Transaction); if (isSettled(String(moneyRequestReport.reportID)) || isReportApproved(String(moneyRequestReport.reportID))) { @@ -2987,7 +2967,7 @@ function getReportPreviewMessage( isForListPreview = false, originalReportAction: OnyxInputOrEntry = iouReportAction, ): string { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; const reportActionMessage = ReportActionsUtils.getReportActionHtml(iouReportAction); if (isEmptyObject(report) || !report?.reportID) { @@ -3455,10 +3435,13 @@ function getReportName(report: OnyxEntry, policy?: OnyxEntry, pa } // Not a room or PolicyExpenseChat, generate title from first 5 other participants - const participantsWithoutCurrentUser = Object.keys(report?.participants ?? {}) - .map(Number) - .filter((accountID) => accountID !== currentUserAccountID) - .slice(0, 5); + const participantsWithoutCurrentUser: number[] = []; + Object.keys(report?.participants ?? {}).forEach((accountID) => { + const accID = Number(accountID); + if (accID !== currentUserAccountID && participantsWithoutCurrentUser.length < 5) { + participantsWithoutCurrentUser.push(accID); + } + }); const isMultipleParticipantReport = participantsWithoutCurrentUser.length > 1; return participantsWithoutCurrentUser.map((accountID) => getDisplayNameForParticipant(accountID, isMultipleParticipantReport)).join(', '); } @@ -3959,7 +3942,7 @@ function buildOptimisticInvoiceReport(chatReportID: string, policyID: string, re function buildOptimisticExpenseReport(chatReportID: string, policyID: string, payeeAccountID: number, total: number, currency: string, reimbursable = true): OptimisticExpenseReport { // The amount for Expense reports are stored as negative value in the database const storedTotal = total * -1; - const policyName = getPolicyName(allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]); + const policyName = getPolicyName(ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`]); const formattedTotal = CurrencyUtils.convertToDisplayString(storedTotal, currency); const policy = getPolicy(policyID); @@ -5219,7 +5202,7 @@ function isUnread(report: OnyxEntry): boolean { } function isIOUOwnedByCurrentUser(report: OnyxEntry, allReportsDict?: OnyxCollection): boolean { - const allAvailableReports = allReportsDict ?? allReports; + const allAvailableReports = allReportsDict ?? ReportConnection.getAllReports(); if (!report || !allAvailableReports) { return false; } @@ -5382,15 +5365,13 @@ function shouldReportBeInOptionList({ // This can also happen for anyone accessing a public room or archived room for which they don't have access to the underlying policy. // Optionally exclude reports that do not belong to currently active workspace - const participantAccountIDs = Object.keys(report?.participants ?? {}).map(Number); - if ( !report?.reportID || !report?.type || report?.reportName === undefined || // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing report?.isHidden || - (participantAccountIDs.length === 0 && + (!report?.participants && !isChatThread(report) && !isPublicRoom(report) && !isUserCreatedPolicyRoom(report) && @@ -5405,7 +5386,7 @@ function shouldReportBeInOptionList({ return false; } - if (participantAccountIDs.includes(CONST.ACCOUNT_ID.NOTIFICATIONS) && (!currentUserAccountID || !AccountUtils.isAccountIDOddNumber(currentUserAccountID))) { + if (report?.participants?.[CONST.ACCOUNT_ID.NOTIFICATIONS] && (!currentUserAccountID || !AccountUtils.isAccountIDOddNumber(currentUserAccountID))) { return false; } @@ -5501,6 +5482,7 @@ function shouldReportBeInOptionList({ * Returns the system report from the list of reports. */ function getSystemChat(): OnyxEntry { + const allReports = ReportConnection.getAllReports(); if (!allReports) { return undefined; } @@ -5511,7 +5493,7 @@ function getSystemChat(): OnyxEntry { /** * Attempts to find a report in onyx with the provided list of participants. Does not include threads, task, expense, room, and policy expense chat. */ -function getChatByParticipants(newParticipantList: number[], reports: OnyxCollection = allReports, shouldIncludeGroupChats = false): OnyxEntry { +function getChatByParticipants(newParticipantList: number[], reports: OnyxCollection = ReportConnection.getAllReports(), shouldIncludeGroupChats = false): OnyxEntry { const sortedNewParticipantList = newParticipantList.sort(); return Object.values(reports ?? {}).find((report) => { const participantAccountIDs = Object.keys(report?.participants ?? {}); @@ -5539,7 +5521,7 @@ function getChatByParticipants(newParticipantList: number[], reports: OnyxCollec /** * Attempts to find an invoice chat report in onyx with the provided policyID and receiverID. */ -function getInvoiceChatByParticipants(policyID: string, receiverID: string | number, reports: OnyxCollection = allReports): OnyxEntry { +function getInvoiceChatByParticipants(policyID: string, receiverID: string | number, reports: OnyxCollection = ReportConnection.getAllReports()): OnyxEntry { return Object.values(reports ?? {}).find((report) => { if (!report || !isInvoiceRoom(report)) { return false; @@ -5558,7 +5540,7 @@ function getInvoiceChatByParticipants(policyID: string, receiverID: string | num * Attempts to find a policy expense report in onyx that is owned by ownerAccountID in a given policy */ function getPolicyExpenseChat(ownerAccountID: number, policyID: string): OnyxEntry { - return Object.values(allReports ?? {}).find((report: OnyxEntry) => { + return Object.values(ReportConnection.getAllReports() ?? {}).find((report: OnyxEntry) => { // If the report has been deleted, then skip it if (!report) { return false; @@ -5569,7 +5551,7 @@ function getPolicyExpenseChat(ownerAccountID: number, policyID: string): OnyxEnt } function getAllPolicyReports(policyID: string): Array> { - return Object.values(allReports ?? {}).filter((report) => report?.policyID === policyID); + return Object.values(ReportConnection.getAllReports() ?? {}).filter((report) => report?.policyID === policyID); } /** @@ -5582,7 +5564,7 @@ function chatIncludesChronos(report: OnyxInputOrEntry): boolean { function chatIncludesChronosWithID(reportID?: string): boolean { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID || -1}`]; return chatIncludesChronos(report); } @@ -5732,7 +5714,7 @@ function getReportIDFromLink(url: string | null): string { */ function hasIOUWaitingOnCurrentUserBankAccount(chatReport: OnyxInputOrEntry): boolean { if (chatReport?.iouReportID) { - const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport?.iouReportID}`]; + const iouReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport?.iouReportID}`]; if (iouReport?.isWaitingOnBankAccount && iouReport?.ownerAccountID === currentUserAccountID) { return true; } @@ -6053,6 +6035,7 @@ function shouldReportShowSubscript(report: OnyxEntry): boolean { * Return true if reports data exists */ function isReportDataReady(): boolean { + const allReports = ReportConnection.getAllReports(); return !isEmptyObject(allReports) && Object.keys(allReports ?? {}).some((key) => allReports?.[key]?.reportID); } @@ -6076,7 +6059,7 @@ function getAddWorkspaceRoomOrChatReportErrors(report: OnyxEntry): Error * Return true if the expense report is marked for deletion. */ function isMoneyRequestReportPendingDeletion(reportOrID: OnyxEntry | string): boolean { - const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; + const report = typeof reportOrID === 'string' ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] : reportOrID; if (!isMoneyRequestReport(report)) { return false; } @@ -6104,7 +6087,9 @@ function getOriginalReportID(reportID: string, reportAction: OnyxInputOrEntry, policy: OnyxEntry, } function getWorkspaceChats(policyID: string, accountIDs: number[]): Array> { + const allReports = ReportConnection.getAllReports(); return Object.values(allReports ?? {}).filter((report) => isPolicyExpenseChat(report) && (report?.policyID ?? '-1') === policyID && accountIDs.includes(report?.ownerAccountID ?? -1)); } @@ -6147,6 +6133,7 @@ function getWorkspaceChats(policyID: string, accountIDs: number[]): Array> { + const allReports = ReportConnection.getAllReports(); return Object.values(allReports ?? {}).filter((report) => (report?.policyID ?? '-1') === policyID); } @@ -6451,7 +6438,7 @@ function shouldUseFullTitleToDisplay(report: OnyxEntry): boolean { } function getRoom(type: ValueOf, policyID: string): OnyxEntry { - const room = Object.values(allReports ?? {}).find((report) => report?.policyID === policyID && report?.chatType === type && !isThread(report)); + const room = Object.values(ReportConnection.getAllReports() ?? {}).find((report) => report?.policyID === policyID && report?.chatType === type && !isThread(report)); return room; } @@ -6817,7 +6804,7 @@ function shouldCreateNewMoneyRequestReport(existingIOUReport: OnyxInputOrEntry report && report?.[reportFieldToCompare] === tripRoomReportID) .map((report) => report?.reportID); return tripTransactionReportIDs.flatMap((reportID) => TransactionUtils.getAllReportTransactions(reportID)); @@ -7013,6 +7000,7 @@ function canReportBeMentionedWithinPolicy(report: OnyxEntry, policyID: s } function shouldShowMerchantColumn(transactions: Transaction[]) { + const allReports = ReportConnection.getAllReports(); return transactions.some((transaction) => isExpenseReport(allReports?.[transaction.reportID] ?? null)); } @@ -7027,11 +7015,11 @@ function isChatUsedForOnboarding(report: OnyxEntry): boolean { * Get the report (system or concierge chat) used for the user's onboarding process. */ function getChatUsedForOnboarding(): OnyxEntry { - return Object.values(allReports ?? {}).find(isChatUsedForOnboarding); + return Object.values(ReportConnection.getAllReports() ?? {}).find(isChatUsedForOnboarding); } function findPolicyExpenseChatByPolicyID(policyID: string): OnyxEntry { - return Object.values(allReports ?? {}).find((report) => isPolicyExpenseChat(report) && report?.policyID === policyID); + return Object.values(ReportConnection.getAllReports() ?? {}).find((report) => isPolicyExpenseChat(report) && report?.policyID === policyID); } export { @@ -7127,7 +7115,6 @@ export { getIcons, getIconsForParticipants, getIndicatedMissingPaymentMethod, - getLastUpdatedReport, getLastVisibleMessage, getMoneyRequestOptions, getMoneyRequestSpendBreakdown, diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 3f7ee1b167c2..4f227e04482a 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -1,7 +1,7 @@ import {Str} from 'expensify-common'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type {ChatReportSelector, PolicySelector, ReportActionsSelector} from '@hooks/useReportIDs'; +import type {PolicySelector, ReportActionsSelector} from '@hooks/useReportIDs'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, PersonalDetailsList, ReportActions, TransactionViolation} from '@src/types/onyx'; @@ -68,7 +68,7 @@ type MiniReport = { */ function getOrderedReportIDs( currentReportId: string | null, - allReports: OnyxCollection, + allReports: OnyxCollection, betas: OnyxEntry, policies: OnyxCollection, priorityMode: OnyxEntry, @@ -82,7 +82,7 @@ function getOrderedReportIDs( const allReportsDictValues = Object.values(allReports ?? {}); // Filter out all the reports that shouldn't be displayed - let reportsToDisplay: Array = []; + let reportsToDisplay: Array = []; allReportsDictValues.forEach((report) => { if (!report) { return; diff --git a/src/libs/TaskUtils.ts b/src/libs/TaskUtils.ts index 332d82915463..bd0bd10cd83e 100644 --- a/src/libs/TaskUtils.ts +++ b/src/libs/TaskUtils.ts @@ -1,21 +1,11 @@ -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import Onyx from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Report} from '@src/types/onyx'; import type {Message} from '@src/types/onyx/ReportAction'; import type ReportAction from '@src/types/onyx/ReportAction'; import * as Localize from './Localize'; import {getReportActionHtml, getReportActionText} from './ReportActionsUtils'; - -let allReports: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (reports) => { - allReports = reports; - }, -}); +import * as ReportConnection from './ReportConnection'; /** * Given the Task reportAction name, return the appropriate message to be displayed and copied to clipboard. @@ -39,7 +29,7 @@ function getTaskReportActionMessage(action: OnyxEntry): Pick = {}; Onyx.connect({ @@ -37,13 +38,6 @@ Onyx.connect({ callback: (value) => (allTransactionViolations = value), }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - let currentUserEmail = ''; let currentUserAccountID = -1; Onyx.connect({ @@ -197,6 +191,7 @@ function isCreatedMissing(transaction: OnyxEntry) { } function areRequiredFieldsEmpty(transaction: OnyxEntry): boolean { + const allReports = ReportConnection.getAllReports(); const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] ?? null; const isFromExpenseReport = parentReport?.type === CONST.REPORT.TYPE.EXPENSE; const isSplitPolicyExpenseChat = !!transaction?.comment?.splits?.some((participant) => allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]?.isOwnPolicyExpenseChat); @@ -908,7 +903,7 @@ function compareDuplicateTransactionFields(transactionID: string): {keep: Partia } function getTransactionID(threadReportID: string): string { - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${threadReportID}`] ?? null; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${threadReportID}`] ?? null; const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? ''); const IOUTransactionID = ReportActionsUtils.isMoneyRequestAction(parentReportAction) ? ReportActionsUtils.getOriginalMessage(parentReportAction)?.IOUTransactionID ?? '-1' : '-1'; diff --git a/src/libs/UnreadIndicatorUpdater/index.ts b/src/libs/UnreadIndicatorUpdater/index.ts index 7698433c33c1..2546225bd6ea 100644 --- a/src/libs/UnreadIndicatorUpdater/index.ts +++ b/src/libs/UnreadIndicatorUpdater/index.ts @@ -1,17 +1,14 @@ import debounce from 'lodash/debounce'; import memoize from 'lodash/memoize'; import type {OnyxCollection} from 'react-native-onyx'; -import Onyx from 'react-native-onyx'; +import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import Navigation, {navigationRef} from '@navigation/Navigation'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import type {Report} from '@src/types/onyx'; import updateUnread from './updateUnread'; -let allReports: OnyxCollection = {}; - -export default function getUnreadReportsForUnreadIndicator(reports: OnyxCollection, currentReportID: string) { +function getUnreadReportsForUnreadIndicator(reports: OnyxCollection, currentReportID: string) { return Object.values(reports ?? {}).filter( (report) => ReportUtils.isUnread(report) && @@ -40,23 +37,16 @@ export default function getUnreadReportsForUnreadIndicator(reports: OnyxCollecti const memoizedGetUnreadReportsForUnreadIndicator = memoize(getUnreadReportsForUnreadIndicator); const triggerUnreadUpdate = debounce(() => { - const currentReportID = navigationRef.isReady() ? Navigation.getTopmostReportId() ?? '-1' : '-1'; + const currentReportID = navigationRef?.isReady?.() ? Navigation.getTopmostReportId() ?? '-1' : '-1'; // We want to keep notification count consistent with what can be accessed from the LHN list - const unreadReports = memoizedGetUnreadReportsForUnreadIndicator(allReports, currentReportID); + const unreadReports = memoizedGetUnreadReportsForUnreadIndicator(ReportConnection.getAllReports(), currentReportID); updateUnread(unreadReports.length); }, CONST.TIMING.UNREAD_UPDATE_DEBOUNCE_TIME); -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (reportsFromOnyx) => { - allReports = reportsFromOnyx; - triggerUnreadUpdate(); - }, -}); - -navigationRef.addListener('state', () => { +navigationRef?.addListener?.('state', () => { triggerUnreadUpdate(); }); + +export {triggerUnreadUpdate, getUnreadReportsForUnreadIndicator}; diff --git a/src/libs/WorkspacesSettingsUtils.ts b/src/libs/WorkspacesSettingsUtils.ts index 62c034145d4b..d827a6cae000 100644 --- a/src/libs/WorkspacesSettingsUtils.ts +++ b/src/libs/WorkspacesSettingsUtils.ts @@ -10,20 +10,13 @@ import * as CurrencyUtils from './CurrencyUtils'; import type {Phrase, PhraseParameters} from './Localize'; import * as OptionsListUtils from './OptionsListUtils'; import {hasCustomUnitsError, hasEmployeeListError, hasPolicyError, hasTaxRateError} from './PolicyUtils'; +import * as ReportConnection from './ReportConnection'; import * as ReportUtils from './ReportUtils'; type CheckingMethod = () => boolean; -let allReports: OnyxCollection; - type BrickRoad = ValueOf | undefined; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - let allPolicies: OnyxCollection; Onyx.connect({ @@ -100,6 +93,7 @@ function hasWorkspaceSettingsRBR(policy: Policy) { } function getChatTabBrickRoad(policyID?: string): BrickRoad | undefined { + const allReports = ReportConnection.getAllReports(); if (!allReports) { return undefined; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 48c70021cacc..0d24d973313a 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -42,6 +42,7 @@ import Permissions from '@libs/Permissions'; import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import * as ReportConnection from '@libs/ReportConnection'; import type {OptimisticChatReport, OptimisticCreatedReportAction, OptimisticIOUReportAction, TransactionDetails} from '@libs/ReportUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; @@ -165,13 +166,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection | null = null; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value ?? null), -}); - let allReportsDraft: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT_DRAFT, @@ -295,6 +289,7 @@ Onyx.connect({ * Get the report or draft report given a reportID */ function getReportOrDraftReport(reportID: string | undefined): OnyxEntry { + const allReports = ReportConnection.getAllReports(); if (!allReports && !allReportsDraft) { return undefined; } @@ -502,7 +497,7 @@ function buildOnyxDataForMoneyRequest( if (TransactionUtils.isDistanceRequest(transaction)) { newQuickAction = CONST.QUICK_ACTIONS.REQUEST_DISTANCE; } - const existingTransactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; + const existingTransactionThreadReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; if (chatReport) { optimisticData.push({ @@ -1218,7 +1213,7 @@ function buildOnyxDataForTrackExpense( } else if (isDistanceRequest) { newQuickAction = CONST.QUICK_ACTIONS.TRACK_DISTANCE; } - const existingTransactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; + const existingTransactionThreadReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingTransactionThreadReportID}`] ?? null; if (chatReport) { optimisticData.push( @@ -1573,6 +1568,7 @@ function getDeleteTrackExpenseInformation( actionableWhisperReportActionID = '', resolution = '', ) { + const allReports = ReportConnection.getAllReports(); // STEP 1: Get all collections we're updating const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -1916,6 +1912,7 @@ function getMoneyRequestInformation( let isNewChatReport = false; let chatReport = !isEmptyObject(parentChatReport) && parentChatReport?.reportID ? parentChatReport : null; + const allReports = ReportConnection.getAllReports(); // If this is a policyExpenseChat, the chatReport must exist and we can get it from Onyx. // report is null if the flow is initiated from the global create menu. However, participant always stores the reportID if it exists, which is the case for policyExpenseChats if (!chatReport && isPolicyExpenseChat) { @@ -2132,7 +2129,7 @@ function getTrackExpenseInformation( // STEP 1: Get existing chat report let chatReport = !isEmptyObject(parentChatReport) && parentChatReport?.reportID ? parentChatReport : null; - + const allReports = ReportConnection.getAllReports(); // The chatReport always exists, and we can get it from Onyx if chatReport is null. if (!chatReport) { chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.reportID}`] ?? null; @@ -2491,6 +2488,7 @@ function getUpdateMoneyRequestParams( const clearedPendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, null])); const errorFields = Object.fromEntries(Object.keys(pendingFields).map((key) => [key, {[DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage')}])); + const allReports = ReportConnection.getAllReports(); // Step 2: Get all the collections being updated const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -2779,6 +2777,7 @@ function getUpdateTrackExpenseParams( const clearedPendingFields = Object.fromEntries(Object.keys(transactionChanges).map((key) => [key, null])); const errorFields = Object.fromEntries(Object.keys(pendingFields).map((key) => [key, {[DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericEditFailureMessage')}])); + const allReports = ReportConnection.getAllReports(); // Step 2: Get all the collections being updated const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const transaction = allTransactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -2945,6 +2944,7 @@ function updateMoneyRequestDate( const transactionChanges: TransactionChanges = { created: value, }; + const allReports = ReportConnection.getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -2985,6 +2985,7 @@ function updateMoneyRequestMerchant( const transactionChanges: TransactionChanges = { merchant: value, }; + const allReports = ReportConnection.getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -3073,6 +3074,7 @@ function updateMoneyRequestDistance({ waypoints, routes, }; + const allReports = ReportConnection.getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -3113,6 +3115,7 @@ function updateMoneyRequestDescription( const transactionChanges: TransactionChanges = { comment, }; + const allReports = ReportConnection.getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -3781,7 +3784,7 @@ function getOrCreateOptimisticSplitChatReport(existingSplitChatReportID: string, const existingChatReportID = existingSplitChatReportID || participants[0].reportID; // Check if the report is available locally if we do have one - let existingSplitChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; + let existingSplitChatReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${existingChatReportID}`]; const allParticipantsAccountIDs = [...participantAccountIDs, currentUserAccountID]; if (!existingSplitChatReport) { @@ -4073,7 +4076,9 @@ function createSplitsAndOnyxData( } // STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one - let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null; + let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID + ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] + : null; const shouldCreateNewOneOnOneIOUReport = ReportUtils.shouldCreateNewMoneyRequestReport(oneOnOneIOUReport, oneOnOneChatReport); if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) { @@ -4805,6 +4810,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA let oneOnOneChatReport: OnyxEntry; let isNewOneOnOneChatReport = false; + const allReports = ReportConnection.getAllReports(); if (isPolicyExpenseChat) { // The workspace chat reportID is saved in the splits array when starting a split expense with a workspace oneOnOneChatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]; @@ -4962,6 +4968,7 @@ function editRegularMoneyRequest( policyTags: OnyxTypes.PolicyTagList, policyCategories: OnyxTypes.PolicyCategories, ) { + const allReports = ReportConnection.getAllReports(); // STEP 1: Get all collections we're updating const transactionThread = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -5262,6 +5269,7 @@ function updateMoneyRequestAmountAndCurrency({ taxCode, taxAmount, }; + const allReports = ReportConnection.getAllReports(); const transactionThreadReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReportID}`] ?? null; const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transactionThreadReport?.parentReportID}`] ?? null; let data: UpdateMoneyRequestData; @@ -5275,6 +5283,7 @@ function updateMoneyRequestAmountAndCurrency({ } function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { + const allReports = ReportConnection.getAllReports(); // STEP 1: Get all collections we're updating const iouReportID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID : '-1'; const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null; @@ -5586,7 +5595,7 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor function deleteTrackExpense(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) { // STEP 1: Get all collections we're updating - const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; + const chatReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`] ?? null; if (!ReportUtils.isSelfDM(chatReport)) { return deleteMoneyRequest(transactionID, reportAction, isSingleTransactionView); } diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index acd42b6202c7..33d906652af6 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -51,6 +51,7 @@ import * as PhoneNumber from '@libs/PhoneNumber'; import * as PolicyUtils from '@libs/PolicyUtils'; import {navigateWhenEnableFeature} from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; @@ -125,13 +126,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - let lastAccessedWorkspacePolicyID: OnyxEntry; Onyx.connect({ key: ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID, @@ -259,7 +253,7 @@ function deleteWorkspace(policyID: string, policyName: string) { : []), ]; - const reportsToArchive = Object.values(allReports ?? {}).filter( + const reportsToArchive = Object.values(ReportConnection.getAllReports() ?? {}).filter( (report) => report?.policyID === policyID && (ReportUtils.isChatRoom(report) || ReportUtils.isPolicyExpenseChat(report) || ReportUtils.isTaskReport(report)), ); const finallyData: OnyxUpdate[] = []; diff --git a/src/libs/actions/PriorityMode.ts b/src/libs/actions/PriorityMode.ts index a4561d44d5a0..beec327a2e40 100644 --- a/src/libs/actions/PriorityMode.ts +++ b/src/libs/actions/PriorityMode.ts @@ -1,11 +1,10 @@ import debounce from 'lodash/debounce'; -import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import Log from '@libs/Log'; +import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Report} from '@src/types/onyx'; /** * This actions file is used to automatically switch a user into #focus mode when they exceed a certain number of reports. We do this primarily for performance reasons. @@ -35,18 +34,6 @@ Onyx.connect({ // eslint-disable-next-line @typescript-eslint/no-use-before-define const autoSwitchToFocusMode = debounce(tryFocusModeUpdate, 300, {leading: true}); -let allReports: OnyxCollection | undefined = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (reports) => { - allReports = reports; - - // Each time a new report is added we will check to see if the user should be switched - autoSwitchToFocusMode(); - }, -}); - let isLoadingReportData = true; Onyx.connect({ key: ONYXKEYS.IS_LOADING_REPORT_DATA, @@ -87,11 +74,10 @@ function resetHasReadRequiredDataFromStorage() { resolveIsReadyPromise = resolve; }); isLoadingReportData = true; - allReports = {}; } function checkRequiredData() { - if (allReports === undefined || hasTriedFocusMode === undefined || isInFocusMode === undefined || isLoadingReportData) { + if (ReportConnection.getAllReports() === undefined || hasTriedFocusMode === undefined || isInFocusMode === undefined || isLoadingReportData) { return; } @@ -112,6 +98,7 @@ function tryFocusModeUpdate() { } const validReports = []; + const allReports = ReportConnection.getAllReports(); Object.keys(allReports ?? {}).forEach((key) => { const report = allReports?.[key]; if (!report) { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index a1a52b64d49f..4d674726540a 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -70,6 +70,7 @@ import {extractPolicyIDFromPath} from '@libs/PolicyUtils'; import processReportIDDeeplink from '@libs/processReportIDDeeplink'; import * as Pusher from '@libs/Pusher/pusher'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import {doesReportBelongToWorkspace} from '@libs/ReportUtils'; import type {OptimisticAddCommentReportAction} from '@libs/ReportUtils'; @@ -190,20 +191,6 @@ Onyx.connect({ }, }); -const currentReportData: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - callback: (report, key) => { - if (!key || !report) { - return; - } - const reportID = CollectionUtils.extractCollectionItemID(key); - currentReportData[reportID] = report; - // eslint-disable-next-line @typescript-eslint/no-use-before-define - handleReportChanged(report); - }, -}); - let isNetworkOffline = false; let networkStatus: NetworkStatus; Onyx.connect({ @@ -242,7 +229,6 @@ Onyx.connect({ callback: (value) => (reportMetadata = value), }); -const allReports: OnyxCollection = {}; const typingWatchTimers: Record = {}; let reportIDDeeplinkedFromOldDot: string | undefined; @@ -493,7 +479,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { lastReadTime: currentTime, }; - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!isEmptyObject(report) && ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) { optimisticReport.notificationPreference = CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; @@ -667,7 +653,7 @@ function updateGroupChatName(reportID: string, reportName: string) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { - reportName: currentReportData?.[reportID]?.reportName ?? null, + reportName: ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? null, errors: { reportName: Localize.translateLocal('common.genericErrorMessage'), }, @@ -704,7 +690,7 @@ function updateGroupChatAvatar(reportID: string, file?: File | CustomRNImageMani onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { - avatarUrl: currentReportData?.[reportID]?.avatarUrl ?? null, + avatarUrl: ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.avatarUrl ?? null, pendingFields: { avatar: null, }, @@ -767,7 +753,7 @@ function openReport( const optimisticReport = reportActionsExist(reportID) ? {} : { - reportName: allReports?.[reportID]?.reportName ?? CONST.REPORT.DEFAULT_REPORT_NAME, + reportName: ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? CONST.REPORT.DEFAULT_REPORT_NAME, }; const optimisticData: OnyxUpdate[] = [ @@ -951,7 +937,7 @@ function openReport( } } - parameters.clientLastReadTime = currentReportData?.[reportID]?.lastReadTime ?? ''; + parameters.clientLastReadTime = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.lastReadTime ?? ''; const paginationConfig = { resourceID: reportID, @@ -1060,7 +1046,7 @@ function navigateToAndOpenChildReport(childReportID = '-1', parentReportAction: Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID)); } else { const participantAccountIDs = [...new Set([currentUserAccountID, Number(parentReportAction.actorAccountID)])]; - const parentReport = allReports?.[parentReportID]; + const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`]; // Threads from DMs and selfDMs don't have a chatType. All other threads inherit the chatType from their parent const childReportChatType = parentReport && ReportUtils.isSelfDM(parentReport) ? undefined : parentReport?.chatType; const newChat = ReportUtils.buildOptimisticChatReport( @@ -1252,7 +1238,9 @@ function markCommentAsUnread(reportID: string, reportActionCreated: string) { }, null); // If no action created date is provided, use the last action's from other user - const actionCreationTime = reportActionCreated || (latestReportActionFromOtherUsers?.created ?? allReports?.[reportID]?.lastVisibleActionCreated ?? DateUtils.getDBTime(0)); + const actionCreationTime = + reportActionCreated || + (latestReportActionFromOtherUsers?.created ?? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.lastVisibleActionCreated ?? DateUtils.getDBTime(0)); // We subtract 1 millisecond so that the lastReadTime is updated to just before a given reportAction's created date // For example, if we want to mark a report action with ID 100 and created date '2014-04-01 16:07:02.999' unread, we set the lastReadTime to '2014-04-01 16:07:02.998' @@ -1354,9 +1342,7 @@ function handleReportChanged(report: OnyxEntry) { return; } - if (allReports && report?.reportID) { - allReports[report.reportID] = report; - + if (report?.reportID) { if (ReportUtils.isConciergeChatReport(report)) { conciergeChatReportID = report.reportID; } @@ -1757,7 +1743,7 @@ function toggleSubscribeToChildReport(childReportID = '-1', parentReportAction: } } else { const participantAccountIDs = [...new Set([currentUserAccountID, Number(parentReportAction?.actorAccountID)])]; - const parentReport = allReports?.[parentReportID]; + const parentReport = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`]; const newChat = ReportUtils.buildOptimisticChatReport( participantAccountIDs, ReportActionsUtils.getReportActionText(parentReportAction), @@ -2170,7 +2156,7 @@ function addPolicyReport(policyReport: ReportUtils.OptimisticChatReport) { /** Deletes a report, along with its reportActions, any linked reports, and any linked IOU report. */ function deleteReport(reportID: string) { - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; const onyxData: Record = { [`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]: null, [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`]: null, @@ -2322,7 +2308,7 @@ function shouldShowReportActionNotification(reportID: string, action: ReportActi } // We don't want to send a local notification if the user preference is daily, mute or hidden. - const notificationPreference = allReports?.[reportID]?.notificationPreference ?? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; + const notificationPreference = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.notificationPreference ?? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS; if (notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS) { Log.info(`${tag} No notification because user preference is to be notified: ${notificationPreference}`); return false; @@ -2340,7 +2326,7 @@ function shouldShowReportActionNotification(reportID: string, action: ReportActi return false; } - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report || (report && report.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)) { Log.info(`${tag} No notification because the report does not exist or is pending deleted`, false); return false; @@ -2374,9 +2360,10 @@ function showReportActionNotification(reportID: string, reportAction: ReportActi Log.info('[LocalNotification] Creating notification'); - const report = allReports?.[reportID] ?? null; + const localReportID = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; + const report = ReportConnection.getAllReports()?.[localReportID] ?? null; if (!report) { - Log.hmmm("[LocalNotification] couldn't show report action notification because the report wasn't found", {reportID, reportActionID: reportAction.reportActionID}); + Log.hmmm("[LocalNotification] couldn't show report action notification because the report wasn't found", {localReportID, reportActionID: reportAction.reportActionID}); return; } @@ -2596,7 +2583,17 @@ function getCurrentUserAccountID(): number { } function navigateToMostRecentReport(currentReport: OnyxEntry) { - const lastAccessedReportID = ReportUtils.findLastAccessedReport(allReports, false, undefined, false, false, reportMetadata, undefined, [], currentReport?.reportID)?.reportID; + const lastAccessedReportID = ReportUtils.findLastAccessedReport( + ReportConnection.getAllReports(), + false, + undefined, + false, + false, + reportMetadata, + undefined, + [], + currentReport?.reportID, + )?.reportID; if (lastAccessedReportID) { const lastAccessedReportRoute = ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID ?? '-1'); @@ -2621,7 +2618,7 @@ function joinRoom(report: OnyxEntry) { } function leaveGroupChat(reportID: string) { - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { Log.warn('Attempting to leave Group Chat that does not existing locally'); return; @@ -2649,7 +2646,7 @@ function leaveGroupChat(reportID: string) { /** Leave a report by setting the state to submitted and closed */ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = false) { - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { return; @@ -2732,7 +2729,7 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal /** Invites people to a room */ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmailsToAccountIDs) { - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { return; } @@ -2826,7 +2823,7 @@ function inviteToRoom(reportID: string, inviteeEmailsToAccountIDs: InvitedEmails } function clearAddRoomMemberError(reportID: string, invitedAccountID: string) { - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, { pendingChatMembers: report?.pendingChatMembers?.filter((pendingChatMember) => pendingChatMember.accountID !== invitedAccountID), participants: { @@ -2888,7 +2885,7 @@ function inviteToGroupChat(reportID: string, inviteeEmailsToAccountIDs: InvitedE * Please see https://github.com/Expensify/App/blob/main/README.md#Security for more details */ function removeFromRoom(reportID: string, targetAccountIDs: number[]) { - const report = currentReportData?.[reportID]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (!report) { return; } @@ -3846,4 +3843,5 @@ export { updateLoadingInitialReportAction, clearAddRoomMemberError, clearAvatarErrors, + handleReportChanged, }; diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts index 395c99fc4b26..b3718079441f 100644 --- a/src/libs/actions/ReportActions.ts +++ b/src/libs/actions/ReportActions.ts @@ -1,10 +1,11 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as ReportActionUtils from '@libs/ReportActionsUtils'; +import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Report as OnyxReportType, ReportActions} from '@src/types/onyx'; +import type {ReportActions} from '@src/types/onyx'; import type ReportAction from '@src/types/onyx/ReportAction'; import * as Report from './Report'; @@ -17,13 +18,6 @@ Onyx.connect({ callback: (value) => (allReportActions = value), }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - function clearReportActionErrors(reportID: string, reportAction: ReportAction, keys?: string[]) { const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction); @@ -85,7 +79,7 @@ function clearAllRelatedReportActionErrors(reportID: string, reportAction: Repor clearReportActionErrors(reportID, reportAction, keys); - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; if (report?.parentReportID && report?.parentReportActionID && ignore !== 'parent') { const parentReportAction = ReportActionUtils.getReportAction(report.parentReportID, report.parentReportActionID); const parentErrorKeys = Object.keys(parentReportAction?.errors ?? {}).filter((err) => errorKeys.includes(err)); diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 013ae698ed3f..0a7244bde1e5 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -12,6 +12,7 @@ import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; +import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; import CONST from '@src/CONST'; @@ -77,13 +78,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => (allReports = value), -}); - /** * Clears out the task info from the store */ @@ -909,14 +903,14 @@ function getParentReport(report: OnyxEntry): OnyxEntry { - return allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + return ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; } /** @@ -1129,7 +1123,7 @@ function canModifyTask(taskReport: OnyxEntry, sessionAccountID } function clearTaskErrors(reportID: string) { - const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; // Delete the task preview in the parent report if (report?.pendingFields?.createChat === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD) { diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index cee4e24041f1..a90c386d02b6 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -1,5 +1,5 @@ import {NativeModules} from 'react-native'; -import type {OnyxCollection, OnyxUpdate} from 'react-native-onyx'; +import type {OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; import {WRITE_COMMANDS} from '@libs/API/types'; @@ -9,7 +9,6 @@ import type {OnboardingPurposeType} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type Onboarding from '@src/types/onyx/Onboarding'; -import type OnyxPolicy from '@src/types/onyx/Policy'; import type TryNewDot from '@src/types/onyx/TryNewDot'; let onboarding: Onboarding | [] | undefined; @@ -202,23 +201,6 @@ Onyx.connect({ }, }); -const allPolicies: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - callback: (val, key) => { - if (!key) { - return; - } - - if (val === null || val === undefined) { - delete allPolicies[key]; - return; - } - - allPolicies[key] = {...allPolicies[key], ...val}; - }, -}); - Onyx.connect({ key: ONYXKEYS.NVP_TRYNEWDOT, callback: (value) => { diff --git a/src/libs/markAllPolicyReportsAsRead.ts b/src/libs/markAllPolicyReportsAsRead.ts index 49001a851cf5..259a5e426d89 100644 --- a/src/libs/markAllPolicyReportsAsRead.ts +++ b/src/libs/markAllPolicyReportsAsRead.ts @@ -1,32 +1,21 @@ -import Onyx from 'react-native-onyx'; -import ONYXKEYS from '@src/ONYXKEYS'; import type {Report} from '@src/types/onyx'; import * as ReportActionFile from './actions/Report'; +import * as ReportConnection from './ReportConnection'; import * as ReportUtils from './ReportUtils'; export default function markAllPolicyReportsAsRead(policyID: string) { - const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (allReports) => { - if (!allReports) { - return; - } + let delay = 0; + const allReports = ReportConnection.getAllReports() ?? {}; + Object.keys(allReports).forEach((key: string) => { + const report: Report | null | undefined = allReports[key]; + if (report?.policyID !== policyID || !ReportUtils.isUnread(report)) { + return; + } - let delay = 0; - Object.keys(allReports).forEach((key: string) => { - const report: Report | null | undefined = allReports[key]; - if (report?.policyID !== policyID || !ReportUtils.isUnread(report)) { - return; - } + setTimeout(() => { + ReportActionFile.readNewestAction(report?.reportID); + }, delay); - setTimeout(() => { - ReportActionFile.readNewestAction(report?.reportID); - }, delay); - - delay += 1000; - }); - Onyx.disconnect(connectionID); - }, + delay += 1000; }); } diff --git a/src/libs/migrations/Participants.ts b/src/libs/migrations/Participants.ts index 3dbbef486d68..eccaa0662f2f 100644 --- a/src/libs/migrations/Participants.ts +++ b/src/libs/migrations/Participants.ts @@ -1,6 +1,7 @@ import Onyx from 'react-native-onyx'; import type {NullishDeep, OnyxCollection} from 'react-native-onyx'; import Log from '@libs/Log'; +import * as ReportConnection from '@libs/ReportConnection'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Report} from '@src/types/onyx'; import type {Participants} from '@src/types/onyx/Report'; @@ -11,14 +12,7 @@ type OldReportCollection = Record>; function getReports(): Promise> { return new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (reports) => { - Onyx.disconnect(connectionID); - return resolve(reports); - }, - }); + resolve(ReportConnection.getAllReports()); }); } diff --git a/src/pages/home/sidebar/SidebarLinksData.tsx b/src/pages/home/sidebar/SidebarLinksData.tsx index 635d4df5cb58..471e0d0bf20e 100644 --- a/src/pages/home/sidebar/SidebarLinksData.tsx +++ b/src/pages/home/sidebar/SidebarLinksData.tsx @@ -2,17 +2,14 @@ import {useIsFocused} from '@react-navigation/native'; import lodashIsEqual from 'lodash/isEqual'; import React, {memo, useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import type {EdgeInsets} from 'react-native-safe-area-context'; import type {ValueOf} from 'type-fest'; import useActiveWorkspaceFromNavigationState from '@hooks/useActiveWorkspaceFromNavigationState'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; -import type {PolicySelector} from '@hooks/useReportIDs'; -import {policySelector, useReportIDs} from '@hooks/useReportIDs'; +import {useReportIDs} from '@hooks/useReportIDs'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getPolicyEmployeeListByIdWithoutCurrentUser} from '@libs/PolicyUtils'; import * as Policy from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -24,9 +21,6 @@ type SidebarLinksDataOnyxProps = { /** The chat priority mode */ priorityMode: OnyxEntry>; - - /** The policies which the user has access to */ - policies: OnyxCollection; }; type SidebarLinksDataProps = SidebarLinksDataOnyxProps & { @@ -37,21 +31,18 @@ type SidebarLinksDataProps = SidebarLinksDataOnyxProps & { insets: EdgeInsets; }; -function SidebarLinksData({insets, isLoadingApp = true, onLinkClick, priorityMode = CONST.PRIORITY_MODE.DEFAULT, policies}: SidebarLinksDataProps) { - const {accountID} = useCurrentUserPersonalDetails(); +function SidebarLinksData({insets, isLoadingApp = true, onLinkClick, priorityMode = CONST.PRIORITY_MODE.DEFAULT}: SidebarLinksDataProps) { const isFocused = useIsFocused(); const styles = useThemeStyles(); const activeWorkspaceID = useActiveWorkspaceFromNavigationState(); const {translate} = useLocalize(); - const policyMemberAccountIDs = getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID); + const {orderedReportIDs, currentReportID, policyMemberAccountIDs} = useReportIDs(); // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => Policy.openWorkspace(activeWorkspaceID ?? '-1', policyMemberAccountIDs), [activeWorkspaceID]); const isLoading = isLoadingApp; - const {orderedReportIDs, currentReportID} = useReportIDs(); - const currentReportIDRef = useRef(currentReportID); currentReportIDRef.current = currentReportID; const isActiveReport = useCallback((reportID: string): boolean => currentReportIDRef.current === reportID, []); @@ -88,11 +79,6 @@ export default withOnyx({ key: ONYXKEYS.NVP_PRIORITY_MODE, initialValue: CONST.PRIORITY_MODE.DEFAULT, }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - selector: policySelector, - initialValue: {}, - }, })( /* While working on audit on the App Start App metric we noticed that by memoizing SidebarLinksData we can avoid 2 additional run of getOrderedReportIDs. @@ -105,7 +91,6 @@ More details - https://github.com/Expensify/App/issues/35234#issuecomment-192691 prevProps.isLoadingApp === nextProps.isLoadingApp && prevProps.priorityMode === nextProps.priorityMode && lodashIsEqual(prevProps.insets, nextProps.insets) && - prevProps.onLinkClick === nextProps.onLinkClick && - lodashIsEqual(prevProps.policies, nextProps.policies), + prevProps.onLinkClick === nextProps.onLinkClick, ), ); diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index 4bbcafa76bbb..4a6b12d726d9 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -2,13 +2,13 @@ import {rand} from '@ngneat/falso'; import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import {measureFunction} from 'reassure'; -import type {ChatReportSelector} from '@hooks/useReportIDs'; import {getReportActionMessage} from '@libs/ReportActionsUtils'; import SidebarUtils from '@libs/SidebarUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetails, TransactionViolation} from '@src/types/onyx'; import type Policy from '@src/types/onyx/Policy'; +import type Report from '@src/types/onyx/Report'; import type ReportAction from '@src/types/onyx/ReportAction'; import createCollection from '../utils/collections/createCollection'; import createPersonalDetails from '../utils/collections/personalDetails'; @@ -21,7 +21,7 @@ const REPORTS_COUNT = 15000; const REPORT_TRESHOLD = 5; const PERSONAL_DETAILS_LIST_COUNT = 1000; -const allReports = createCollection( +const allReports = createCollection( (item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, (index) => ({ ...createRandomReport(index), diff --git a/tests/unit/SidebarOrderTest.ts b/tests/unit/SidebarOrderTest.ts index 0abfa2efd752..41e85c4fdd78 100644 --- a/tests/unit/SidebarOrderTest.ts +++ b/tests/unit/SidebarOrderTest.ts @@ -873,13 +873,13 @@ describe('Sidebar', () => { return ( waitForBatchedUpdates() + .then(() => Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, LHNTestUtils.fakePersonalDetails)) .then(() => LHNTestUtils.getDefaultRenderedSidebarLinks('0')) // Given the sidebar is rendered in #focus mode (hides read chats) // with all reports having unread comments .then(() => Onyx.multiSet({ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, [ONYXKEYS.IS_LOADING_APP]: false, ...reportCollectionDataSet, }), diff --git a/tests/unit/UnreadIndicatorUpdaterTest.ts b/tests/unit/UnreadIndicatorUpdaterTest.ts index 22141eee791d..9cf65bcb69d4 100644 --- a/tests/unit/UnreadIndicatorUpdaterTest.ts +++ b/tests/unit/UnreadIndicatorUpdaterTest.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import CONST from '../../src/CONST'; -import getUnreadReportsForUnreadIndicator from '../../src/libs/UnreadIndicatorUpdater'; +import * as UnreadIndicatorUpdater from '../../src/libs/UnreadIndicatorUpdater'; describe('UnreadIndicatorUpdaterTest', () => { describe('should return correct number of unread reports', () => { @@ -24,7 +24,7 @@ describe('UnreadIndicatorUpdaterTest', () => { }, 3: {reportID: '3', reportName: 'test', type: CONST.REPORT.TYPE.TASK, lastMessageText: 'test'}, }; - expect(getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(2); + expect(UnreadIndicatorUpdater.getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(2); }); it('given some reports are incomplete', () => { @@ -33,7 +33,7 @@ describe('UnreadIndicatorUpdaterTest', () => { 2: {reportID: '2', type: CONST.REPORT.TYPE.TASK, lastReadTime: '2023-02-05 09:12:05.000', lastVisibleActionCreated: '2023-02-06 07:15:44.030'}, 3: {reportID: '3', type: CONST.REPORT.TYPE.TASK}, }; - expect(getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(0); + expect(UnreadIndicatorUpdater.getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(0); }); it('given notification preference of some reports is hidden', () => { @@ -57,7 +57,7 @@ describe('UnreadIndicatorUpdaterTest', () => { }, 3: {reportID: '3', reportName: 'test', type: CONST.REPORT.TYPE.TASK, lastMessageText: 'test'}, }; - expect(getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(1); + expect(UnreadIndicatorUpdater.getUnreadReportsForUnreadIndicator(reportsToBeUsed, '3').length).toBe(1); }); }); });