diff --git a/src/hooks/useFilterFormValues.tsx b/src/hooks/useFilterFormValues.tsx index dddb5db7b76e..90f711cad151 100644 --- a/src/hooks/useFilterFormValues.tsx +++ b/src/hooks/useFilterFormValues.tsx @@ -11,6 +11,7 @@ import type {SearchAdvancedFiltersForm} from '@src/types/form'; import type {Policy, PolicyCategories, PolicyTagLists, Report} from '@src/types/onyx'; import {getEmptyObject} from '@src/types/utils/EmptyObject'; import {useCurrencyListState} from './useCurrencyList'; +import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; import useExportedToFilterOptions from './useExportedToFilterOptions'; import useOnyx from './useOnyx'; @@ -84,6 +85,7 @@ function policyTagsSelector(tags: OnyxCollection): OnyxCollectio const useFilterFormValues = (queryJSON?: SearchQueryJSON) => { const personalDetails = usePersonalDetails(); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const {currencyList} = useCurrencyListState(); const [userCardList] = useOnyx(ONYXKEYS.CARD_LIST); @@ -99,7 +101,18 @@ const useFilterFormValues = (queryJSON?: SearchQueryJSON) => { const {exportedToFilterOptions} = useExportedToFilterOptions(); const formValues = queryJSON - ? buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, allCards, allReports, taxRates, exportedToFilterOptions) + ? buildFilterFormValuesFromQuery( + queryJSON, + policyCategories, + policyTagsLists, + currencyList, + personalDetails, + allCards, + allReports, + taxRates, + exportedToFilterOptions, + currentUserPersonalDetails.accountID, + ) : getEmptyObject>(); return formValues; diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index a1812094e501..fa63e7f4d20f 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -1062,6 +1062,7 @@ function buildFilterFormValuesFromQuery( reports: OnyxCollection, taxRates: Record, exportedToFilterOptions?: string[], + currentUserAccountID?: number, ) { const filters = queryJSON.flatFilters; const filtersForm = {} as Partial; @@ -1128,7 +1129,8 @@ function buildFilterFormValuesFromQuery( filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.ASSIGNEE || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTER ) { - filtersForm[key as typeof filterKey] = filterValues.filter((id) => personalDetails?.[id]); + const resolvedValues = filterValues.map((id) => (id === CONST.SEARCH.ME && currentUserAccountID ? currentUserAccountID.toString() : id)); + filtersForm[key as typeof filterKey] = resolvedValues.filter((id) => personalDetails?.[id]); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE) { // Don't filter attendee values by personalDetails - they can be accountIDs OR display names for name-only attendees @@ -1437,6 +1439,9 @@ function getFilterDisplayValue({ filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTER || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE ) { + if (filterValue === CONST.SEARCH.ME) { + return CONST.SEARCH.ME; + } return filterValue === currentUserAccountID.toString() ? CONST.SEARCH.ME : getDisplayNameOrDefault(personalDetails?.[filterValue], filterValue, false); } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { diff --git a/src/pages/settings/Subscription/CardSection/CardSection.tsx b/src/pages/settings/Subscription/CardSection/CardSection.tsx index 074e3b68dea1..701daf0ee83f 100644 --- a/src/pages/settings/Subscription/CardSection/CardSection.tsx +++ b/src/pages/settings/Subscription/CardSection/CardSection.tsx @@ -100,8 +100,17 @@ function CardSection() { const viewPurchases = () => { const query = buildQueryStringFromFilterFormValues({ type: CONST.SEARCH.DATA_TYPES.EXPENSE, - status: CONST.SEARCH.STATUS.EXPENSE.ALL, + status: [ + CONST.SEARCH.STATUS.EXPENSE.UNREPORTED, + CONST.SEARCH.STATUS.EXPENSE.DRAFTS, + CONST.SEARCH.STATUS.EXPENSE.OUTSTANDING, + CONST.SEARCH.STATUS.EXPENSE.APPROVED, + CONST.SEARCH.STATUS.EXPENSE.DONE, + CONST.SEARCH.STATUS.EXPENSE.PAID, + CONST.SEARCH.STATUS.EXPENSE.DELETED, + ], merchant: CONST.EXPENSIFY_MERCHANT, + from: [CONST.SEARCH.ME], }); Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query, rawQuery: query})); diff --git a/tests/unit/Search/SearchQueryUtilsTest.ts b/tests/unit/Search/SearchQueryUtilsTest.ts index 71f3d71667e6..27fe0613224f 100644 --- a/tests/unit/Search/SearchQueryUtilsTest.ts +++ b/tests/unit/Search/SearchQueryUtilsTest.ts @@ -1353,6 +1353,111 @@ describe('SearchQueryUtils', () => { // invalid should be filtered out, cash and card are valid CONST.SEARCH.TRANSACTION_TYPE values expect(result.expenseType).toEqual(['cash', 'card']); }); + + test('from:me resolves to current user account ID when currentUserAccountID is provided', () => { + const currentUserAccountID = 12345; + const queryString = 'type:expense from:me'; + const queryJSON = buildSearchQueryJSON(queryString); + + const policyCategories = {}; + const policyTags = {}; + const currencyList = {}; + const personalDetails = { + '12345': { + accountID: 12345, + login: 'testuser@example.com', + displayName: 'Test User', + }, + }; + const cardList = {}; + const reports = {}; + const taxRates = {}; + + if (!queryJSON) { + throw new Error('Failed to parse query string'); + } + + const result = buildFilterFormValuesFromQuery( + queryJSON, + policyCategories, + policyTags, + currencyList, + personalDetails, + cardList, + reports, + taxRates, + undefined, + currentUserAccountID, + ); + + expect(result.from).toEqual(['12345']); + }); + + test('from:me is filtered out when currentUserAccountID is not provided', () => { + const queryString = 'type:expense from:me'; + const queryJSON = buildSearchQueryJSON(queryString); + + const policyCategories = {}; + const policyTags = {}; + const currencyList = {}; + const personalDetails = { + '12345': { + accountID: 12345, + login: 'testuser@example.com', + displayName: 'Test User', + }, + }; + const cardList = {}; + const reports = {}; + const taxRates = {}; + + if (!queryJSON) { + throw new Error('Failed to parse query string'); + } + + const result = buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTags, currencyList, personalDetails, cardList, reports, taxRates); + + expect(result.from).toEqual([]); + }); + + test('to:me resolves to current user account ID', () => { + const currentUserAccountID = 99999; + const queryString = 'type:expense to:me'; + const queryJSON = buildSearchQueryJSON(queryString); + + const policyCategories = {}; + const policyTags = {}; + const currencyList = {}; + const personalDetails = { + '99999': { + accountID: 99999, + login: 'otheruser@example.com', + displayName: 'Other User', + }, + }; + const cardList = {}; + const reports = {}; + const taxRates = {}; + + if (!queryJSON) { + throw new Error('Failed to parse query string'); + } + + const result = buildFilterFormValuesFromQuery( + queryJSON, + policyCategories, + policyTags, + currencyList, + personalDetails, + cardList, + reports, + taxRates, + undefined, + currentUserAccountID, + ); + + expect(result.to).toEqual(['99999']); + }); }); describe('shouldHighlight', () => { @@ -1699,6 +1804,24 @@ describe('SearchQueryUtils', () => { expect(result).toBe(CONST.SEARCH.ME); }); + it('should return "me" when filterValue is the literal "me" keyword', () => { + const personalDetails = {}; + + const result = getFilterDisplayValue({ + filterName: CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM, + filterValue: CONST.SEARCH.ME, + personalDetails, + reports: mockReports, + cardList: mockCardList, + cardFeeds: mockCardFeeds, + policies: mockPolicies, + currentUserAccountID, + translate: translateLocal, + }); + + expect(result).toBe(CONST.SEARCH.ME); + }); + it('should return fallback value when personal details not found', () => { const personalDetails = {};