Skip to content

Commit

Permalink
change contextual search logic
Browse files Browse the repository at this point in the history
  • Loading branch information
SzymczakJ committed Sep 25, 2024
1 parent 7df4c32 commit 48a4296
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 50 deletions.
5 changes: 5 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5578,6 +5578,11 @@ const CONST = {
KEYWORD: 'keyword',
IN: 'in',
},
ROUTER_LIST_ITEM_TYPE: {
REPORT: 'report',
SEARCH: 'search',
CONTEXTUAL_SUGGESTION: 'contextualSuggestion',
},
},

REFERRER: {
Expand Down
45 changes: 29 additions & 16 deletions src/components/Search/SearchRouter/SearchRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function SearchRouter() {
const {isSmallScreenWidth} = useResponsiveLayout();
const {isSearchRouterDisplayed, closeSearchRouter} = useSearchRouterContext();

const [textInputValue, setTextInputValue] = useState('');
const [userSearchQuery, setUserSearchQuery] = useState<SearchQueryJSON | undefined>(undefined);
const contextualReportID = useNavigationState<Record<string, {reportID: string}>, string | undefined>((state) => {
return state.routes.at(-1)?.params?.reportID;
Expand All @@ -56,26 +57,35 @@ function SearchRouter() {
const contextualReportData = contextualReportID ? searchOptions.recentReports?.find((option) => option.reportID === contextualReportID) : undefined;

const clearUserQuery = () => {
setTextInputValue('');
setUserSearchQuery(undefined);
};

const onSearchChange = debounce((userQuery: string) => {
if (!userQuery) {
clearUserQuery();
return;
}
const onSearchChange = useCallback(

Check warning on line 64 in src/components/Search/SearchRouter/SearchRouter.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead

Check warning on line 64 in src/components/Search/SearchRouter/SearchRouter.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

React Hook useCallback received a function whose dependencies are unknown. Pass an inline function instead
debounce((userQuery: string) => {

Check failure on line 65 in src/components/Search/SearchRouter/SearchRouter.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Expected the first argument to be an inline function expression

Check failure on line 65 in src/components/Search/SearchRouter/SearchRouter.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Expected the first argument to be an inline function expression
if (!userQuery) {
clearUserQuery();
return;
}

const queryJSON = SearchUtils.buildSearchQueryJSON(userQuery);
const queryJSON = SearchUtils.buildSearchQueryJSON(userQuery);

if (queryJSON) {
// eslint-disable-next-line
console.log('parsedQuery', queryJSON);
if (queryJSON) {
// eslint-disable-next-line
console.log('parsedQuery', queryJSON);

setUserSearchQuery(queryJSON);
} else {
// Handle query parsing error
}
}, SEARCH_DEBOUNCE_DELAY);
setUserSearchQuery(queryJSON);
} else {
// Handle query parsing error
}
}, SEARCH_DEBOUNCE_DELAY),
[],
);

const updateUserSearchQuery = (newSearchQuery: string) => {
setTextInputValue(newSearchQuery);
onSearchChange(newSearchQuery);
};

const closeAndClearRouter = useCallback(() => {
closeSearchRouter();
Expand Down Expand Up @@ -114,7 +124,9 @@ function SearchRouter() {
<FocusTrapForModal active={isSearchRouterDisplayed}>
<View style={[styles.flex1, styles.p3, modalWidth, styles.mh100, !isSmallScreenWidth && styles.mh85vh]}>
<SearchRouterInput
onChange={onSearchChange}
text={textInputValue}
setText={setTextInputValue}
updateSearch={onSearchChange}
onSubmit={() => {
onSearchSubmit(userSearchQuery);
}}
Expand All @@ -125,7 +137,8 @@ function SearchRouter() {
reportForContextualSearch={contextualReportData}
recentSearches={sortedRecentSearches}
recentReports={searchOptions?.recentReports?.slice(0, 5)}
onRecentSearchSelect={onSearchSubmit}
onSearchSubmit={onSearchSubmit}
updateUserSearchQuery={updateUserSearchQuery}
closeAndClearRouter={closeAndClearRouter}
/>
</View>
Expand Down
14 changes: 7 additions & 7 deletions src/components/Search/SearchRouter/SearchRouterInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';

type SearchRouterInputProps = {
onChange: (searchTerm: string) => void;
text: string;
setText: (searchTerm: string) => void;
updateSearch: (searchTerm: string) => void;
onSubmit: () => void;
};

function SearchRouterInput({onChange, onSubmit}: SearchRouterInputProps) {
function SearchRouterInput({text, setText, updateSearch, onSubmit}: SearchRouterInputProps) {
const styles = useThemeStyles();

const [value, setValue] = useState('');

const onChangeText = (text: string) => {

Check failure on line 16 in src/components/Search/SearchRouter/SearchRouterInput.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'text' is already declared in the upper scope on line 13 column 29

Check failure on line 16 in src/components/Search/SearchRouter/SearchRouterInput.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

'text' is already declared in the upper scope on line 13 column 29
setValue(text);
onChange(text);
setText(text);
updateSearch(text);
};

return (
<BaseTextInput
value={value}
value={text}
onChangeText={onChangeText}
onSubmitEditing={onSubmit}
autoFocus
Expand Down
69 changes: 43 additions & 26 deletions src/components/Search/SearchRouter/SearchRouterList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {useCallback} from 'react';
import * as Expensicons from '@components/Icon/Expensicons';
import type {SearchQueryJSON} from '@components/Search/types';
import type {SearchQueryJSON, SearchRouterListItem} from '@components/Search/types';
import SelectionList from '@components/SelectionList';
import SingleIconListItem from '@components/SelectionList/Search/SingleIconListItem';
import type {ListItemWithSingleIcon, SingleIconListItemProps} from '@components/SelectionList/Search/SingleIconListItem';
Expand All @@ -12,6 +12,7 @@ import Navigation from '@libs/Navigation/Navigation';
import type {OptionData} from '@libs/ReportUtils';
import * as SearchUtils from '@libs/SearchUtils';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';

type ItemWithQuery = {
Expand All @@ -23,16 +24,17 @@ type SearchRouterListProps = {
reportForContextualSearch?: OptionData;
recentSearches: ItemWithQuery[] | undefined;
recentReports: OptionData[];
onRecentSearchSelect: (query: SearchQueryJSON | undefined, shouldAddToRecentSearch?: boolean) => void;
onSearchSubmit: (query: SearchQueryJSON | undefined) => void;
updateUserSearchQuery: (newSearchQuery: string) => void;
closeAndClearRouter: () => void;
};

function SearchRouterItem(props: UserListItemProps<OptionData> | SingleIconListItemProps<ListItemWithSingleIcon & ItemWithQuery>) {
function SearchRouterItem(props: UserListItemProps<SearchRouterListItem> | SingleIconListItemProps<SearchRouterListItem>) {
const styles = useThemeStyles();

if ('item' in props && props.item.reportID) {
if (props.item.itemType === CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.REPORT) {
return (
<UserListItem
pressableStyle={styles.br2}
// eslint-disable-next-line react/jsx-props-no-spreading
{...(props as UserListItemProps<OptionData>)}
/>
Expand All @@ -42,10 +44,10 @@ function SearchRouterItem(props: UserListItemProps<OptionData> | SingleIconListI
return <SingleIconListItem {...(props as SingleIconListItemProps<ListItemWithSingleIcon & ItemWithQuery>)} />;
}

function SearchRouterList({currentQuery, reportForContextualSearch, recentSearches, recentReports, onRecentSearchSelect, closeAndClearRouter}: SearchRouterListProps) {
function SearchRouterList({currentQuery, reportForContextualSearch, recentSearches, recentReports, onSearchSubmit, updateUserSearchQuery, closeAndClearRouter}: SearchRouterListProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const sections: Array<SectionListDataType<OptionData | (ListItemWithSingleIcon & ItemWithQuery)>> = [];
const sections: Array<SectionListDataType<SearchRouterListItem>> = [];

if (currentQuery?.inputQuery) {
sections.push({
Expand All @@ -56,6 +58,7 @@ function SearchRouterList({currentQuery, reportForContextualSearch, recentSearch
query: currentQuery?.inputQuery,
itemStyle: styles.activeComponentBG,
keyForList: 'findItem',
itemType: CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.SEARCH,
},
],
});
Expand All @@ -67,10 +70,10 @@ function SearchRouterList({currentQuery, reportForContextualSearch, recentSearch
{
text: `${translate('search.searchIn')}${reportForContextualSearch.text ?? reportForContextualSearch.alternateText}`,
singleIcon: Expensicons.MagnifyingGlass,
// We will change it to different behaviour when Search 2.5 autocomplete will be implemented
query: `in:${reportForContextualSearch.reportID}`,
itemStyle: styles.activeComponentBG,
keyForList: 'contextualSearch',
itemType: CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.CONTEXTUAL_SUGGESTION,
},
],
});
Expand All @@ -81,37 +84,50 @@ function SearchRouterList({currentQuery, reportForContextualSearch, recentSearch
singleIcon: Expensicons.History,
query,
keyForList: query,
itemType: CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.SEARCH,
}));

if (recentSearchesData && recentSearchesData.length > 0) {
sections.push({title: translate('search.recentSearches'), data: recentSearchesData});
}

const styledRecentReports = recentReports.map((item) => ({...item, pressableStyle: styles.br2}));
sections.push({title: translate('search.recentChats'), data: styledRecentReports});
const recentReportsData = recentReports.map((item) => ({...item, pressableStyle: styles.br2, itemType: CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.REPORT}));
sections.push({title: translate('search.recentChats'), data: recentReportsData});

const onSelectRow = useCallback(
(item: OptionData | ItemWithQuery) => {
// Handle selection of "Recent search"
if ('query' in item && item?.query) {
const queryJSON = SearchUtils.buildSearchQueryJSON(item?.query);
onRecentSearchSelect(queryJSON, true);
return;
}

// Handle selection of "Recent chat"
closeAndClearRouter();
if ('reportID' in item && item?.reportID) {
Navigation.closeAndNavigate(ROUTES.REPORT_WITH_ID.getRoute(item?.reportID));
} else if ('login' in item) {
Report.navigateToAndOpenReport(item?.login ? [item.login] : []);
(item: SearchRouterListItem) => {
switch (item.itemType) {

Check failure on line 99 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Expected a default case

Check failure on line 99 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Switch is not exhaustive. Cases not matched: undefined

Check failure on line 99 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Expected a default case

Check failure on line 99 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Switch is not exhaustive. Cases not matched: undefined
case CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.SEARCH:
// Handle selection of "Recent search"
if (!('query' in item) || !item?.query) {
return;
}
const queryJSON = SearchUtils.buildSearchQueryJSON(item?.query);

Check failure on line 105 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Unexpected lexical declaration in case block

Check failure on line 105 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Unexpected lexical declaration in case block
onSearchSubmit(queryJSON);
return;
case CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.CONTEXTUAL_SUGGESTION:
// Handle selection of "Contextual search suggestion"
if (!('query' in item) || !item?.query || currentQuery?.inputQuery.includes(item?.query)) {
return;
}
updateUserSearchQuery(`${item?.query} ${currentQuery?.inputQuery ?? ''}`);
return;
case CONST.SEARCH.ROUTER_LIST_ITEM_TYPE.REPORT:
// Handle selection of "Recent chat"
closeAndClearRouter();
if ('reportID' in item && item?.reportID) {
Navigation.closeAndNavigate(ROUTES.REPORT_WITH_ID.getRoute(item?.reportID));
} else if ('login' in item) {
Report.navigateToAndOpenReport(item?.login ? [item.login] : []);
}
return;

Check failure on line 123 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Unnecessary return statement

Check failure on line 123 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

Unnecessary return statement
}
},
[closeAndClearRouter, onRecentSearchSelect],
[closeAndClearRouter, onSearchSubmit, currentQuery],

Check warning on line 126 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useCallback has a missing dependency: 'updateUserSearchQuery'. Either include it or remove the dependency array. If 'updateUserSearchQuery' changes too often, find the parent component that defines it and wrap that definition in useCallback

Check warning on line 126 in src/components/Search/SearchRouter/SearchRouterList.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

React Hook useCallback has a missing dependency: 'updateUserSearchQuery'. Either include it or remove the dependency array. If 'updateUserSearchQuery' changes too often, find the parent component that defines it and wrap that definition in useCallback
);

return (
<SelectionList<OptionData | (ListItemWithSingleIcon & ItemWithQuery)>
<SelectionList<SearchRouterListItem>
sections={sections}
onSelectRow={onSelectRow}
ListItem={SearchRouterItem}
Expand All @@ -122,3 +138,4 @@ function SearchRouterList({currentQuery, reportForContextualSearch, recentSearch

export default SearchRouterList;
export {SearchRouterItem};
export type {ItemWithQuery};
7 changes: 7 additions & 0 deletions src/components/Search/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type {ValueOf} from 'react-native-gesture-handler/lib/typescript/typeUtils';
import type {ListItemWithSingleIcon, SingleIconListItemProps} from '@components/SelectionList/Search/SingleIconListItem';

Check failure on line 2 in src/components/Search/types.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'SingleIconListItemProps' is defined but never used

Check failure on line 2 in src/components/Search/types.ts

View workflow job for this annotation

GitHub Actions / ESLint check

'SingleIconListItemProps' is defined but never used
import type {ListItemProps, UserListItemProps} from '@components/SelectionList/types';

Check failure on line 3 in src/components/Search/types.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'ListItemProps' is defined but never used

Check failure on line 3 in src/components/Search/types.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'UserListItemProps' is defined but never used

Check failure on line 3 in src/components/Search/types.ts

View workflow job for this annotation

GitHub Actions / ESLint check

'ListItemProps' is defined but never used

Check failure on line 3 in src/components/Search/types.ts

View workflow job for this annotation

GitHub Actions / ESLint check

'UserListItemProps' is defined but never used
import type {OptionData} from '@libs/ReportUtils';
import type CONST from '@src/CONST';
import type {SearchDataTypes} from '@src/types/onyx/SearchResults';
import type {ItemWithQuery} from './SearchRouter/SearchRouterList';

/** Model of the selected transaction */
type SelectedTransactionInfo = {
Expand Down Expand Up @@ -73,6 +77,8 @@ type SearchQueryJSON = {
flatFilters: QueryFilters;
} & SearchQueryAST;

type SearchRouterListItem = (OptionData | (ListItemWithSingleIcon & ItemWithQuery)) & {itemType?: ValueOf<typeof CONST.SEARCH.ROUTER_LIST_ITEM_TYPE>};

export type {
SelectedTransactionInfo,
SelectedTransactions,
Expand All @@ -91,4 +97,5 @@ export type {
InvoiceSearchStatus,
TripSearchStatus,
ChatSearchStatus,
SearchRouterListItem,
};
2 changes: 1 addition & 1 deletion src/components/SelectionList/Search/SingleIconListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import type IconAsset from '@src/types/utils/IconAsset';

type ListItemWithSingleIcon = {singleIcon: IconAsset} & ListItem;
type ListItemWithSingleIcon = {singleIcon?: IconAsset} & ListItem;

type SingleIconListItemProps<TItem extends ListItemWithSingleIcon> = {
item: TItem;
Expand Down

0 comments on commit 48a4296

Please sign in to comment.