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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/components/OptionListContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) {
for (const reportKey of changedReportKeys) {
const report = changedReportsEntries[reportKey];
const reportID = reportKey.replace(ONYXKEYS.COLLECTION.REPORT, '');
const {reportOption} = processReport(report, personalDetails, currentUserAccountID, reportAttributes?.reports);
const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`];
const {reportOption} = processReport(report, personalDetails, privateIsArchived, currentUserAccountID, reportAttributes?.reports);

if (reportOption) {
updatedReportsMap.set(reportID, reportOption);
Expand All @@ -137,7 +138,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) {
reports: Array.from(updatedReportsMap.values()),
};
});
}, [changedReportsEntries, personalDetails, currentUserAccountID, reportAttributes?.reports]);
}, [changedReportsEntries, personalDetails, currentUserAccountID, reportAttributes?.reports, privateIsArchivedMap]);

useEffect(() => {
if (!changedReportActions || !areOptionsInitialized.current) {
Expand All @@ -157,7 +158,8 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) {
}

const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_ACTIONS, '');
const {reportOption} = processReport(updatedReportsMap.get(reportID)?.item, personalDetails, currentUserAccountID, reportAttributes?.reports);
const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`];
const {reportOption} = processReport(updatedReportsMap.get(reportID)?.item, personalDetails, privateIsArchived, currentUserAccountID, reportAttributes?.reports);

if (reportOption) {
updatedReportsMap.set(reportID, reportOption);
Expand All @@ -169,7 +171,7 @@ function OptionsListContextProvider({children}: OptionsListProviderProps) {
reports: Array.from(updatedReportsMap.values()),
};
});
}, [changedReportActions, personalDetails, currentUserAccountID, reportAttributes?.reports]);
}, [changedReportActions, personalDetails, currentUserAccountID, reportAttributes?.reports, privateIsArchivedMap]);

/**
* This effect is used to update the options list when personal details change.
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useFilteredOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ function useFilteredOptions(config: UseFilteredOptionsConfig = {}): UseFilteredO
const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true});
const [allPersonalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: true});
const reportAttributesDerived = useReportAttributes();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();

const privateIsArchivedMap = usePrivateIsArchivedMap();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();

const totalReports = allReports ? Object.keys(allReports).length : 0;

Expand Down
9 changes: 6 additions & 3 deletions src/libs/OptionsListUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,13 @@
*/

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

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

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

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

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

View workflow job for this annotation

GitHub Actions / ESLint check

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

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

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

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

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

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

View workflow job for this annotation

GitHub Actions / ESLint check

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

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

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

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

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

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

View workflow job for this annotation

GitHub Actions / ESLint check

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

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

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

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

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

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

View workflow job for this annotation

GitHub Actions / ESLint check

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

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

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

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

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

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

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_ACTIVE_POLICY_ID,
callback: (value) => (activePolicyID = value),
});
Expand Down Expand Up @@ -1261,6 +1261,7 @@
function processReport(
report: OnyxEntry<Report> | null,
personalDetails: OnyxEntry<PersonalDetailsList>,
privateIsArchived: string | undefined,
currentUserAccountID: number,
reportAttributesDerived?: ReportAttributesDerivedValue['reports'],
): {
Expand All @@ -1286,7 +1287,7 @@
reportMapEntry,
reportOption: {
item: report,
...createOption(accountIDs, personalDetails, report, currentUserAccountID, undefined, reportAttributesDerived),
...createOption(accountIDs, personalDetails, report, currentUserAccountID, undefined, reportAttributesDerived, privateIsArchived),
},
};
}
Expand All @@ -1305,7 +1306,8 @@

if (reports) {
for (const report of Object.values(reports)) {
const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reportAttributesDerived);
const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report?.reportID}`];
const {reportMapEntry, reportOption} = processReport(report, personalDetails, privateIsArchived, currentUserAccountID, reportAttributesDerived);

if (reportMapEntry) {
const [accountID, reportValue] = reportMapEntry;
Expand Down Expand Up @@ -1424,7 +1426,8 @@
// Step 5: Process the limited set of reports (performance optimization)
const reportOptions: Array<SearchOption<Report>> = [];
for (const report of limitedReports) {
const {reportMapEntry, reportOption} = processReport(report, personalDetails, currentUserAccountID, reportAttributesDerived);
const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`];
const {reportMapEntry, reportOption} = processReport(report, personalDetails, privateIsArchived, currentUserAccountID, reportAttributesDerived);

if (reportMapEntry) {
const [accountID, reportValue] = reportMapEntry;
Expand Down
56 changes: 55 additions & 1 deletion tests/unit/OptionListContextProviderTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import OptionListContextProvider, {useOptionsList} from '@components/OptionListC
import useOnyx from '@hooks/useOnyx';
import usePrivateIsArchivedMap from '@hooks/usePrivateIsArchivedMap';
import type {OptionList, SearchOption} from '@libs/OptionsListUtils';
import {createOptionFromReport, createOptionList} from '@libs/OptionsListUtils';
import {createOptionFromReport, createOptionList, processReport} from '@libs/OptionsListUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Report} from '@src/types/onyx';

Expand All @@ -28,6 +28,7 @@ jest.mock('@components/OnyxListItemProvider', () => ({
}));

const mockCreateOptionList = createOptionList as jest.MockedFunction<typeof createOptionList>;
const mockProcessReport = processReport as jest.MockedFunction<typeof processReport>;
const mockCreateOptionFromReport = createOptionFromReport as jest.MockedFunction<typeof createOptionFromReport>;
const mockUseOnyx = useOnyx as jest.MockedFunction<typeof useOnyx>;
const mockUsePersonalDetails = usePersonalDetails as jest.MockedFunction<typeof usePersonalDetails>;
Expand Down Expand Up @@ -122,6 +123,59 @@ describe('OptionListContextProvider', () => {
expect(mockCreateOptionList).toHaveBeenCalledTimes(1);
});

it('calls processReport with privateIsArchived when reports change', () => {
const reportID = '1';
const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
const report = {reportID};

const {result, rerender} = renderHook(({shouldInitialize}) => useOptionsList({shouldInitialize}), {
initialProps: {shouldInitialize: false},
wrapper,
});

act(() => {
result.current.initializeOptions();
});

mockProcessReport.mockClear();

onyxState = {
...onyxState,
[ONYXKEYS.COLLECTION.REPORT]: {[reportKey]: report},
};
onyxSourceValues = {
...onyxSourceValues,
[ONYXKEYS.COLLECTION.REPORT]: {[reportKey]: report},
};
rerender({shouldInitialize: false});

expect(mockProcessReport).toHaveBeenCalled();
});

it('calls processReport with privateIsArchived when report actions change', () => {
const reportID = '2';
const reportActionsKey = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`;

const {result, rerender} = renderHook(({shouldInitialize}) => useOptionsList({shouldInitialize}), {
initialProps: {shouldInitialize: false},
wrapper,
});

act(() => {
result.current.initializeOptions();
});

mockProcessReport.mockClear();

onyxSourceValues = {
...onyxSourceValues,
[ONYXKEYS.COLLECTION.REPORT_ACTIONS]: {[reportActionsKey]: {someAction: {}}},
};
rerender({shouldInitialize: false});

expect(mockProcessReport).toHaveBeenCalled();
});

it('passes privateIsArchived to createOptionFromReport when personal details change', () => {
const reportID = '1';
const accountID = '12345';
Expand Down
107 changes: 107 additions & 0 deletions tests/unit/OptionsListUtilsTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3663,6 +3663,113 @@ describe('OptionsListUtils', () => {
expect(misterFantasticOption?.private_isArchived).toBe('2023-06-15 10:00:00');
expect(invisibleWomanOption?.private_isArchived).toBe('2023-07-20 15:30:00');
});

it('should set private_isArchived on report options when privateIsArchivedMap is provided', () => {
renderLocaleContextProvider();
// Given a privateIsArchivedMap with archived reports
const privateIsArchivedMap: PrivateIsArchivedMap = {
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}3`]: '2023-06-15 10:00:00',
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}5`]: '2023-07-20 15:30:00',
};

// When we call createOptionList with this privateIsArchivedMap
const result = createOptionList(PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID, privateIsArchivedMap, REPORTS);

// Then the report options should have the correct private_isArchived values
const report3Option = result.reports.find((r) => r.item?.reportID === '3');
const report5Option = result.reports.find((r) => r.item?.reportID === '5');
const report1Option = result.reports.find((r) => r.item?.reportID === '1');

expect(report3Option?.private_isArchived).toBe('2023-06-15 10:00:00');
expect(report5Option?.private_isArchived).toBe('2023-07-20 15:30:00');
// Report 1 should not have private_isArchived since it's not in the map
expect(report1Option?.private_isArchived).toBeUndefined();
});
});

describe('createFilteredOptionList()', () => {
it('should set private_isArchived on report options when privateIsArchivedMap is provided', () => {
renderLocaleContextProvider();
// Given a privateIsArchivedMap with archived reports
const privateIsArchivedMap: PrivateIsArchivedMap = {
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}3`]: '2023-06-15 10:00:00',
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}5`]: '2023-07-20 15:30:00',
};

// When we call createFilteredOptionList with this privateIsArchivedMap
const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, CURRENT_USER_ACCOUNT_ID, undefined, privateIsArchivedMap);

// Then the report options should have the correct private_isArchived values
const report3Option = result.reports.find((r) => r.item?.reportID === '3');
const report5Option = result.reports.find((r) => r.item?.reportID === '5');
const report1Option = result.reports.find((r) => r.item?.reportID === '1');

expect(report3Option?.private_isArchived).toBe('2023-06-15 10:00:00');
expect(report5Option?.private_isArchived).toBe('2023-07-20 15:30:00');
// Report 1 should not have private_isArchived since it's not in the map
expect(report1Option?.private_isArchived).toBeUndefined();
});

it('should not set private_isArchived from map when privateIsArchivedMap is empty', () => {
renderLocaleContextProvider();
// Given an empty privateIsArchivedMap
const emptyMap: PrivateIsArchivedMap = {};

// When we call createFilteredOptionList with an empty privateIsArchivedMap
const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, CURRENT_USER_ACCOUNT_ID, undefined, emptyMap);

// Then reports NOT in Onyx (like report 3, 5) should not have private_isArchived set
// Note: Report 10 gets private_isArchived from Onyx (set in beforeAll)
const report3Option = result.reports.find((r) => r.item?.reportID === '3');
const report5Option = result.reports.find((r) => r.item?.reportID === '5');
expect(report3Option?.private_isArchived).toBeUndefined();
expect(report5Option?.private_isArchived).toBeUndefined();
});

it('should correctly map multiple archived reports in privateIsArchivedMap', () => {
renderLocaleContextProvider();
// Given a privateIsArchivedMap with multiple archived reports
const privateIsArchivedMap: PrivateIsArchivedMap = {
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}1`]: '2023-01-01 00:00:00',
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}3`]: '2023-06-15 10:00:00',
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}5`]: '2023-07-20 15:30:00',
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}7`]: '2023-12-31 23:59:59',
};

// When we call createFilteredOptionList with this privateIsArchivedMap
const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, CURRENT_USER_ACCOUNT_ID, undefined, privateIsArchivedMap);

// Then the report options should have the correct private_isArchived values
const report1Option = result.reports.find((r) => r.item?.reportID === '1');
const report3Option = result.reports.find((r) => r.item?.reportID === '3');
const report5Option = result.reports.find((r) => r.item?.reportID === '5');
const report7Option = result.reports.find((r) => r.item?.reportID === '7');
const report2Option = result.reports.find((r) => r.item?.reportID === '2');

expect(report1Option?.private_isArchived).toBe('2023-01-01 00:00:00');
expect(report3Option?.private_isArchived).toBe('2023-06-15 10:00:00');
expect(report5Option?.private_isArchived).toBe('2023-07-20 15:30:00');
expect(report7Option?.private_isArchived).toBe('2023-12-31 23:59:59');
// Report 2 should not have private_isArchived since it's not in the map
expect(report2Option?.private_isArchived).toBeUndefined();
});

it('should respect maxRecentReports option while preserving archived status', () => {
renderLocaleContextProvider();
// Given a privateIsArchivedMap and a small maxRecentReports limit
const privateIsArchivedMap: PrivateIsArchivedMap = {
[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}7`]: '2023-12-31 23:59:59', // Report 7 has largest lastVisibleActionCreated
};

// When we call createFilteredOptionList with maxRecentReports limit
const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, CURRENT_USER_ACCOUNT_ID, undefined, privateIsArchivedMap, {
maxRecentReports: 5,
});

// Then the report 7 (most recent) should still have private_isArchived set
const report7Option = result.reports.find((r) => r.item?.reportID === '7');
expect(report7Option?.private_isArchived).toBe('2023-12-31 23:59:59');
});
});

describe('filterSelfDMChat()', () => {
Expand Down
Loading