Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion src/hooks/useSidebarOrderedReports.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, {createContext, useCallback, useContext, useEffect, useMemo, useState} from 'react';
import {deepEqual} from 'fast-equals';
import React, {createContext, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import Log from '@libs/Log';
import {getPolicyEmployeeListByIdWithoutCurrentUser} from '@libs/PolicyUtils';
import SidebarUtils from '@libs/SidebarUtils';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -224,6 +226,53 @@ function SidebarOrderedReportsContextProvider({
};
}, [getOrderedReportIDs, orderedReportIDs, derivedCurrentReportID, policyMemberAccountIDs, shouldUseNarrowLayout, getOrderedReports, orderedReports]);

const currentDeps = {
priorityMode,
chatReports,
policies,
transactions,
transactionViolations,
reportNameValuePairs,
betas,
reportAttributes,
currentReportsToDisplay,
shouldUseNarrowLayout,
accountID,
currentReportIDValue,
derivedCurrentReportID,
prevDerivedCurrentReportID,
policyMemberAccountIDs,
prevBetas,
prevPriorityMode,
reportsToDisplayInLHN,
orderedReportIDs,
orderedReports,
};
const prevContextValue = usePrevious(contextValue);
const previousDeps = usePrevious(currentDeps);
const firstRender = useRef(true);

useEffect(() => {
// Cases below ensure we only log when the edge case (empty -> non-empty or non-empty -> empty) happens.
// This is done to avoid excessive logging when the orderedReports array is updated, but does not impact LHN.

// Case 1: orderedReports goes from empty to non-empty
if (contextValue.orderedReports.length > 0 && prevContextValue?.orderedReports.length === 0) {
logChangedDeps('[useSidebarOrderedReports] Ordered reports went from empty to non-empty', currentDeps, previousDeps);
}
// Case 2: orderedReports goes from non-empty to empty
if (contextValue.orderedReports.length === 0 && prevContextValue?.orderedReports.length > 0) {
logChangedDeps('[useSidebarOrderedReports] Ordered reports went from non-empty to empty', currentDeps, previousDeps);
}

// Case 3: orderedReports are empty from the beginning
if (firstRender.current && contextValue.orderedReports.length === 0) {
logChangedDeps('[useSidebarOrderedReports] Ordered reports initialized empty', currentDeps, previousDeps);
}

firstRender.current = false;
});

return <SidebarOrderedReportsContext.Provider value={contextValue}>{children}</SidebarOrderedReportsContext.Provider>;
}

Expand All @@ -233,3 +282,31 @@ function useSidebarOrderedReports() {

export {SidebarOrderedReportsContext, SidebarOrderedReportsContextProvider, useSidebarOrderedReports};
export type {PartialPolicyForSidebar, ReportsToDisplayInLHN};

function getChangedKeys<T extends Record<string, unknown>>(deps: T, prevDeps: T) {
const depsKeys = Object.keys(deps);

return depsKeys.filter((depKey) => !deepEqual(deps[depKey], prevDeps[depKey]));
}

function logChangedDeps<T extends Record<string, unknown>>(msg: string, deps: T, prevDeps: T) {
const startTime = performance.now();
const changedDeps = getChangedKeys(deps, prevDeps);
const parsedDeps = parseDepsForLogging(deps);
const processingDuration = performance.now() - startTime;
Log.info(msg, false, {
deps: parsedDeps,
changedDeps,
processingDuration,
});
}

/**
* @param deps - The dependencies to parse.
* @returns A simplified object with light-weight values.
*/
function parseDepsForLogging<T extends Record<string, unknown>>(deps: T) {
// If object or array, return the keys' length
// If primitive, return the value
return Object.fromEntries(Object.entries(deps).map(([key, value]) => [key, typeof value === 'object' && value !== null ? Object.keys(value).length : value]));
}
Loading