From 6d612005b01dfb8a9b52d9bf30b3086b689d9963 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Mon, 9 Sep 2024 16:46:42 +0200 Subject: [PATCH 1/7] Add initial SearchRouter component and context to display it --- src/App.tsx | 2 + src/CONST.ts | 1 - src/components/Search/SearchPageHeader.tsx | 2 + .../Search/SearchRouter/SearchButton.tsx | 37 +++++++++++ .../Search/SearchRouter/SearchRouter.tsx | 64 +++++++++++++++++++ .../SearchRouter/SearchRouterContext.tsx | 33 ++++++++++ .../Search/SearchRouter/SearchRouterInput.tsx | 50 +++++++++++++++ .../Navigation/AppNavigator/AuthScreens.tsx | 2 + 8 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 src/components/Search/SearchRouter/SearchButton.tsx create mode 100644 src/components/Search/SearchRouter/SearchRouter.tsx create mode 100644 src/components/Search/SearchRouter/SearchRouterContext.tsx create mode 100644 src/components/Search/SearchRouter/SearchRouterInput.tsx diff --git a/src/App.tsx b/src/App.tsx index cf0fd5528eec..35254fa29b2a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -20,6 +20,7 @@ import OnyxProvider from './components/OnyxProvider'; import PopoverContextProvider from './components/PopoverProvider'; import SafeArea from './components/SafeArea'; import ScrollOffsetContextProvider from './components/ScrollOffsetContextProvider'; +import {SearchRouterContextProvider} from './components/Search/SearchRouter/SearchRouterContext'; import ThemeIllustrationsProvider from './components/ThemeIllustrationsProvider'; import ThemeProvider from './components/ThemeProvider'; import ThemeStylesProvider from './components/ThemeStylesProvider'; @@ -94,6 +95,7 @@ function App({url}: AppProps) { VolumeContextProvider, VideoPopoverMenuContextProvider, KeyboardProvider, + SearchRouterContextProvider, ]} > diff --git a/src/CONST.ts b/src/CONST.ts index 86cbd4c28fc9..7ea2af2b1522 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1054,7 +1054,6 @@ const CONST = { BOTTOM_DOCKED: 'bottom_docked', POPOVER: 'popover', RIGHT_DOCKED: 'right_docked', - ONBOARDING: 'onboarding', }, ANCHOR_ORIGIN_VERTICAL: { TOP: 'top', diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 73829989409c..75a4feb66c28 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -10,6 +10,7 @@ import type HeaderWithBackButtonProps from '@components/HeaderWithBackButton/typ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; +import SearchButton from '@components/Search/SearchRouter/SearchButton'; import {usePersonalDetails} from '@components/OnyxProvider'; import type {ReportActionListItemType, ReportListItemType, TransactionListItemType} from '@components/SelectionList/types'; import Text from '@components/Text'; @@ -307,6 +308,7 @@ function SearchPageHeader({queryJSON, hash, onSelectDeleteOption, setOfflineModa icon={headerIcon} subtitleStyles={subtitleStyles} > + {headerButtonsOptions.length > 0 ? ( null} diff --git a/src/components/Search/SearchRouter/SearchButton.tsx b/src/components/Search/SearchRouter/SearchButton.tsx new file mode 100644 index 000000000000..618afb07cc84 --- /dev/null +++ b/src/components/Search/SearchRouter/SearchButton.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import Icon from '@components/Icon'; +import * as Expensicons from '@components/Icon/Expensicons'; +import {PressableWithoutFeedback} from '@components/Pressable'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as SearchUtils from '@libs/SearchUtils'; +import {useSearchRouterContext} from './SearchRouterContext'; + +function SearchButton() { + const styles = useThemeStyles(); + const theme = useTheme(); + const {toggleSearchRouter} = useSearchRouterContext(); + + if (!SearchUtils.shouldDisplayNewSearchRouter()) { + return; + } + + return ( + { + toggleSearchRouter(); + }} + > + + + ); +} + +SearchButton.displayName = 'SearchButton'; + +export default SearchButton; diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx new file mode 100644 index 000000000000..6ec1145cf4c4 --- /dev/null +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -0,0 +1,64 @@ +import React, {useState} from 'react'; +import {View} from 'react-native'; +import Modal from '@components/Modal'; +import type {SearchQueryJSON} from '@components/Search/types'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as SearchUtils from '@libs/SearchUtils'; +import CONST from '@src/CONST'; +import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; +import {useSearchRouterContext} from './SearchRouterContext'; +import SearchRouterInput from './SearchRouterInput'; + +type SearchRouterProps = { + type?: SearchDataTypes; +}; + +function SearchRouter({type}: SearchRouterProps) { + const styles = useThemeStyles(); + const {isSmallScreenWidth} = useResponsiveLayout(); + + const {isSearchRouterDisplayed, toggleSearchRouter} = useSearchRouterContext(); + const [, setCurrentQuery] = useState(undefined); + + const modalType = isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE : CONST.MODAL.MODAL_TYPE.POPOVER; + + const onSearch = (userQuery: string) => { + if (!userQuery) { + setCurrentQuery(undefined); + return; + } + + const query = type ? `type:${type} ${userQuery}` : userQuery; + const queryJSON = SearchUtils.buildSearchQueryJSON(query); + + if (queryJSON) { + // eslint-disable-next-line + console.log('parsedQuery', queryJSON); + + setCurrentQuery(queryJSON); + } else { + // Handle query parsing error + } + }; + + return ( + { + toggleSearchRouter(); + }} + > + + + + + ); +} + +SearchRouter.displayName = 'SearchRouter'; + +export default SearchRouter; diff --git a/src/components/Search/SearchRouter/SearchRouterContext.tsx b/src/components/Search/SearchRouter/SearchRouterContext.tsx new file mode 100644 index 000000000000..02206c0be004 --- /dev/null +++ b/src/components/Search/SearchRouter/SearchRouterContext.tsx @@ -0,0 +1,33 @@ +import React, {useCallback, useContext, useState} from 'react'; +import type ChildrenProps from '@src/types/utils/ChildrenProps'; + +const defaultSearchContext = { + isSearchRouterDisplayed: false, + toggleSearchRouter: () => {}, +}; + +type SearchRouterContext = typeof defaultSearchContext; + +const Context = React.createContext(defaultSearchContext); + +function SearchRouterContextProvider({children}: ChildrenProps) { + const [isSearchRouterDisplayed, setIsSearchRouterDisplayed] = useState(false); + + const toggleSearchRouter = useCallback(() => { + setIsSearchRouterDisplayed(!isSearchRouterDisplayed); + }, [isSearchRouterDisplayed]); + + const routerContext = { + isSearchRouterDisplayed, + toggleSearchRouter, + }; + return {children}; +} + +function useSearchRouterContext() { + return useContext(Context); +} + +SearchRouterContextProvider.displayName = 'SearchRouterContextProvider'; + +export {SearchRouterContextProvider, useSearchRouterContext}; diff --git a/src/components/Search/SearchRouter/SearchRouterInput.tsx b/src/components/Search/SearchRouter/SearchRouterInput.tsx new file mode 100644 index 000000000000..b0b999cb86b3 --- /dev/null +++ b/src/components/Search/SearchRouter/SearchRouterInput.tsx @@ -0,0 +1,50 @@ +import React, {useState} from 'react'; +import {View} from 'react-native'; +import TextInput from '@components/TextInput'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import CONST from '@src/CONST'; + +type SearchRouterInputProps = { + onSearch: (searchTerm: string) => void; +}; + +function SearchRouterInput({onSearch}: SearchRouterInputProps) { + const styles = useThemeStyles(); + const theme = useTheme(); + + const [value, setValue] = useState(''); + + const onChangeText = (text: string) => { + setValue(text); + onSearch(text); + }; + + return ( + + + + ); +} + +SearchRouterInput.displayName = 'SearchRouterInput'; + +export default SearchRouterInput; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index f2461f400678..8f1b27baa888 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -6,6 +6,7 @@ import type {ValueOf} from 'type-fest'; import ComposeProviders from '@components/ComposeProviders'; import OptionsListContextProvider from '@components/OptionListContextProvider'; import {SearchContextProvider} from '@components/Search/SearchContext'; +import SearchRouter from '@components/Search/SearchRouter/SearchRouter'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -558,6 +559,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie ); })} + ); From 1f7c608eade08aa51d4bdca984b9f6b79d5172e3 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Tue, 10 Sep 2024 10:35:52 +0200 Subject: [PATCH 2/7] move search router permission to Permissions.ts --- src/components/Search/SearchRouter/SearchButton.tsx | 4 ++-- src/libs/Permissions.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchButton.tsx b/src/components/Search/SearchRouter/SearchButton.tsx index 618afb07cc84..d7242529cb13 100644 --- a/src/components/Search/SearchRouter/SearchButton.tsx +++ b/src/components/Search/SearchRouter/SearchButton.tsx @@ -4,7 +4,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import {PressableWithoutFeedback} from '@components/Pressable'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as SearchUtils from '@libs/SearchUtils'; +import Permissions from '@libs/Permissions'; import {useSearchRouterContext} from './SearchRouterContext'; function SearchButton() { @@ -12,7 +12,7 @@ function SearchButton() { const theme = useTheme(); const {toggleSearchRouter} = useSearchRouterContext(); - if (!SearchUtils.shouldDisplayNewSearchRouter()) { + if (!Permissions.canUseNewSearchRouter()) { return; } diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 8c47100e465b..7f7e89ad3585 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -2,6 +2,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import type {IOUType} from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; +import * as Environment from './Environment/Environment'; function canUseAllBetas(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.ALL); @@ -49,6 +50,17 @@ function canUseCombinedTrackSubmit(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.COMBINED_TRACK_SUBMIT); } +/** + * New Search Router is under construction and for now should be displayed only in dev to allow developers to work on it. + * We are not using BETA for this feature, as betas are heavier to cleanup, + * and the development of new router is expected to take 2-3 weeks at most + * + * After everything is implemented this function can be removed, as we will always use SearchRouter in the App. + */ +function canUseNewSearchRouter() { + return Environment.isDevelopment(); +} + /** * Link previews are temporarily disabled. */ @@ -68,4 +80,5 @@ export default { canUseNewDotCopilot, canUseWorkspaceRules, canUseCombinedTrackSubmit, + canUseNewSearchRouter, }; From d7a83117bb904e711349bb51368b077716234dc2 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Tue, 10 Sep 2024 11:53:18 +0200 Subject: [PATCH 3/7] Improve SearchRouter and SearchRouterContext --- src/components/Search/SearchPageHeader.tsx | 2 +- .../Search/SearchRouter/SearchButton.tsx | 4 +-- .../Search/SearchRouter/SearchRouter.tsx | 23 +++++++--------- .../SearchRouter/SearchRouterContext.tsx | 22 +++++++++------- .../Search/SearchRouter/SearchRouterInput.tsx | 22 ++++------------ src/styles/index.ts | 26 +++++-------------- 6 files changed, 37 insertions(+), 62 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 75a4feb66c28..70646ea7db1c 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -10,7 +10,6 @@ import type HeaderWithBackButtonProps from '@components/HeaderWithBackButton/typ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; -import SearchButton from '@components/Search/SearchRouter/SearchButton'; import {usePersonalDetails} from '@components/OnyxProvider'; import type {ReportActionListItemType, ReportListItemType, TransactionListItemType} from '@components/SelectionList/types'; import Text from '@components/Text'; @@ -34,6 +33,7 @@ import type {SearchDataTypes, SearchReport} from '@src/types/onyx/SearchResults' import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type IconAsset from '@src/types/utils/IconAsset'; import {useSearchContext} from './SearchContext'; +import SearchButton from './SearchRouter/SearchButton'; import type {SearchQueryJSON} from './types'; type HeaderWrapperProps = Pick & { diff --git a/src/components/Search/SearchRouter/SearchButton.tsx b/src/components/Search/SearchRouter/SearchButton.tsx index d7242529cb13..4948c90ce3d1 100644 --- a/src/components/Search/SearchRouter/SearchButton.tsx +++ b/src/components/Search/SearchRouter/SearchButton.tsx @@ -10,7 +10,7 @@ import {useSearchRouterContext} from './SearchRouterContext'; function SearchButton() { const styles = useThemeStyles(); const theme = useTheme(); - const {toggleSearchRouter} = useSearchRouterContext(); + const {openSearchRouter} = useSearchRouterContext(); if (!Permissions.canUseNewSearchRouter()) { return; @@ -21,7 +21,7 @@ function SearchButton() { accessibilityLabel="" style={[styles.flexRow, styles.mr2, styles.touchableButtonImage]} onPress={() => { - toggleSearchRouter(); + openSearchRouter(); }} > (undefined); const modalType = isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE : CONST.MODAL.MODAL_TYPE.POPOVER; - const onSearch = (userQuery: string) => { + const onSearch = debounce((userQuery: string) => { if (!userQuery) { setCurrentQuery(undefined); return; } - const query = type ? `type:${type} ${userQuery}` : userQuery; - const queryJSON = SearchUtils.buildSearchQueryJSON(query); + const queryJSON = SearchUtils.buildSearchQueryJSON(userQuery); if (queryJSON) { // eslint-disable-next-line @@ -40,7 +37,7 @@ function SearchRouter({type}: SearchRouterProps) { } else { // Handle query parsing error } - }; + }, SEARCH_DEBOUNCE_DELAY); return ( { - toggleSearchRouter(); - }} + onClose={closeSearchRouter} > - + diff --git a/src/components/Search/SearchRouter/SearchRouterContext.tsx b/src/components/Search/SearchRouter/SearchRouterContext.tsx index 02206c0be004..d935fff110a4 100644 --- a/src/components/Search/SearchRouter/SearchRouterContext.tsx +++ b/src/components/Search/SearchRouter/SearchRouterContext.tsx @@ -1,9 +1,10 @@ -import React, {useCallback, useContext, useState} from 'react'; +import React, {useContext, useMemo, useState} from 'react'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; const defaultSearchContext = { isSearchRouterDisplayed: false, - toggleSearchRouter: () => {}, + openSearchRouter: () => {}, + closeSearchRouter: () => {}, }; type SearchRouterContext = typeof defaultSearchContext; @@ -13,14 +14,17 @@ const Context = React.createContext(defaultSearchContext); function SearchRouterContextProvider({children}: ChildrenProps) { const [isSearchRouterDisplayed, setIsSearchRouterDisplayed] = useState(false); - const toggleSearchRouter = useCallback(() => { - setIsSearchRouterDisplayed(!isSearchRouterDisplayed); - }, [isSearchRouterDisplayed]); + const routerContext = useMemo(() => { + const openSearchRouter = () => setIsSearchRouterDisplayed(true); + const closeSearchRouter = () => setIsSearchRouterDisplayed(false); + + return { + isSearchRouterDisplayed, + openSearchRouter, + closeSearchRouter, + }; + }, [isSearchRouterDisplayed, setIsSearchRouterDisplayed]); - const routerContext = { - isSearchRouterDisplayed, - toggleSearchRouter, - }; return {children}; } diff --git a/src/components/Search/SearchRouter/SearchRouterInput.tsx b/src/components/Search/SearchRouter/SearchRouterInput.tsx index b0b999cb86b3..136b45239eb1 100644 --- a/src/components/Search/SearchRouter/SearchRouterInput.tsx +++ b/src/components/Search/SearchRouter/SearchRouterInput.tsx @@ -1,8 +1,8 @@ import React, {useState} from 'react'; import {View} from 'react-native'; -import TextInput from '@components/TextInput'; -import useTheme from '@hooks/useTheme'; +import BaseTextInput from '@components/TextInput/BaseTextInput'; import useThemeStyles from '@hooks/useThemeStyles'; +import variables from '@styles/variables'; import CONST from '@src/CONST'; type SearchRouterInputProps = { @@ -11,7 +11,6 @@ type SearchRouterInputProps = { function SearchRouterInput({onSearch}: SearchRouterInputProps) { const styles = useThemeStyles(); - const theme = useTheme(); const [value, setValue] = useState(''); @@ -22,23 +21,12 @@ function SearchRouterInput({onSearch}: SearchRouterInputProps) { return ( - diff --git a/src/styles/index.ts b/src/styles/index.ts index 9dfd18b641e8..44362ab75ded 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3593,31 +3593,19 @@ const styles = (theme: ThemeColors) => flex: 1, }, - searchPressable: { - height: variables.componentSizeNormal, - }, - - searchContainer: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - gap: 8, - paddingHorizontal: 24, - backgroundColor: theme.hoverComponentBG, - borderRadius: variables.componentBorderRadiusRounded, - justifyContent: 'center', - }, - - searchContainerHovered: { - backgroundColor: theme.border, - }, - searchInputStyle: { color: theme.textSupporting, fontSize: 13, lineHeight: 16, }, + searchRouterInputStyle: { + borderRadius: variables.componentBorderRadiusSmall, + borderWidth: 2, + borderColor: theme.borderFocus, + paddingHorizontal: 8, + }, + searchTableHeaderActive: { fontWeight: FontUtils.fontWeight.bold, }, From 27724319043df45394231b96a5d333910b936c14 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Mon, 16 Sep 2024 15:10:29 +0200 Subject: [PATCH 4/7] Add searching on ENTER key press --- src/components/Search/SearchPageHeader.tsx | 1 - .../Search/SearchRouter/SearchRouter.tsx | 49 ++++++++++++++++--- .../Search/SearchRouter/SearchRouterInput.tsx | 24 ++++----- .../createCustomBottomTabNavigator/TopBar.tsx | 3 ++ 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 70646ea7db1c..40bf7fe4dfa3 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -308,7 +308,6 @@ function SearchPageHeader({queryJSON, hash, onSelectDeleteOption, setOfflineModa icon={headerIcon} subtitleStyles={subtitleStyles} > - {headerButtonsOptions.length > 0 ? ( null} diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index b774f4d91184..49a8e494f9d2 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -1,29 +1,54 @@ import debounce from 'lodash/debounce'; import React, {useState} from 'react'; import {View} from 'react-native'; +import FocusTrapForModal from '@components/FocusTrap/FocusTrapForModal'; import Modal from '@components/Modal'; import type {SearchQueryJSON} from '@components/Search/types'; +import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import * as SearchUtils from '@libs/SearchUtils'; +import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; import {useSearchRouterContext} from './SearchRouterContext'; import SearchRouterInput from './SearchRouterInput'; -const SEARCH_DEBOUNCE_DELAY = 250; +const SEARCH_DEBOUNCE_DELAY = 200; function SearchRouter() { const styles = useThemeStyles(); - const {isSmallScreenWidth} = useResponsiveLayout(); + const {isSmallScreenWidth} = useResponsiveLayout(); const {isSearchRouterDisplayed, closeSearchRouter} = useSearchRouterContext(); - const [, setCurrentQuery] = useState(undefined); + const [currentQuery, setCurrentQuery] = useState(undefined); - const modalType = isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE : CONST.MODAL.MODAL_TYPE.POPOVER; + const clearUserQuery = () => { + setCurrentQuery(undefined); + }; + + useKeyboardShortcut( + CONST.KEYBOARD_SHORTCUTS.ENTER, + () => { + if (!currentQuery) { + return; + } + + const query = SearchUtils.buildSearchQueryString(currentQuery); + Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); + + closeSearchRouter(); + clearUserQuery(); + }, + { + captureOnInputs: true, + shouldBubble: false, + }, + ); const onSearch = debounce((userQuery: string) => { if (!userQuery) { - setCurrentQuery(undefined); + clearUserQuery(); return; } @@ -39,6 +64,9 @@ function SearchRouter() { } }, SEARCH_DEBOUNCE_DELAY); + const modalType = isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE : CONST.MODAL.MODAL_TYPE.POPOVER; + const isFullWidth = isSmallScreenWidth; + return ( - - - + + + + + ); } diff --git a/src/components/Search/SearchRouter/SearchRouterInput.tsx b/src/components/Search/SearchRouter/SearchRouterInput.tsx index 136b45239eb1..903a1120b3aa 100644 --- a/src/components/Search/SearchRouter/SearchRouterInput.tsx +++ b/src/components/Search/SearchRouter/SearchRouterInput.tsx @@ -1,15 +1,15 @@ import React, {useState} from 'react'; -import {View} from 'react-native'; import BaseTextInput from '@components/TextInput/BaseTextInput'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import CONST from '@src/CONST'; type SearchRouterInputProps = { + isFullWidth: boolean; onSearch: (searchTerm: string) => void; }; -function SearchRouterInput({onSearch}: SearchRouterInputProps) { +function SearchRouterInput({isFullWidth, onSearch}: SearchRouterInputProps) { const styles = useThemeStyles(); const [value, setValue] = useState(''); @@ -19,17 +19,17 @@ function SearchRouterInput({onSearch}: SearchRouterInputProps) { onSearch(text); }; + const modalWidth = isFullWidth ? styles.w100 : {width: variables.popoverWidth}; + return ( - - - + ); } diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index f4728a80f2ca..985c16d50c22 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -5,6 +5,7 @@ import Breadcrumbs from '@components/Breadcrumbs'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import {PressableWithoutFeedback} from '@components/Pressable'; +import SearchButton from '@components/Search/SearchRouter/SearchButton'; import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import WorkspaceSwitcherButton from '@components/WorkspaceSwitcherButton'; @@ -73,6 +74,8 @@ function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true, {translate('common.cancel')} )} + {/* This is only temporary for development and will be cleaned up in: https://github.com/Expensify/App/issues/49122 */} + {displaySearch && ( Date: Mon, 16 Sep 2024 15:17:01 +0200 Subject: [PATCH 5/7] fix lint --- src/components/Search/SearchPageHeader.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 40bf7fe4dfa3..73829989409c 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -33,7 +33,6 @@ import type {SearchDataTypes, SearchReport} from '@src/types/onyx/SearchResults' import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type IconAsset from '@src/types/utils/IconAsset'; import {useSearchContext} from './SearchContext'; -import SearchButton from './SearchRouter/SearchButton'; import type {SearchQueryJSON} from './types'; type HeaderWrapperProps = Pick & { From 3e26bf1d7850fe6f27399abbaabc2be53318ccd8 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Mon, 16 Sep 2024 17:12:05 +0200 Subject: [PATCH 6/7] Improve keyboard handling in SearchRouter --- .../Search/SearchRouter/SearchRouter.tsx | 56 +++++++++++-------- .../Search/SearchRouter/SearchRouterInput.tsx | 9 ++- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 49a8e494f9d2..73a86f95719e 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -1,5 +1,5 @@ import debounce from 'lodash/debounce'; -import React, {useState} from 'react'; +import React, {useCallback, useState} from 'react'; import {View} from 'react-native'; import FocusTrapForModal from '@components/FocusTrap/FocusTrapForModal'; import Modal from '@components/Modal'; @@ -27,26 +27,7 @@ function SearchRouter() { setCurrentQuery(undefined); }; - useKeyboardShortcut( - CONST.KEYBOARD_SHORTCUTS.ENTER, - () => { - if (!currentQuery) { - return; - } - - const query = SearchUtils.buildSearchQueryString(currentQuery); - Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); - - closeSearchRouter(); - clearUserQuery(); - }, - { - captureOnInputs: true, - shouldBubble: false, - }, - ); - - const onSearch = debounce((userQuery: string) => { + const onSearchChange = debounce((userQuery: string) => { if (!userQuery) { clearUserQuery(); return; @@ -64,7 +45,35 @@ function SearchRouter() { } }, SEARCH_DEBOUNCE_DELAY); - const modalType = isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE : CONST.MODAL.MODAL_TYPE.POPOVER; + const onSearchSubmit = useCallback(() => { + const query = SearchUtils.buildSearchQueryString(currentQuery); + Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); + + closeSearchRouter(); + clearUserQuery(); + }, [currentQuery, closeSearchRouter]); + + useKeyboardShortcut( + CONST.KEYBOARD_SHORTCUTS.ENTER, + () => { + if (!currentQuery) { + return; + } + + onSearchSubmit(); + }, + { + captureOnInputs: true, + shouldBubble: false, + }, + ); + + useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ESCAPE, () => { + closeSearchRouter(); + clearUserQuery(); + }); + + const modalType = isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.CENTERED : CONST.MODAL.MODAL_TYPE.POPOVER; const isFullWidth = isSmallScreenWidth; return ( @@ -79,7 +88,8 @@ function SearchRouter() { diff --git a/src/components/Search/SearchRouter/SearchRouterInput.tsx b/src/components/Search/SearchRouter/SearchRouterInput.tsx index 903a1120b3aa..860a46239d21 100644 --- a/src/components/Search/SearchRouter/SearchRouterInput.tsx +++ b/src/components/Search/SearchRouter/SearchRouterInput.tsx @@ -6,17 +6,18 @@ import CONST from '@src/CONST'; type SearchRouterInputProps = { isFullWidth: boolean; - onSearch: (searchTerm: string) => void; + onChange: (searchTerm: string) => void; + onSubmit: () => void; }; -function SearchRouterInput({isFullWidth, onSearch}: SearchRouterInputProps) { +function SearchRouterInput({isFullWidth, onChange, onSubmit}: SearchRouterInputProps) { const styles = useThemeStyles(); const [value, setValue] = useState(''); const onChangeText = (text: string) => { setValue(text); - onSearch(text); + onChange(text); }; const modalWidth = isFullWidth ? styles.w100 : {width: variables.popoverWidth}; @@ -25,10 +26,12 @@ function SearchRouterInput({isFullWidth, onSearch}: SearchRouterInputProps) { ); } From d89f4d2e0f2d1c486e962a16740c5186306e19b5 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Tue, 17 Sep 2024 12:28:49 +0200 Subject: [PATCH 7/7] Improve redirecting from SearchRouter --- src/components/Search/SearchRouter/SearchRouter.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 73a86f95719e..b38c55279c1e 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -46,10 +46,10 @@ function SearchRouter() { }, SEARCH_DEBOUNCE_DELAY); const onSearchSubmit = useCallback(() => { + closeSearchRouter(); + const query = SearchUtils.buildSearchQueryString(currentQuery); Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); - - closeSearchRouter(); clearUserQuery(); }, [currentQuery, closeSearchRouter]);