Skip to content

Commit

Permalink
Merge pull request #49838 from software-mansion-labs/289Adam289/49121…
Browse files Browse the repository at this point in the history
…-add-ids-search-router-input

add display name replacement and make search page router editable
  • Loading branch information
luacmartins authored Oct 11, 2024
2 parents 45a3a13 + 5201fce commit 2f1b6f1
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 69 deletions.
7 changes: 6 additions & 1 deletion src/components/Search/SearchContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const defaultSearchContext = {
clearSelectedTransactions: () => {},
shouldShowStatusBarLoading: false,
setShouldShowStatusBarLoading: () => {},
lastSearchType: undefined,
setLastSearchType: () => {},
};

const Context = React.createContext<SearchContext>(defaultSearchContext);
Expand Down Expand Up @@ -69,6 +71,7 @@ function SearchContextProvider({children}: ChildrenProps) {
);

const [shouldShowStatusBarLoading, setShouldShowStatusBarLoading] = useState(false);
const [lastSearchType, setLastSearchType] = useState<string | undefined>(undefined);

const searchContext = useMemo<SearchContext>(
() => ({
Expand All @@ -78,8 +81,10 @@ function SearchContextProvider({children}: ChildrenProps) {
clearSelectedTransactions,
shouldShowStatusBarLoading,
setShouldShowStatusBarLoading,
lastSearchType,
setLastSearchType,
}),
[searchContextData, setCurrentSearchHash, setSelectedTransactions, clearSelectedTransactions, shouldShowStatusBarLoading],
[searchContextData, setCurrentSearchHash, setSelectedTransactions, clearSelectedTransactions, shouldShowStatusBarLoading, lastSearchType, setLastSearchType],
);

return <Context.Provider value={searchContext}>{children}</Context.Provider>;
Expand Down
50 changes: 40 additions & 10 deletions src/components/Search/SearchPageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useMemo, useState} from 'react';
import React, {useEffect, useMemo, useState} from 'react';
import {InteractionManager, View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
Expand All @@ -20,6 +20,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as SearchActions from '@libs/actions/Search';
import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import {getAllTaxRates} from '@libs/PolicyUtils';
import * as SearchUtils from '@libs/SearchUtils';
Expand All @@ -39,12 +40,14 @@ import type {SearchQueryJSON} from './types';

type HeaderWrapperProps = Pick<HeaderWithBackButtonProps, 'icon' | 'children'> & {
text: string;
value: string;
isCannedQuery: boolean;
onSubmit: () => void;
setValue: (input: string) => void;
};

function HeaderWrapper({icon, children, text, isCannedQuery}: HeaderWrapperProps) {
function HeaderWrapper({icon, children, text, value, isCannedQuery, onSubmit, setValue}: HeaderWrapperProps) {
const styles = useThemeStyles();

// If the icon is present, the header bar should be taller and use different font.
const isCentralPaneSettings = !!icon;

Expand All @@ -69,10 +72,11 @@ function HeaderWrapper({icon, children, text, isCannedQuery}: HeaderWrapperProps
) : (
<View style={styles.pr5}>
<SearchRouterInput
value={text}
setValue={() => {}}
value={value}
setValue={setValue}
onSubmit={onSubmit}
updateSearch={() => {}}
disabled
autoFocus={false}
isFullWidth
wrapperStyle={[styles.searchRouterInputResults, styles.br2]}
wrapperFocusedStyle={styles.searchRouterInputResultsFocused}
Expand Down Expand Up @@ -124,17 +128,25 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) {
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
const taxRates = getAllTaxRates();
const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST);
const [currencyList = {}] = useOnyx(ONYXKEYS.CURRENCY_LIST);
const [policyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES);
const [policyTagsLists] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS);
const [isDeleteExpensesConfirmModalVisible, setIsDeleteExpensesConfirmModalVisible] = useState(false);
const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false);
const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false);

const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {});

const {status, type} = queryJSON;
const isCannedQuery = SearchUtils.isCannedSearchQuery(queryJSON);
const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchUtils.getSearchHeaderTitle(queryJSON, personalDetails, cardList, reports, taxRates);
const [inputValue, setInputValue] = useState(headerText);

useEffect(() => {
setInputValue(headerText);
}, [headerText]);

const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {});

const headerIcon = getHeaderContent(type).icon;
const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchUtils.getSearchHeaderTitle(queryJSON, personalDetails, cardList, reports, taxRates);

const handleDeleteExpenses = () => {
if (selectedTransactionsKeys.length === 0) {
Expand Down Expand Up @@ -315,18 +327,36 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) {
}

const onPress = () => {
const filterFormValues = SearchUtils.buildFilterFormValuesFromQuery(queryJSON);
const filterFormValues = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, cardList, reports, taxRates);
SearchActions.updateAdvancedFilters(filterFormValues);

Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS);
};

const onSubmit = () => {
if (!inputValue) {
return;
}
const inputQueryJSON = SearchUtils.buildSearchQueryJSON(inputValue);
if (inputQueryJSON) {
const standardizedQuery = SearchUtils.standardizeQueryJSON(inputQueryJSON, cardList, taxRates);
const query = SearchUtils.buildSearchQueryString(standardizedQuery);
SearchActions.clearAllFilters();
Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query}));
} else {
Log.alert(`${CONST.ERROR.ENSURE_BUGBOT} user query failed to parse`, inputValue, false);
}
};

return (
<>
<HeaderWrapper
icon={headerIcon}
text={headerText}
value={inputValue}
isCannedQuery={isCannedQuery}
onSubmit={onSubmit}
setValue={setInputValue}
>
{headerButtonsOptions.length > 0 ? (
<ButtonWithDropdownMenu
Expand Down
7 changes: 6 additions & 1 deletion src/components/Search/SearchRouter/SearchRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import Log from '@libs/Log';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import {getAllTaxRates} from '@libs/PolicyUtils';
import type {OptionData} from '@libs/ReportUtils';
import * as SearchUtils from '@libs/SearchUtils';
import Navigation from '@navigation/Navigation';
Expand All @@ -39,6 +40,9 @@ function SearchRouter() {
const {isSearchRouterDisplayed, closeSearchRouter} = useSearchRouterContext();
const listRef = useRef<SelectionListHandle>(null);

const taxRates = getAllTaxRates();
const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST);

const [textInputValue, debouncedInputValue, setTextInputValue] = useDebouncedState('', 500);
const [userSearchQuery, setUserSearchQuery] = useState<SearchQueryJSON | undefined>(undefined);
const contextualReportID = useNavigationState<Record<string, {reportID: string}>, string | undefined>((state) => {
Expand Down Expand Up @@ -144,7 +148,8 @@ function SearchRouter() {
return;
}
closeSearchRouter();
const queryString = SearchUtils.buildSearchQueryString(query);
const standardizedQuery = SearchUtils.standardizeQueryJSON(query, cardList, taxRates);
const queryString = SearchUtils.buildSearchQueryString(standardizedQuery);
Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: queryString}));
clearUserQuery();
},
Expand Down
12 changes: 11 additions & 1 deletion src/components/Search/SearchRouter/SearchRouterInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ type SearchRouterInputProps = {
/** Callback to update search in SearchRouter */
updateSearch: (searchTerm: string) => void;

/** Callback invoked when the user submits the input */
onSubmit?: () => void;

/** SearchRouterList ref for managing TextInput and SearchRouterList focus */
routerListRef?: RefObject<SelectionListHandle>;

Expand All @@ -28,6 +31,9 @@ type SearchRouterInputProps = {
/** Whether the input is disabled */
disabled?: boolean;

/** Whether the input should be focused */
autoFocus?: boolean;

/** Any additional styles to apply */
wrapperStyle?: StyleProp<ViewStyle>;

Expand All @@ -45,9 +51,11 @@ function SearchRouterInput({
value,
setValue,
updateSearch,
onSubmit = () => {},
routerListRef,
isFullWidth,
disabled = false,
autoFocus = true,
wrapperStyle,
wrapperFocusedStyle,
rightComponent,
Expand All @@ -70,12 +78,14 @@ function SearchRouterInput({
<TextInput
value={value}
onChangeText={onChangeText}
autoFocus
autoFocus={autoFocus}
loadingSpinnerStyle={[styles.mt0, styles.mr2]}
role={CONST.ROLE.PRESENTATION}
placeholder={translate('search.searchPlaceholder')}
autoCapitalize="none"
autoCorrect={false}
disabled={disabled}
onSubmitEditing={onSubmit}
shouldUseDisabledStyles={false}
textInputContainerStyles={styles.borderNone}
inputStyle={[styles.searchInputStyle, inputWidth, styles.pl3, styles.pr3]}
Expand Down
14 changes: 6 additions & 8 deletions src/components/Search/SearchStatusBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ import type {TranslationPaths} from '@src/languages/types';
import type {SearchDataTypes} from '@src/types/onyx/SearchResults';
import type IconAsset from '@src/types/utils/IconAsset';
import {useSearchContext} from './SearchContext';
import type {ChatSearchStatus, ExpenseSearchStatus, InvoiceSearchStatus, SearchStatus, TripSearchStatus} from './types';
import type {ChatSearchStatus, ExpenseSearchStatus, InvoiceSearchStatus, SearchQueryJSON, TripSearchStatus} from './types';

type SearchStatusBarProps = {
type: SearchDataTypes;
status: SearchStatus;
policyID: string | undefined;
queryJSON: SearchQueryJSON;
onStatusChange?: () => void;
};

Expand Down Expand Up @@ -154,13 +152,13 @@ function getOptions(type: SearchDataTypes) {
}
}

function SearchStatusBar({type, status, policyID, onStatusChange}: SearchStatusBarProps) {
function SearchStatusBar({queryJSON, onStatusChange}: SearchStatusBarProps) {
const {singleExecution} = useSingleExecution();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const theme = useTheme();
const {translate} = useLocalize();
const options = getOptions(type);
const options = getOptions(queryJSON.type);
const scrollRef = useRef<RNScrollView>(null);
const isScrolledRef = useRef(false);
const {shouldShowStatusBarLoading} = useSearchContext();
Expand All @@ -179,10 +177,10 @@ function SearchStatusBar({type, status, policyID, onStatusChange}: SearchStatusB
{options.map((item, index) => {
const onPress = singleExecution(() => {
onStatusChange?.();
const query = SearchUtils.buildCannedSearchQuery({type: item.type, status: item.status, policyID});
const query = SearchUtils.buildSearchQueryString({...queryJSON, status: item.status});
Navigation.setParams({q: query});
});
const isActive = status === item.status;
const isActive = queryJSON.status === item.status;
const isFirstItem = index === 0;
const isLastItem = index === options.length - 1;

Expand Down
14 changes: 11 additions & 3 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
const {isSmallScreenWidth, isLargeScreenWidth} = useResponsiveLayout();
const navigation = useNavigation<StackNavigationProp<AuthScreensParamList>>();
const lastSearchResultsRef = useRef<OnyxEntry<SearchResults>>();
const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions, setShouldShowStatusBarLoading} = useSearchContext();
const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions, setShouldShowStatusBarLoading, lastSearchType, setLastSearchType} =
useSearchContext();
const {selectionMode} = useMobileSelectionMode();
const [offset, setOffset] = useState(0);

Expand All @@ -101,6 +102,13 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION);
const previousTransactions = usePrevious(transactions);

useEffect(() => {
if (!currentSearchResults?.search?.type) {
return;
}
setLastSearchType(currentSearchResults.search.type);
}, [lastSearchType, queryJSON, setLastSearchType, currentSearchResults]);

const canSelectMultiple = isSmallScreenWidth ? !!selectionMode?.isEnabled : true;

useEffect(() => {
Expand Down Expand Up @@ -184,8 +192,8 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr

useEffect(() => {
/** We only want to display the skeleton for the status filters the first time we load them for a specific data type */
setShouldShowStatusBarLoading(shouldShowLoadingState && searchResults?.search?.type !== type);
}, [searchResults?.search?.type, setShouldShowStatusBarLoading, shouldShowLoadingState, type]);
setShouldShowStatusBarLoading(shouldShowLoadingState && lastSearchType !== type);
}, [lastSearchType, setShouldShowStatusBarLoading, shouldShowLoadingState, type]);

useEffect(() => {
if (type === CONST.SEARCH.DATA_TYPES.CHAT) {
Expand Down
2 changes: 2 additions & 0 deletions src/components/Search/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type SearchContext = {
clearSelectedTransactions: (hash?: number) => void;
shouldShowStatusBarLoading: boolean;
setShouldShowStatusBarLoading: (shouldShow: boolean) => void;
setLastSearchType: (type: string | undefined) => void;
lastSearchType: string | undefined;
};

type ASTNode = {
Expand Down
Loading

0 comments on commit 2f1b6f1

Please sign in to comment.