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

add display name replacement and make search page router editable #49838

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
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
Loading