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
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
Copy Markdown
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?

@Kicu Kicu Jul 25, 2024

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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,
Comment thread
luacmartins marked this conversation as 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,
Comment thread
adamgrzybowski marked this conversation as 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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We increased the offset here but we forgot to reset it when we changed the tab, once offset was increased here and we changed the tab, it kept the old offset which led to the wrong data arriving.
More details:
#55235 (comment)

};

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