Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Search v2] [App] Use new query syntax #45617

Merged
Show file tree
Hide file tree
Changes from 15 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
11 changes: 9 additions & 2 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5233,12 +5233,20 @@ const CONST = {
ASC: 'asc',
DESC: 'desc',
},
TAB: {
STATUS: {
ALL: 'all',
SHARED: 'shared',
DRAFTS: 'drafts',
FINISHED: 'finished',
},
TAB: {
EXPENSE: {
ALL: 'type:expense status:all',
SHARED: 'type:expense status:shared',
DRAFTS: 'type:expense status:drafts',
FINISHED: 'type:expense status:finished',
},
},
TABLE_COLUMNS: {
RECEIPT: 'receipt',
DATE: 'date',
Expand Down Expand Up @@ -5268,7 +5276,6 @@ const CONST = {
STATUS: 'status',
SORT_BY: 'sortBy',
SORT_ORDER: 'sortOrder',
OFFSET: 'offset',
},
SYNTAX_FILTER_KEYS: {
DATE: 'date',
Expand Down
25 changes: 7 additions & 18 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import type {TupleToUnion, ValueOf} from 'type-fest';
import type {SearchQueryString} from './components/Search/types';
import type CONST from './CONST';
import type {IOUAction, IOUType} from './CONST';
import type {IOURequestType} from './libs/actions/IOU';
import type {AuthScreensParamList} from './libs/Navigation/types';
import type {ConnectionName, SageIntacctMappingName} from './types/onyx/Policy';
import type {SearchQuery} from './types/onyx/SearchResults';
import type AssertTypesNotEqual from './types/utils/AssertTypesNotEqual';

// This is a file containing constants for all the routes we want to be able to go to
Expand Down Expand Up @@ -37,16 +36,9 @@ const ROUTES = {
ALL_SETTINGS: 'all-settings',

SEARCH_CENTRAL_PANE: {
route: '/search/:query',
getRoute: (searchQuery: SearchQuery, queryParams?: AuthScreensParamList['Search_Central_Pane']) => {
const {sortBy, sortOrder} = queryParams ?? {};

if (!sortBy && !sortOrder) {
return `search/${searchQuery}` as const;
}

return `search/${searchQuery}?sortBy=${sortBy}&sortOrder=${sortOrder}` as const;
},
route: 'search',
getRoute: ({query, isCustomQuery = false, policyIDs}: {query: SearchQueryString; isCustomQuery?: boolean; policyIDs?: string}) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add a comment explaining why we are introducing the isCustomQuery param and what it is/will be doing?

Copy link
Contributor

@Kicu Kicu Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adam is back on Tuesday next week, and I simply don't know why this is needed, so we need to wait for him to add the comment.
Perhaps we could merge without it, I will ask @luacmartins

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed for filters since selecting any filter will navigate the user to the Search Results page that's being implemented here. I know it's a bit out of place now, but we should just leave this in place.

`search?q=${query}&isCustomQuery=${isCustomQuery}${policyIDs ? `&policyIDs=${policyIDs}` : ''}` as const,
luacmartins marked this conversation as resolved.
Show resolved Hide resolved
},

SEARCH_ADVANCED_FILTERS: 'search/filters',
Expand All @@ -56,14 +48,11 @@ const ROUTES = {
SEARCH_ADVANCED_FILTERS_TYPE: 'search/filters/type',

SEARCH_REPORT: {
route: 'search/:query/view/:reportID',
getRoute: (query: string, reportID: string) => `search/${query}/view/${reportID}` as const,
route: 'search/view/:reportID',
getRoute: (reportID: string) => `search/view/${reportID}` as const,
},

TRANSACTION_HOLD_REASON_RHP: {
route: 'search/:query/hold',
getRoute: (query: string) => `search/${query}/hold` as const,
},
TRANSACTION_HOLD_REASON_RHP: 'search/hold',

// This is a utility route used to go to the user's concierge chat, or the sign-in page if the user's not authenticated
CONCIERGE: 'concierge',
Expand Down
5 changes: 2 additions & 3 deletions src/components/PromotedActionsBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as HeaderUtils from '@libs/HeaderUtils';
import * as Localize from '@libs/Localize';
import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
import type {AuthScreensParamList, RootStackParamList, State} from '@libs/Navigation/types';
import type {RootStackParamList, State} from '@libs/Navigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import * as ReportActions from '@userActions/Report';
import * as Session from '@userActions/Session';
Expand Down Expand Up @@ -85,8 +85,7 @@ const PromotedActions = {
return;
}

const currentQuery = topmostCentralPaneRoute?.params as AuthScreensParamList['Search_Central_Pane'];
ReportUtils.changeMoneyRequestHoldStatus(reportAction, ROUTES.SEARCH_REPORT.getRoute(currentQuery?.query ?? CONST.SEARCH.TAB.ALL, reportAction?.childReportID ?? ''));
ReportUtils.changeMoneyRequestHoldStatus(reportAction, ROUTES.SEARCH_REPORT.getRoute(reportAction?.childReportID ?? ''));
},
}),
} satisfies PromotedActionsType;
Expand Down
10 changes: 5 additions & 5 deletions src/components/Search/SearchListWithHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import useWindowDimensions from '@hooks/useWindowDimensions';
import * as SearchActions from '@libs/actions/Search';
import * as SearchUtils from '@libs/SearchUtils';
import CONST from '@src/CONST';
import type {SearchDataTypes, SearchQuery, SearchReport} from '@src/types/onyx/SearchResults';
import type {SearchDataTypes, SearchReport} from '@src/types/onyx/SearchResults';
import SearchPageHeader from './SearchPageHeader';
import type {SelectedTransactionInfo, SelectedTransactions} from './types';
import type {SearchStatus, SelectedTransactionInfo, SelectedTransactions} from './types';

type SearchListWithHeaderProps = Omit<BaseSelectionListProps<ReportListItemType | TransactionListItemType>, 'onSelectAll' | 'onCheckboxPress' | 'sections'> & {
query: SearchQuery;
status: SearchStatus;
hash: number;
data: TransactionListItemType[] | ReportListItemType[];
searchType: SearchDataTypes;
Expand All @@ -44,7 +44,7 @@ function mapToItemWithSelectionInfo(item: TransactionListItemType | ReportListIt
}

function SearchListWithHeader(
{ListItem, onSelectRow, query, hash, data, searchType, isMobileSelectionModeActive, setIsMobileSelectionModeActive, ...props}: SearchListWithHeaderProps,
{ListItem, onSelectRow, status, hash, data, searchType, isMobileSelectionModeActive, setIsMobileSelectionModeActive, ...props}: SearchListWithHeaderProps,
ref: ForwardedRef<SelectionListHandle>,
) {
const {isSmallScreenWidth} = useWindowDimensions();
Expand Down Expand Up @@ -188,7 +188,7 @@ function SearchListWithHeader(
<SearchPageHeader
selectedTransactions={selectedTransactions}
clearSelectedItems={clearSelectedItems}
query={query}
status={status}
hash={hash}
onSelectDeleteOption={handleOnSelectDeleteOption}
isMobileSelectionModeActive={isMobileSelectionModeActive}
Expand Down
20 changes: 10 additions & 10 deletions src/components/Search/SearchPageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import SearchSelectedNarrow from '@pages/Search/SearchSelectedNarrow';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {SearchQuery, SearchReport} from '@src/types/onyx/SearchResults';
import type {SearchReport} from '@src/types/onyx/SearchResults';
import type DeepValueOf from '@src/types/utils/DeepValueOf';
import type IconAsset from '@src/types/utils/IconAsset';
import getDownloadOption from './SearchActionOptionsUtils';
import {useSearchContext} from './SearchContext';
import type {SelectedTransactions} from './types';
import type {SearchStatus, SelectedTransactions} from './types';

type SearchPageHeaderProps = {
query: SearchQuery;
status: SearchStatus;
selectedTransactions?: SelectedTransactions;
selectedReports?: Array<SearchReport['reportID']>;
clearSelectedItems?: () => void;
Expand All @@ -39,7 +39,7 @@ type SearchPageHeaderProps = {
type SearchHeaderOptionValue = DeepValueOf<typeof CONST.SEARCH.BULK_ACTION_TYPES> | undefined;

function SearchPageHeader({
query,
status,
adamgrzybowski marked this conversation as resolved.
Show resolved Hide resolved
selectedTransactions = {},
hash,
clearSelectedItems,
Expand All @@ -58,7 +58,7 @@ function SearchPageHeader({
const {isSmallScreenWidth} = useResponsiveLayout();
const {setSelectedTransactionIDs} = useSearchContext();

const headerContent: {[key in SearchQuery]: {icon: IconAsset; title: string}} = {
const headerContent: {[key in SearchStatus]: {icon: IconAsset; title: string}} = {
all: {icon: Illustrations.MoneyReceipts, title: translate('common.expenses')},
shared: {icon: Illustrations.SendMoney, title: translate('common.shared')},
drafts: {icon: Illustrations.Pencil, title: translate('common.drafts')},
Expand All @@ -81,7 +81,7 @@ function SearchPageHeader({
return;
}

SearchActions.exportSearchItemsToCSV(query, selectedReports, selectedTransactionsKeys, [activeWorkspaceID ?? ''], () => {
SearchActions.exportSearchItemsToCSV(status, selectedReports, selectedTransactionsKeys, [activeWorkspaceID ?? ''], () => {
setDownloadErrorModalOpen?.();
});
});
Expand Down Expand Up @@ -109,7 +109,7 @@ function SearchPageHeader({
setIsMobileSelectionModeActive?.(false);
}
setSelectedTransactionIDs(selectedTransactionsKeys);
Navigation.navigate(ROUTES.TRANSACTION_HOLD_REASON_RHP.getRoute(query));
Navigation.navigate(ROUTES.TRANSACTION_HOLD_REASON_RHP);
},
});
}
Expand Down Expand Up @@ -176,6 +176,7 @@ function SearchPageHeader({

return options;
}, [
status,
selectedTransactionsKeys,
selectedTransactions,
translate,
Expand All @@ -187,7 +188,6 @@ function SearchPageHeader({
theme.icon,
styles.colorMuted,
styles.fontWeightNormal,
query,
isOffline,
setOfflineModalOpen,
setDownloadErrorModalOpen,
Expand All @@ -211,8 +211,8 @@ function SearchPageHeader({

return (
<HeaderWithBackButton
title={headerContent[query]?.title}
icon={headerContent[query]?.icon}
title={headerContent[status]?.title}
icon={headerContent[status]?.icon}
shouldShowBackButton={false}
>
{headerButtonsOptions.length > 0 && (
Expand Down
43 changes: 22 additions & 21 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,35 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SearchResults from '@src/types/onyx/SearchResults';
import type {SearchDataTypes, SearchQuery} from '@src/types/onyx/SearchResults';
import type {SearchDataTypes} from '@src/types/onyx/SearchResults';
import {useSearchContext} from './SearchContext';
import SearchListWithHeader from './SearchListWithHeader';
import SearchPageHeader from './SearchPageHeader';
import type {SearchColumnType, SortOrder} from './types';
import type {SearchColumnType, SearchQueryJSON, SearchStatus, SortOrder} from './types';

type SearchProps = {
query: SearchQuery;
queryJSON: SearchQueryJSON;
policyIDs?: string;
sortBy?: SearchColumnType;
sortOrder?: SortOrder;
isMobileSelectionModeActive?: boolean;
setIsMobileSelectionModeActive?: (isMobileSelectionModeActive: boolean) => void;
};

const sortableSearchTabs: SearchQuery[] = [CONST.SEARCH.TAB.ALL];
const sortableSearchTabs: SearchStatus[] = [CONST.SEARCH.STATUS.ALL];
const transactionItemMobileHeight = 100;
const reportItemTransactionHeight = 52;
const listItemPadding = 12; // this is equivalent to 'mb3' on every transaction/report list item
const searchHeaderHeight = 54;
function Search({query, policyIDs, sortBy, sortOrder, isMobileSelectionModeActive, setIsMobileSelectionModeActive}: SearchProps) {
function Search({queryJSON, policyIDs, isMobileSelectionModeActive, setIsMobileSelectionModeActive}: SearchProps) {
const {isOffline} = useNetwork();
const styles = useThemeStyles();
const {isLargeScreenWidth, isSmallScreenWidth} = useWindowDimensions();
const navigation = useNavigation<StackNavigationProp<AuthScreensParamList>>();
const lastSearchResultsRef = useRef<OnyxEntry<SearchResults>>();
const {setCurrentSearchHash} = useSearchContext();
const [offset, setOffset] = React.useState(0);

const {status, sortBy, sortOrder, hash} = queryJSON;

const hash = SearchUtils.getQueryHash(query, policyIDs, sortBy, sortOrder);
const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`);

const getItemHeight = useCallback(
Expand Down Expand Up @@ -96,9 +96,10 @@ function Search({query, policyIDs, sortBy, sortOrder, isMobileSelectionModeActiv
}

setCurrentSearchHash(hash);
SearchActions.search({hash, query, policyIDs, offset: 0, sortBy, sortOrder});

SearchActions.search({hash, query: status, policyIDs, offset, sortBy, sortOrder});
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [hash, isOffline]);
}, [hash, isOffline, offset]);

const isDataLoaded = searchResults?.data !== undefined;
const shouldShowLoadingState = !isOffline && !isDataLoaded;
Expand All @@ -108,7 +109,7 @@ function Search({query, policyIDs, sortBy, sortOrder, isMobileSelectionModeActiv
return (
<>
<SearchPageHeader
query={query}
status={status}
hash={hash}
/>
<SearchRowSkeleton shouldAnimate />
Expand All @@ -122,7 +123,7 @@ function Search({query, policyIDs, sortBy, sortOrder, isMobileSelectionModeActiv
return (
<>
<SearchPageHeader
query={query}
status={status}
hash={hash}
/>
<EmptySearchView />
Expand All @@ -143,15 +144,14 @@ function Search({query, policyIDs, sortBy, sortOrder, isMobileSelectionModeActiv
SearchActions.createTransactionThread(hash, item.transactionID, reportID, item.moneyRequestReportActionID);
}

Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute(query, reportID));
Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute(reportID));
};

const fetchMoreResults = () => {
if (!searchResults?.search?.hasMoreResults || shouldShowLoadingState || shouldShowLoadingMoreItems) {
return;
}
const currentOffset = searchResults?.search?.offset ?? 0;
SearchActions.search({hash, query, offset: currentOffset + CONST.SEARCH.RESULTS_PAGE_SIZE, sortBy, sortOrder});
setOffset(offset + CONST.SEARCH.RESULTS_PAGE_SIZE);
};

const type = SearchUtils.getSearchType(searchResults?.search);
Expand All @@ -167,21 +167,22 @@ function Search({query, policyIDs, sortBy, sortOrder, isMobileSelectionModeActiv
const sortedData = SearchUtils.getSortedSections(type, data, sortBy, sortOrder);

const onSortPress = (column: SearchColumnType, order: SortOrder) => {
navigation.setParams({
sortBy: column,
sortOrder: order,
});
const currentSearchParams = SearchUtils.getCurrentSearchParams();
const currentQueryJSON = SearchUtils.buildSearchQueryJSON(currentSearchParams.q, policyIDs);

const newQuery = SearchUtils.buildSearchQueryString({...currentQueryJSON, sortBy: column, sortOrder: order});
navigation.setParams({q: newQuery});
};

const isSortingAllowed = sortableSearchTabs.includes(query);
const isSortingAllowed = sortableSearchTabs.includes(status);

const shouldShowYear = SearchUtils.shouldShowYear(searchResults?.data);

const canSelectMultiple = isSmallScreenWidth ? isMobileSelectionModeActive : true;

return (
<SearchListWithHeader
query={query}
status={status}
hash={hash}
data={sortedData}
searchType={searchResults?.search?.type as SearchDataTypes}
Expand Down
32 changes: 31 additions & 1 deletion src/components/Search/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type SelectedTransactions = Record<string, SelectedTransactionInfo>;

type SortOrder = ValueOf<typeof CONST.SEARCH.SORT_ORDER>;
type SearchColumnType = ValueOf<typeof CONST.SEARCH.TABLE_COLUMNS>;
type SearchStatus = ValueOf<typeof CONST.SEARCH.STATUS>;

type SearchContext = {
currentSearchHash: number;
Expand All @@ -49,4 +50,33 @@ type QueryFilters = {
[K in AllFieldKeys]: QueryFilter | QueryFilter[];
};

export type {SelectedTransactionInfo, SelectedTransactions, SearchColumnType, SortOrder, SearchContext, ASTNode, QueryFilter, QueryFilters, AllFieldKeys};
type SearchQueryString = string;

type SearchQueryAST = {
type: string;
status: SearchStatus;
sortBy: SearchColumnType;
sortOrder: SortOrder;
filters: ASTNode;
};

type SearchQueryJSON = {
input: string;
hash: number;
} & SearchQueryAST;

export type {
SelectedTransactionInfo,
SelectedTransactions,
SearchColumnType,
SearchStatus,
SearchQueryAST,
SearchQueryJSON,
SearchQueryString,
SortOrder,
SearchContext,
ASTNode,
QueryFilter,
QueryFilters,
AllFieldKeys,
};
5 changes: 1 addition & 4 deletions src/components/SelectionList/Search/ReportListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import Navigation from '@libs/Navigation/Navigation';
import {getSearchParams} from '@libs/SearchUtils';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import ActionCell from './ActionCell';
Expand Down Expand Up @@ -85,9 +84,7 @@ function ReportListItem<TItem extends ListItem>({
};

const openReportInRHP = (transactionItem: TransactionListItemType) => {
const searchParams = getSearchParams();
const currentQuery = searchParams?.query ?? CONST.SEARCH.TAB.ALL;
Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute(currentQuery, transactionItem.transactionThreadReportID));
Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute(transactionItem.transactionThreadReportID));
};

if (!reportItem?.reportName && reportItem.transactions.length > 1) {
Expand Down
Loading
Loading