Skip to content

Commit f45837d

Browse files
authored
Merge pull request Expensify#67450 from s77rt/enable-statement-lhn
Enable Statements in LHN
2 parents f5bf7c6 + 2cd4bd4 commit f45837d

9 files changed

Lines changed: 76 additions & 39 deletions

File tree

src/CONST/index.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6456,14 +6456,6 @@ const CONST = {
64566456
LAST_MONTH: 'last-month',
64576457
LAST_STATEMENT: 'last-statement',
64586458
},
6459-
get FILTER_DATE_PRESETS() {
6460-
return {
6461-
// s77rt remove DEV lock
6462-
[this.SYNTAX_FILTER_KEYS.POSTED]:
6463-
(Config?.ENVIRONMENT ?? 'development') === 'development' ? [this.DATE_PRESETS.LAST_STATEMENT, this.DATE_PRESETS.LAST_MONTH] : [this.DATE_PRESETS.LAST_MONTH],
6464-
[this.SYNTAX_FILTER_KEYS.EXPORTED]: [this.DATE_PRESETS.NEVER],
6465-
};
6466-
},
64676459
SNAPSHOT_ONYX_KEYS: [
64686460
ONYXKEYS.COLLECTION.REPORT,
64696461
ONYXKEYS.COLLECTION.POLICY,

src/components/Search/SearchAutocompleteList.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
parseForAutocomplete,
3333
} from '@libs/SearchAutocompleteUtils';
3434
import {buildSearchQueryJSON, buildUserReadableQueryString, getQueryWithoutFilters, sanitizeSearchValue, shouldHighlight} from '@libs/SearchQueryUtils';
35+
import {getDatePresets} from '@libs/SearchUIUtils';
3536
import StringUtils from '@libs/StringUtils';
3637
import Timing from '@userActions/Timing';
3738
import CONST from '@src/CONST';
@@ -433,7 +434,7 @@ function SearchAutocompleteList(
433434
}
434435
case CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED:
435436
case CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED: {
436-
const filteredDatePresets = CONST.SEARCH.FILTER_DATE_PRESETS[autocompleteKey]
437+
const filteredDatePresets = (getDatePresets(autocompleteKey, true) ?? [])
437438
.filter((datePreset) => datePreset.toLowerCase().includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.includes(datePreset.toLowerCase()))
438439
.sort()
439440
.slice(0, 10);

src/components/Search/SearchDatePresetFilterBasePage.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,25 @@ import useOnyx from '@hooks/useOnyx';
99
import useThemeStyles from '@hooks/useThemeStyles';
1010
import {updateAdvancedFilters} from '@libs/actions/Search';
1111
import Navigation from '@libs/Navigation/Navigation';
12+
import {getDatePresets} from '@libs/SearchUIUtils';
1213
import type {SearchDateModifier, SearchDateModifierLower} from '@libs/SearchUIUtils';
1314
import CONST from '@src/CONST';
1415
import type {TranslationPaths} from '@src/languages/types';
1516
import ONYXKEYS from '@src/ONYXKEYS';
1617
import ROUTES from '@src/ROUTES';
1718
import SearchDatePresetFilterBase from './SearchDatePresetFilterBase';
1819
import type {SearchDatePresetFilterBaseHandle} from './SearchDatePresetFilterBase';
19-
import type {SearchDateFilterKeys, SearchDatePreset} from './types';
20+
import type {SearchDateFilterKeys} from './types';
2021

2122
type SearchDatePresetFilterBasePageProps = {
2223
/** Key used for the date filter */
2324
dateKey: SearchDateFilterKeys;
2425

2526
/** The translation key for the page title */
2627
titleKey: TranslationPaths;
27-
28-
/** The date presets */
29-
presets?: SearchDatePreset[];
3028
};
3129

32-
function SearchDatePresetFilterBasePage({dateKey, titleKey, presets}: SearchDatePresetFilterBasePageProps) {
30+
function SearchDatePresetFilterBasePage({dateKey, titleKey}: SearchDatePresetFilterBasePageProps) {
3331
const styles = useThemeStyles();
3432
const {translate} = useLocalize();
3533

@@ -43,6 +41,11 @@ function SearchDatePresetFilterBasePage({dateKey, titleKey, presets}: SearchDate
4341
[CONST.SEARCH.DATE_MODIFIERS.AFTER]: searchAdvancedFiltersForm?.[`${dateKey}${CONST.SEARCH.DATE_MODIFIERS.AFTER}`],
4442
};
4543

44+
const presets = useMemo(() => {
45+
const hasFeed = !!searchAdvancedFiltersForm?.feed?.length;
46+
return getDatePresets(dateKey, hasFeed);
47+
}, [dateKey, searchAdvancedFiltersForm?.feed]);
48+
4649
const title = useMemo(() => {
4750
if (selectedDateModifier) {
4851
return translate(`common.${selectedDateModifier.toLowerCase() as SearchDateModifierLower}`);

src/components/Search/SearchPageHeader/SearchFiltersBar.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import {
4040
isFilterSupported,
4141
isSearchDatePreset,
4242
} from '@libs/SearchQueryUtils';
43-
import {getFeedOptions, getGroupByOptions, getStatusOptions, getTypeOptions} from '@libs/SearchUIUtils';
43+
import {getDatePresets, getFeedOptions, getGroupByOptions, getStatusOptions, getTypeOptions} from '@libs/SearchUIUtils';
4444
import CONST from '@src/CONST';
4545
import ONYXKEYS from '@src/ONYXKEYS';
4646
import ROUTES from '@src/ROUTES';
@@ -256,7 +256,7 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions, isMobileSelectionMod
256256
value={posted}
257257
onChange={onChange}
258258
closeOverlay={closeOverlay}
259-
presets={CONST.SEARCH.FILTER_DATE_PRESETS[CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED]}
259+
presets={getDatePresets(CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED, true)}
260260
/>
261261
);
262262
},
@@ -331,8 +331,8 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions, isMobileSelectionMod
331331

332332
// s77rt remove DEV lock
333333
const shouldDisplayGroupByFilter = isDevelopment;
334-
const shouldDisplayFeedFilter = feedOptions.length > 1 && !!filterFormValues?.feed;
335-
const shouldDisplayPostedFilter = groupBy?.value === CONST.SEARCH.GROUP_BY.CARDS;
334+
const shouldDisplayFeedFilter = feedOptions.length > 1 && !!filterFormValues.feed;
335+
const shouldDisplayPostedFilter = !!filterFormValues.feed && (!!filterFormValues.postedOn || !!filterFormValues.postedAfter || !!filterFormValues.postedBefore);
336336

337337
const filterList = [
338338
{
@@ -399,6 +399,9 @@ function SearchFiltersBar({queryJSON, headerButtonsOptions, isMobileSelectionMod
399399
displayPosted,
400400
filterFormValues.from,
401401
filterFormValues.feed,
402+
filterFormValues.postedOn,
403+
filterFormValues.postedAfter,
404+
filterFormValues.postedBefore,
402405
translate,
403406
typeComponent,
404407
groupByComponent,

src/components/Search/index.tsx

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import {
4444
shouldShowEmptyState,
4545
shouldShowYear as shouldShowYearUtil,
4646
} from '@libs/SearchUIUtils';
47-
import type {ArchivedReportsIDSet, SearchKey} from '@libs/SearchUIUtils';
47+
import type {ArchivedReportsIDSet} from '@libs/SearchUIUtils';
4848
import {isOnHold, isTransactionPendingDelete} from '@libs/TransactionUtils';
4949
import Navigation, {navigationRef} from '@navigation/Navigation';
5050
import type {SearchFullscreenNavigatorParamList} from '@navigation/types';
@@ -215,12 +215,42 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
215215
if (offset !== 0) {
216216
return false;
217217
}
218-
if (!searchKey) {
218+
if (queryJSON.type !== CONST.SEARCH.DATA_TYPES.EXPENSE) {
219219
return false;
220220
}
221-
const eligibleSearchKeys: Partial<SearchKey[]> = [CONST.SEARCH.SEARCH_KEYS.STATEMENTS, CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH, CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD];
222-
return eligibleSearchKeys.includes(searchKey);
223-
}, [offset, searchKey]);
221+
222+
let hasFeedFilter = false;
223+
let hasPostedFilter = false;
224+
let isReimbursable = false;
225+
226+
queryJSON.flatFilters.forEach((filter) => {
227+
if (filter.key === CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED) {
228+
hasFeedFilter = true;
229+
} else if (filter.key === CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED) {
230+
hasPostedFilter = true;
231+
} else if (filter.key === CONST.SEARCH.SYNTAX_FILTER_KEYS.REIMBURSABLE && filter.filters.at(0)?.value === CONST.SEARCH.BOOLEAN.YES) {
232+
isReimbursable = true;
233+
}
234+
});
235+
236+
/**
237+
* The total should be calculated for all accounting queries (statements, unapprovedCash and unapprovedCard)
238+
* We can't use `searchKey` directly because we want to also match similar queries e.g. the statements suggested search query with a custom feed should be matched too.
239+
*/
240+
const isStatementsLikeQuery = queryJSON.flatFilters.length === 2 && hasFeedFilter && hasPostedFilter;
241+
const isUnapprovedCashLikeQuery =
242+
queryJSON.flatFilters.length === 1 &&
243+
isReimbursable &&
244+
queryJSON.status[0] === CONST.SEARCH.STATUS.EXPENSE.DRAFTS &&
245+
queryJSON.status[1] === CONST.SEARCH.STATUS.EXPENSE.OUTSTANDING;
246+
const isUnapprovedCardLikeQuery =
247+
queryJSON.flatFilters.length === 1 &&
248+
hasFeedFilter &&
249+
queryJSON.status[0] === CONST.SEARCH.STATUS.EXPENSE.DRAFTS &&
250+
queryJSON.status[1] === CONST.SEARCH.STATUS.EXPENSE.OUTSTANDING;
251+
252+
return isStatementsLikeQuery || isUnapprovedCashLikeQuery || isUnapprovedCardLikeQuery;
253+
}, [offset, queryJSON.flatFilters, queryJSON.type, queryJSON.status]);
224254

225255
const previousReportActions = usePrevious(reportActions);
226256
const reportActionsArray = useMemo(

src/libs/SearchQueryUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,11 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial<SearchAdvanc
510510
filtersString.push(...mappedFilters);
511511

512512
DATE_FILTER_KEYS.forEach((dateKey) => {
513-
const dateFilter = buildDateFilterQuery(filterValues, dateKey);
513+
const dateFilter = buildDateFilterQuery(supportedFilterValues, dateKey);
514514
filtersString.push(dateFilter);
515515
});
516516

517-
const amountFilter = buildAmountFilterQuery(filterValues);
517+
const amountFilter = buildAmountFilterQuery(supportedFilterValues);
518518
filtersString.push(amountFilter);
519519

520520
return filtersString.filter(Boolean).join(' ').trim();

src/libs/SearchUIUtils.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type DotLottieAnimation from '@components/LottieAnimations/types';
88
import type {MenuItemWithLink} from '@components/MenuItemList';
99
import type {MultiSelectItem} from '@components/Search/FilterDropdowns/MultiSelectPopup';
1010
import type {SingleSelectItem} from '@components/Search/FilterDropdowns/SingleSelectPopup';
11-
import type {SearchColumnType, SearchGroupBy, SearchQueryJSON, SearchStatus, SingularSearchStatus, SortOrder} from '@components/Search/types';
11+
import type {SearchColumnType, SearchDateFilterKeys, SearchDatePreset, SearchGroupBy, SearchQueryJSON, SearchStatus, SingularSearchStatus, SortOrder} from '@components/Search/types';
1212
import ChatListItem from '@components/SelectionList/ChatListItem';
1313
import TaskListItem from '@components/SelectionList/Search/TaskListItem';
1414
import TransactionGroupListItem from '@components/SelectionList/Search/TransactionGroupListItem';
@@ -51,7 +51,6 @@ import type {CardFeedForDisplay} from './CardFeedUtils';
5151
import {getCardFeedsForDisplay} from './CardFeedUtils';
5252
import {convertToDisplayString} from './CurrencyUtils';
5353
import DateUtils from './DateUtils';
54-
import {isDevelopment} from './Environment/Environment';
5554
import interceptAnonymousUser from './interceptAnonymousUser';
5655
import {formatPhoneNumber} from './LocalePhoneNumber';
5756
import {translateLocal} from './Localize';
@@ -366,8 +365,8 @@ function getSuggestedSearchesVisibility(
366365
let shouldShowApproveSuggestion = false;
367366
let shouldShowExportSuggestion = false;
368367
let shouldShowStatementsSuggestion = false;
369-
let showShowUnapprovedCashSuggestion = false;
370-
let showShowUnapprovedCardSuggestion = false;
368+
let shouldShowUnapprovedCashSuggestion = false;
369+
let shouldShowUnapprovedCardSuggestion = false;
371370
let shouldShowReconciliationSuggestion = false;
372371

373372
Object.values(policies ?? {}).some((policy) => {
@@ -400,8 +399,8 @@ function getSuggestedSearchesVisibility(
400399
shouldShowApproveSuggestion ||= isEligibleForApproveSuggestion;
401400
shouldShowExportSuggestion ||= isEligibleForExportSuggestion;
402401
shouldShowStatementsSuggestion ||= isEligibleForStatementsSuggestion;
403-
showShowUnapprovedCashSuggestion ||= isEligibleForUnapprovedCashSuggestion;
404-
showShowUnapprovedCardSuggestion ||= isEligibleForUnapprovedCardSuggestion;
402+
shouldShowUnapprovedCashSuggestion ||= isEligibleForUnapprovedCashSuggestion;
403+
shouldShowUnapprovedCardSuggestion ||= isEligibleForUnapprovedCardSuggestion;
405404
shouldShowReconciliationSuggestion ||= isEligibleForReconciliationSuggestion;
406405

407406
// We don't need to check the rest of the policies if we already determined that all suggestions should be displayed
@@ -411,8 +410,8 @@ function getSuggestedSearchesVisibility(
411410
shouldShowApproveSuggestion &&
412411
shouldShowExportSuggestion &&
413412
shouldShowStatementsSuggestion &&
414-
showShowUnapprovedCashSuggestion &&
415-
showShowUnapprovedCardSuggestion &&
413+
shouldShowUnapprovedCashSuggestion &&
414+
shouldShowUnapprovedCardSuggestion &&
416415
shouldShowReconciliationSuggestion
417416
);
418417
});
@@ -425,10 +424,9 @@ function getSuggestedSearchesVisibility(
425424
[CONST.SEARCH.SEARCH_KEYS.PAY]: shouldShowPaySuggestion,
426425
[CONST.SEARCH.SEARCH_KEYS.APPROVE]: shouldShowApproveSuggestion,
427426
[CONST.SEARCH.SEARCH_KEYS.EXPORT]: shouldShowExportSuggestion,
428-
// s77rt remove DEV lock
429-
[CONST.SEARCH.SEARCH_KEYS.STATEMENTS]: shouldShowStatementsSuggestion && isDevelopment(),
430-
[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH]: showShowUnapprovedCashSuggestion,
431-
[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD]: showShowUnapprovedCardSuggestion,
427+
[CONST.SEARCH.SEARCH_KEYS.STATEMENTS]: shouldShowStatementsSuggestion,
428+
[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH]: shouldShowUnapprovedCashSuggestion,
429+
[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD]: shouldShowUnapprovedCardSuggestion,
432430
};
433431
}
434432

@@ -1857,6 +1855,17 @@ function getFeedOptions(allCardFeeds: OnyxCollection<OnyxTypes.CardFeeds>, allCa
18571855
}));
18581856
}
18591857

1858+
function getDatePresets(filterKey: SearchDateFilterKeys, hasFeed: boolean): SearchDatePreset[] | undefined {
1859+
switch (filterKey) {
1860+
case CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED:
1861+
return [...(hasFeed ? [CONST.SEARCH.DATE_PRESETS.LAST_STATEMENT] : []), CONST.SEARCH.DATE_PRESETS.LAST_MONTH];
1862+
case CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED:
1863+
return [CONST.SEARCH.DATE_PRESETS.NEVER];
1864+
default:
1865+
return undefined;
1866+
}
1867+
}
1868+
18601869
export {
18611870
getSuggestedSearches,
18621871
getListItem,
@@ -1890,5 +1899,6 @@ export {
18901899
getWideAmountIndicators,
18911900
isTransactionAmountTooLong,
18921901
isTransactionTaxAmountTooLong,
1902+
getDatePresets,
18931903
};
18941904
export type {SavedSearchMenuItem, SearchTypeMenuSection, SearchTypeMenuItem, SearchDateModifier, SearchDateModifierLower, SearchKey, ArchivedReportsIDSet};

src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExportedPage.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ function SearchFiltersExportedPage() {
77
<SearchDatePresetFilterBasePage
88
dateKey={CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED}
99
titleKey="search.filters.exported"
10-
presets={CONST.SEARCH.FILTER_DATE_PRESETS[CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED]}
1110
/>
1211
);
1312
}

src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersPostedPage.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ function SearchFiltersPostedPage() {
77
<SearchDatePresetFilterBasePage
88
dateKey={CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED}
99
titleKey="search.filters.posted"
10-
presets={CONST.SEARCH.FILTER_DATE_PRESETS[CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED]}
1110
/>
1211
);
1312
}

0 commit comments

Comments
 (0)