From 8ffcb6b472082f123a12cf0d5cecf45cc6566868 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Mon, 3 Jun 2024 20:26:36 +0100 Subject: [PATCH 01/15] Reapply "Merge pull request #35045 from callstack-internal/issues/30123" This reverts commit ad202800542b480ab212b5acabe88b73c2834a7f. --- src/CONST.ts | 1 + src/components/AddressSearch/index.tsx | 61 ++++++++++++---- .../listViewOverflow/index.native.ts | 4 + .../AddressSearch/listViewOverflow/index.ts | 4 + src/components/AddressSearch/types.ts | 11 ++- src/components/Form/FormProvider.tsx | 3 + src/components/Form/FormWrapper.tsx | 14 ++-- src/hooks/useSubmitButtonVisibility.native.ts | 33 +++++++++ src/hooks/useSubmitButtonVisibility.ts | 58 +++++++++++++++ src/libs/actions/Transaction.ts | 2 +- .../request/step/IOURequestStepWaypoint.tsx | 73 ++++++++++--------- src/styles/index.ts | 1 - src/styles/utils/sizing.ts | 3 + 13 files changed, 212 insertions(+), 56 deletions(-) create mode 100644 src/components/AddressSearch/listViewOverflow/index.native.ts create mode 100644 src/components/AddressSearch/listViewOverflow/index.ts create mode 100644 src/hooks/useSubmitButtonVisibility.native.ts create mode 100644 src/hooks/useSubmitButtonVisibility.ts diff --git a/src/CONST.ts b/src/CONST.ts index bdf5463031f7..26d481564870 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -73,6 +73,7 @@ const onboardingChoices = { type OnboardingPurposeType = ValueOf; const CONST = { + RECENT_WAYPOINTS_NUMBER: 20, DEFAULT_POLICY_ROOM_CHAT_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL], // Note: Group and Self-DM excluded as these are not tied to a Workspace diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index 17a2f6212447..d1dc42bb4678 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -23,7 +23,25 @@ import CONST from '@src/CONST'; import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import CurrentLocationButton from './CurrentLocationButton'; import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer'; -import type {AddressSearchProps} from './types'; +import listViewOverflow from './listViewOverflow'; +import type {AddressSearchProps, PredefinedPlace} from './types'; + +/** + * Check if the place matches the search by the place name or description. + * @param search The search string for a place + * @param place The place to check for a match on the search + * @returns true if search is related to place, otherwise it returns false. + */ +function isPlaceMatchForSearch(search: string, place: PredefinedPlace): boolean { + if (!search) { + return true; + } + if (!place) { + return false; + } + const fullSearchSentence = `${place.name ?? ''} ${place.description}`; + return search.split(' ').every((searchTerm) => !searchTerm || (searchTerm && fullSearchSentence.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase()))); +} // The error that's being thrown below will be ignored until we fork the // react-native-google-places-autocomplete repo and replace the @@ -41,6 +59,7 @@ function AddressSearch( isLimitedToUSA = false, label, maxInputLength, + onFocus, onBlur, onInputChange, onPress, @@ -298,10 +317,16 @@ function AddressSearch( }; }, []); + const filteredPredefinedPlaces = useMemo(() => { + if (!isOffline || !searchValue) { + return predefinedPlaces ?? []; + } + return predefinedPlaces?.filter((predefinedPlace) => isPlaceMatchForSearch(searchValue, predefinedPlace)) ?? []; + }, [isOffline, predefinedPlaces, searchValue]); + const listEmptyComponent = useCallback( - () => - !!isOffline || !isTyping ? null : {translate('common.noResultsFound')}, - [isOffline, isTyping, styles, translate], + () => (!isTyping ? null : {translate('common.noResultsFound')}), + [isTyping, styles, translate], ); const listLoader = useCallback( @@ -338,11 +363,10 @@ function AddressSearch( ref={containerRef} > - {!!title && {title}} + {!!title && {title}} {subtitle} ); @@ -385,6 +409,7 @@ function AddressSearch( shouldSaveDraft, onFocus: () => { setIsFocused(true); + onFocus?.(); }, onBlur: (event) => { if (!isCurrentTargetInsideContainer(event, containerRef)) { @@ -414,10 +439,18 @@ function AddressSearch( }} styles={{ textInputContainer: [styles.flexColumn], - listView: [StyleUtils.getGoogleListViewStyle(displayListViewBorder), styles.overflowAuto, styles.borderLeft, styles.borderRight, !isFocused && {height: 0}], + listView: [ + StyleUtils.getGoogleListViewStyle(displayListViewBorder), + listViewOverflow, + styles.borderLeft, + styles.borderRight, + styles.flexGrow0, + !isFocused && styles.h0, + ], row: [styles.pv4, styles.ph3, styles.overflowAuto], description: [styles.googleSearchText], separator: [styles.googleSearchSeparator], + container: [styles.mh100], }} numberOfLines={2} isRowScrollable={false} @@ -441,11 +474,13 @@ function AddressSearch( ) } placeholder="" - /> - setLocationErrorCode(null)} - locationErrorCode={locationErrorCode} - /> + listViewDisplayed + > + setLocationErrorCode(null)} + locationErrorCode={locationErrorCode} + /> + {isFetchingCurrentLocation && } diff --git a/src/components/AddressSearch/listViewOverflow/index.native.ts b/src/components/AddressSearch/listViewOverflow/index.native.ts new file mode 100644 index 000000000000..36b9f4005376 --- /dev/null +++ b/src/components/AddressSearch/listViewOverflow/index.native.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line no-restricted-imports +import {defaultStyles} from '@styles/index'; + +export default defaultStyles.overflowHidden; diff --git a/src/components/AddressSearch/listViewOverflow/index.ts b/src/components/AddressSearch/listViewOverflow/index.ts new file mode 100644 index 000000000000..ae8bf35cc80c --- /dev/null +++ b/src/components/AddressSearch/listViewOverflow/index.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line no-restricted-imports +import {defaultStyles} from '@styles/index'; + +export default defaultStyles.overflowAuto; diff --git a/src/components/AddressSearch/types.ts b/src/components/AddressSearch/types.ts index bc7acf3f7e40..22cc3834b7a9 100644 --- a/src/components/AddressSearch/types.ts +++ b/src/components/AddressSearch/types.ts @@ -24,6 +24,10 @@ type StreetValue = { street: string; }; +type PredefinedPlace = Place & { + name?: string; +}; + type AddressSearchProps = { /** The ID used to uniquely identify the input in a Form */ inputID?: string; @@ -31,6 +35,9 @@ type AddressSearchProps = { /** Saves a draft of the input value when used in a form */ shouldSaveDraft?: boolean; + /** Callback that is called when the text input is focused */ + onFocus?: () => void; + /** Callback that is called when the text input is blurred */ onBlur?: () => void; @@ -65,7 +72,7 @@ type AddressSearchProps = { canUseCurrentLocation?: boolean; /** A list of predefined places that can be shown when the user isn't searching for something */ - predefinedPlaces?: Place[] | null; + predefinedPlaces?: PredefinedPlace[] | null; /** A map of inputID key names */ renamedInputKeys?: Address; @@ -85,4 +92,4 @@ type AddressSearchProps = { type IsCurrentTargetInsideContainerType = (event: FocusEvent | NativeSyntheticEvent, containerRef: RefObject) => boolean; -export type {CurrentLocationButtonProps, AddressSearchProps, IsCurrentTargetInsideContainerType, StreetValue}; +export type {CurrentLocationButtonProps, AddressSearchProps, IsCurrentTargetInsideContainerType, StreetValue, PredefinedPlace}; diff --git a/src/components/Form/FormProvider.tsx b/src/components/Form/FormProvider.tsx index 3d20f910dca0..b6699c0cf3f4 100644 --- a/src/components/Form/FormProvider.tsx +++ b/src/components/Form/FormProvider.tsx @@ -74,6 +74,9 @@ type FormProviderProps = FormProvider /** Whether to apply flex to the submit button */ submitFlexEnabled?: boolean; + + /** Whether the form container should grow or adapt to the viewable available space */ + shouldContainerGrow?: boolean; }; function FormProvider( diff --git a/src/components/Form/FormWrapper.tsx b/src/components/Form/FormWrapper.tsx index 5c74fd466a15..e7c9dba5c77a 100644 --- a/src/components/Form/FormWrapper.tsx +++ b/src/components/Form/FormWrapper.tsx @@ -1,8 +1,8 @@ import React, {useCallback, useMemo, useRef} from 'react'; import type {RefObject} from 'react'; // eslint-disable-next-line no-restricted-imports -import type {ScrollView as RNScrollView, StyleProp, View, ViewStyle} from 'react-native'; -import {Keyboard} from 'react-native'; +import type {ScrollView as RNScrollView, StyleProp, ViewStyle} from 'react-native'; +import {Keyboard, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; @@ -32,6 +32,9 @@ type FormWrapperProps = ChildrenProps & /** Whether to apply flex to the submit button */ submitFlexEnabled?: boolean; + /** Whether the form container should grow or adapt to the viewable available space */ + shouldContainerGrow?: boolean; + /** Server side errors keyed by microtime */ errors: FormInputErrors; @@ -60,6 +63,7 @@ function FormWrapper({ scrollContextEnabled = false, shouldHideFixErrorsAlert = false, disablePressOnEnter = true, + shouldContainerGrow = true, }: FormWrapperProps) { const styles = useThemeStyles(); const formRef = useRef(null); @@ -104,7 +108,7 @@ function FormWrapper({ ref={formContentRef} style={[style, safeAreaPaddingBottomStyle.paddingBottom ? safeAreaPaddingBottomStyle : styles.pb5]} > - {children} + {children} {isSubmitButtonVisible && ( @@ -164,7 +168,7 @@ function FormWrapper({ ) : ( diff --git a/src/hooks/useSubmitButtonVisibility.native.ts b/src/hooks/useSubmitButtonVisibility.native.ts new file mode 100644 index 000000000000..a962b52ce1f0 --- /dev/null +++ b/src/hooks/useSubmitButtonVisibility.native.ts @@ -0,0 +1,33 @@ +import {useState} from 'react'; +import useSafeAreaInsets from './useSafeAreaInsets'; +import useThemeStyles from './useThemeStyles'; + +// Useful when there's a need to hide the submit button from FormProvider, +// to let form content fill the page when virtual keyboard is shown +function useSubmitButtonVisibility() { + const styles = useThemeStyles(); + const [isSubmitButtonVisible, setIsSubmitButtonVisible] = useState(true); + const {bottom} = useSafeAreaInsets(); + + const showSubmitButton = () => { + setIsSubmitButtonVisible(true); + }; + + const hideSubmitButton = () => { + setIsSubmitButtonVisible(false); + }; + + // When the submit button is hidden there's a need to manually + // add its bottom style to the FormProvider style prop, + // otherwise the form content will touch the bottom of the page/screen + const formStyle = !isSubmitButtonVisible && bottom === 0 && styles.mb5; + + return { + isSubmitButtonVisible, + showSubmitButton, + hideSubmitButton, + formStyle, + }; +} + +export default useSubmitButtonVisibility; diff --git a/src/hooks/useSubmitButtonVisibility.ts b/src/hooks/useSubmitButtonVisibility.ts new file mode 100644 index 000000000000..72f704edbe13 --- /dev/null +++ b/src/hooks/useSubmitButtonVisibility.ts @@ -0,0 +1,58 @@ +import {useEffect, useRef, useState} from 'react'; +import {Dimensions} from 'react-native'; +import useSafeAreaInsets from './useSafeAreaInsets'; +import useThemeStyles from './useThemeStyles'; +import useWindowDimensions from './useWindowDimensions'; + +// Useful when there's a need to hide the submit button from FormProvider, +// to let form content fill the page when virtual keyboard is shown +function useSubmitButtonVisibility() { + const styles = useThemeStyles(); + const {windowHeight, isSmallScreenWidth} = useWindowDimensions(); + const [isSubmitButtonVisible, setIsSubmitButtonVisible] = useState(true); + const initialWindowHeightRef = useRef(windowHeight); + const isSmallScreenWidthRef = useRef(isSmallScreenWidth); + const {bottom} = useSafeAreaInsets(); + + // Web: the submit button is shown when the height of the window is the same or greater, + // otherwise it's hidden + useEffect(() => { + const dimensionsListener = Dimensions.addEventListener('change', ({window}) => { + if (!isSmallScreenWidthRef.current) { + return; + } + + if (window.height < initialWindowHeightRef.current) { + setIsSubmitButtonVisible(false); + return; + } + + setIsSubmitButtonVisible(true); + }); + + return () => dimensionsListener.remove(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + // Web: the submit button is only shown when the window height is the same or greater, + // so executing this function won't do anything + const showSubmitButton = () => {}; + + // Web: the submit button is only hidden when the window height becomes smaller, + // so executing this function won't do anything + const hideSubmitButton = () => {}; + + // When the submit button is hidden there's a need to manually + // add its bottom style to the FormProvider style prop, + // otherwise the form content will touch the bottom of the page/screen + const formStyle = !isSubmitButtonVisible && bottom === 0 && styles.mb5; + + return { + isSubmitButtonVisible, + showSubmitButton, + hideSubmitButton, + formStyle, + }; +} + +export default useSubmitButtonVisibility; diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts index 251c8d046562..ee306fd44fc8 100644 --- a/src/libs/actions/Transaction.ts +++ b/src/libs/actions/Transaction.ts @@ -113,7 +113,7 @@ function saveWaypoint(transactionID: string, index: string, waypoint: RecentWayp if (!recentWaypointAlreadyExists && waypoint !== null) { const clonedWaypoints = lodashClone(recentWaypoints); clonedWaypoints.unshift(waypoint); - Onyx.merge(ONYXKEYS.NVP_RECENT_WAYPOINTS, clonedWaypoints.slice(0, 5)); + Onyx.merge(ONYXKEYS.NVP_RECENT_WAYPOINTS, clonedWaypoints.slice(0, CONST.RECENT_WAYPOINTS_NUMBER)); } } diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index 6c0eae98fb85..374e27819e70 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -1,7 +1,6 @@ import {useNavigation} from '@react-navigation/native'; import React, {useMemo, useRef, useState} from 'react'; import type {TextInput} from 'react-native'; -import {View} from 'react-native'; import type {Place} from 'react-native-google-places-autocomplete'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -17,6 +16,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useLocationBias from '@hooks/useLocationBias'; import useNetwork from '@hooks/useNetwork'; +import useSubmitButtonVisibility from '@hooks/useSubmitButtonVisibility'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -57,6 +57,7 @@ function IOURequestStepWaypoint({ }: IOURequestStepWaypointProps) { const styles = useThemeStyles(); const {windowWidth} = useWindowDimensions(); + const {isSubmitButtonVisible, showSubmitButton, hideSubmitButton, formStyle} = useSubmitButtonVisibility(); const [isDeleteStopModalOpen, setIsDeleteStopModalOpen] = useState(false); const navigation = useNavigation(); const isFocused = navigation.isFocused(); @@ -157,6 +158,7 @@ function IOURequestStepWaypoint({ onEntryTransitionEnd={() => textInput.current?.focus()} shouldEnableMaxHeight testID={IOURequestStepWaypoint.displayName} + style={styles.overflowHidden} > - - { - textInput.current = e as unknown as TextInput; - }} - hint={!isOffline ? 'distance.error.selectSuggestedAddress' : ''} - containerStyles={[styles.mt4]} - label={translate('distance.address')} - defaultValue={waypointAddress} - onPress={selectWaypoint} - maxInputLength={CONST.FORM_CHARACTER_LIMIT} - renamedInputKeys={{ - address: `waypoint${pageIndex}`, - city: '', - country: '', - street: '', - street2: '', - zipCode: '', - lat: '', - lng: '', - state: '', - }} - predefinedPlaces={recentWaypoints} - resultTypes="" - /> - + { + textInput.current = e as unknown as TextInput; + }} + hint={!isOffline ? 'distance.error.selectSuggestedAddress' : ''} + containerStyles={[styles.mt4]} + label={translate('distance.address')} + defaultValue={waypointAddress} + onPress={selectWaypoint} + onFocus={hideSubmitButton} + onBlur={showSubmitButton} + maxInputLength={CONST.FORM_CHARACTER_LIMIT} + renamedInputKeys={{ + address: `waypoint${pageIndex}`, + city: '', + country: '', + street: '', + street2: '', + zipCode: '', + lat: '', + lng: '', + state: '', + }} + predefinedPlaces={recentWaypoints} + resultTypes="" + /> @@ -244,10 +249,10 @@ export default withWritableReportOrNotFound( recentWaypoints: { key: ONYXKEYS.NVP_RECENT_WAYPOINTS, - // Only grab the most recent 5 waypoints because that's all that is shown in the UI. This also puts them into the format of data + // Only grab the most recent 20 waypoints because that's all that is shown in the UI. This also puts them into the format of data // that the google autocomplete component expects for it's "predefined places" feature. selector: (waypoints) => - (waypoints ? waypoints.slice(0, 5) : []).map((waypoint) => ({ + (waypoints ? waypoints.slice(0, CONST.RECENT_WAYPOINTS_NUMBER) : []).map((waypoint) => ({ name: waypoint.name, description: waypoint.address ?? '', geometry: { diff --git a/src/styles/index.ts b/src/styles/index.ts index 9980a96f64ae..51820ff827f4 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3481,7 +3481,6 @@ const styles = (theme: ThemeColors) => fontSize: variables.fontSizeNormal, lineHeight: variables.fontSizeNormalHeight, fontFamily: FontUtils.fontFamily.platform.EXP_NEUE, - flex: 1, }, searchPressable: { diff --git a/src/styles/utils/sizing.ts b/src/styles/utils/sizing.ts index bde2837f16ba..ba232ef99b81 100644 --- a/src/styles/utils/sizing.ts +++ b/src/styles/utils/sizing.ts @@ -6,6 +6,9 @@ import type {ViewStyle} from 'react-native'; * https://getbootstrap.com/docs/5.0/utilities/sizing/ */ export default { + h0: { + height: 0, + }, h100: { height: '100%', }, From e81675ecae5bc1df5dfb9f2cf59b64b988cc5f7f Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Mon, 3 Jun 2024 21:10:38 +0100 Subject: [PATCH 02/15] fix: unreachable form inputs --- src/components/Form/FormWrapper.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Form/FormWrapper.tsx b/src/components/Form/FormWrapper.tsx index e7c9dba5c77a..500f7d985599 100644 --- a/src/components/Form/FormWrapper.tsx +++ b/src/components/Form/FormWrapper.tsx @@ -108,7 +108,7 @@ function FormWrapper({ ref={formContentRef} style={[style, safeAreaPaddingBottomStyle.paddingBottom ? safeAreaPaddingBottomStyle : styles.pb5]} > - {children} + {shouldContainerGrow ? children : {children}} {isSubmitButtonVisible && ( Date: Mon, 3 Jun 2024 21:11:30 +0100 Subject: [PATCH 03/15] chore: disable typescript rule for constant --- src/pages/iou/request/step/IOURequestStepWaypoint.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index 374e27819e70..2c2c27d2c497 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -252,6 +252,7 @@ export default withWritableReportOrNotFound( // Only grab the most recent 20 waypoints because that's all that is shown in the UI. This also puts them into the format of data // that the google autocomplete component expects for it's "predefined places" feature. selector: (waypoints) => + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument (waypoints ? waypoints.slice(0, CONST.RECENT_WAYPOINTS_NUMBER) : []).map((waypoint) => ({ name: waypoint.name, description: waypoint.address ?? '', From 838218d992a2d43547bd85de40bdf6b6c57ed30f Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Tue, 11 Jun 2024 19:46:03 +0100 Subject: [PATCH 04/15] fix: hiding submit button on address search screen --- src/components/AddressSearch/index.tsx | 1 + src/components/Form/FormProvider.tsx | 3 - src/components/Form/FormWrapper.tsx | 17 ++--- src/hooks/useSubmitButtonVisibility.native.ts | 33 --------- src/hooks/useSubmitButtonVisibility.ts | 58 --------------- .../request/step/IOURequestStepWaypoint.tsx | 71 +++++++++---------- src/styles/index.ts | 1 + 7 files changed, 41 insertions(+), 143 deletions(-) delete mode 100644 src/hooks/useSubmitButtonVisibility.native.ts delete mode 100644 src/hooks/useSubmitButtonVisibility.ts diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index d1dc42bb4678..e3723b85e3d9 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -475,6 +475,7 @@ function AddressSearch( } placeholder="" listViewDisplayed + disableScroll > setLocationErrorCode(null)} diff --git a/src/components/Form/FormProvider.tsx b/src/components/Form/FormProvider.tsx index b6699c0cf3f4..3d20f910dca0 100644 --- a/src/components/Form/FormProvider.tsx +++ b/src/components/Form/FormProvider.tsx @@ -74,9 +74,6 @@ type FormProviderProps = FormProvider /** Whether to apply flex to the submit button */ submitFlexEnabled?: boolean; - - /** Whether the form container should grow or adapt to the viewable available space */ - shouldContainerGrow?: boolean; }; function FormProvider( diff --git a/src/components/Form/FormWrapper.tsx b/src/components/Form/FormWrapper.tsx index 500f7d985599..5c74fd466a15 100644 --- a/src/components/Form/FormWrapper.tsx +++ b/src/components/Form/FormWrapper.tsx @@ -1,8 +1,8 @@ import React, {useCallback, useMemo, useRef} from 'react'; import type {RefObject} from 'react'; // eslint-disable-next-line no-restricted-imports -import type {ScrollView as RNScrollView, StyleProp, ViewStyle} from 'react-native'; -import {Keyboard, View} from 'react-native'; +import type {ScrollView as RNScrollView, StyleProp, View, ViewStyle} from 'react-native'; +import {Keyboard} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; @@ -32,9 +32,6 @@ type FormWrapperProps = ChildrenProps & /** Whether to apply flex to the submit button */ submitFlexEnabled?: boolean; - /** Whether the form container should grow or adapt to the viewable available space */ - shouldContainerGrow?: boolean; - /** Server side errors keyed by microtime */ errors: FormInputErrors; @@ -63,7 +60,6 @@ function FormWrapper({ scrollContextEnabled = false, shouldHideFixErrorsAlert = false, disablePressOnEnter = true, - shouldContainerGrow = true, }: FormWrapperProps) { const styles = useThemeStyles(); const formRef = useRef(null); @@ -108,7 +104,7 @@ function FormWrapper({ ref={formContentRef} style={[style, safeAreaPaddingBottomStyle.paddingBottom ? safeAreaPaddingBottomStyle : styles.pb5]} > - {shouldContainerGrow ? children : {children}} + {children} {isSubmitButtonVisible && ( @@ -169,7 +164,7 @@ function FormWrapper({ ) : ( diff --git a/src/hooks/useSubmitButtonVisibility.native.ts b/src/hooks/useSubmitButtonVisibility.native.ts deleted file mode 100644 index a962b52ce1f0..000000000000 --- a/src/hooks/useSubmitButtonVisibility.native.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {useState} from 'react'; -import useSafeAreaInsets from './useSafeAreaInsets'; -import useThemeStyles from './useThemeStyles'; - -// Useful when there's a need to hide the submit button from FormProvider, -// to let form content fill the page when virtual keyboard is shown -function useSubmitButtonVisibility() { - const styles = useThemeStyles(); - const [isSubmitButtonVisible, setIsSubmitButtonVisible] = useState(true); - const {bottom} = useSafeAreaInsets(); - - const showSubmitButton = () => { - setIsSubmitButtonVisible(true); - }; - - const hideSubmitButton = () => { - setIsSubmitButtonVisible(false); - }; - - // When the submit button is hidden there's a need to manually - // add its bottom style to the FormProvider style prop, - // otherwise the form content will touch the bottom of the page/screen - const formStyle = !isSubmitButtonVisible && bottom === 0 && styles.mb5; - - return { - isSubmitButtonVisible, - showSubmitButton, - hideSubmitButton, - formStyle, - }; -} - -export default useSubmitButtonVisibility; diff --git a/src/hooks/useSubmitButtonVisibility.ts b/src/hooks/useSubmitButtonVisibility.ts deleted file mode 100644 index 72f704edbe13..000000000000 --- a/src/hooks/useSubmitButtonVisibility.ts +++ /dev/null @@ -1,58 +0,0 @@ -import {useEffect, useRef, useState} from 'react'; -import {Dimensions} from 'react-native'; -import useSafeAreaInsets from './useSafeAreaInsets'; -import useThemeStyles from './useThemeStyles'; -import useWindowDimensions from './useWindowDimensions'; - -// Useful when there's a need to hide the submit button from FormProvider, -// to let form content fill the page when virtual keyboard is shown -function useSubmitButtonVisibility() { - const styles = useThemeStyles(); - const {windowHeight, isSmallScreenWidth} = useWindowDimensions(); - const [isSubmitButtonVisible, setIsSubmitButtonVisible] = useState(true); - const initialWindowHeightRef = useRef(windowHeight); - const isSmallScreenWidthRef = useRef(isSmallScreenWidth); - const {bottom} = useSafeAreaInsets(); - - // Web: the submit button is shown when the height of the window is the same or greater, - // otherwise it's hidden - useEffect(() => { - const dimensionsListener = Dimensions.addEventListener('change', ({window}) => { - if (!isSmallScreenWidthRef.current) { - return; - } - - if (window.height < initialWindowHeightRef.current) { - setIsSubmitButtonVisible(false); - return; - } - - setIsSubmitButtonVisible(true); - }); - - return () => dimensionsListener.remove(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // Web: the submit button is only shown when the window height is the same or greater, - // so executing this function won't do anything - const showSubmitButton = () => {}; - - // Web: the submit button is only hidden when the window height becomes smaller, - // so executing this function won't do anything - const hideSubmitButton = () => {}; - - // When the submit button is hidden there's a need to manually - // add its bottom style to the FormProvider style prop, - // otherwise the form content will touch the bottom of the page/screen - const formStyle = !isSubmitButtonVisible && bottom === 0 && styles.mb5; - - return { - isSubmitButtonVisible, - showSubmitButton, - hideSubmitButton, - formStyle, - }; -} - -export default useSubmitButtonVisibility; diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index d5684c373a87..a5c7df4254d9 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -1,6 +1,7 @@ import {useNavigation} from '@react-navigation/native'; import React, {useMemo, useRef, useState} from 'react'; import type {TextInput} from 'react-native'; +import {View} from 'react-native'; import type {Place} from 'react-native-google-places-autocomplete'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -17,7 +18,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useLocationBias from '@hooks/useLocationBias'; import useNetwork from '@hooks/useNetwork'; -import useSubmitButtonVisibility from '@hooks/useSubmitButtonVisibility'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ErrorUtils from '@libs/ErrorUtils'; @@ -58,7 +58,6 @@ function IOURequestStepWaypoint({ }: IOURequestStepWaypointProps) { const styles = useThemeStyles(); const {windowWidth} = useWindowDimensions(); - const {isSubmitButtonVisible, showSubmitButton, hideSubmitButton, formStyle} = useSubmitButtonVisibility(); const [isDeleteStopModalOpen, setIsDeleteStopModalOpen] = useState(false); const [restoreFocusType, setRestoreFocusType] = useState(); const navigation = useNavigation(); @@ -198,48 +197,45 @@ function IOURequestStepWaypoint({ restoreFocusType={restoreFocusType} /> - { - textInput.current = e as unknown as TextInput; - }} - hint={!isOffline ? 'distance.error.selectSuggestedAddress' : ''} - containerStyles={[styles.mt4]} - label={translate('distance.address')} - defaultValue={waypointAddress} - onPress={selectWaypoint} - onFocus={hideSubmitButton} - onBlur={showSubmitButton} - maxInputLength={CONST.FORM_CHARACTER_LIMIT} - renamedInputKeys={{ - address: `waypoint${pageIndex}`, - city: '', - country: '', - street: '', - street2: '', - zipCode: '', - lat: '', - lng: '', - state: '', - }} - predefinedPlaces={recentWaypoints} - resultTypes="" - /> + + { + textInput.current = e as unknown as TextInput; + }} + hint={!isOffline ? 'distance.error.selectSuggestedAddress' : ''} + containerStyles={[styles.mt4]} + label={translate('distance.address')} + defaultValue={waypointAddress} + onPress={selectWaypoint} + maxInputLength={CONST.FORM_CHARACTER_LIMIT} + renamedInputKeys={{ + address: `waypoint${pageIndex}`, + city: '', + country: '', + street: '', + street2: '', + zipCode: '', + lat: '', + lng: '', + state: '', + }} + predefinedPlaces={recentWaypoints} + resultTypes="" + /> + @@ -260,8 +256,7 @@ export default withWritableReportOrNotFound( // Only grab the most recent 20 waypoints because that's all that is shown in the UI. This also puts them into the format of data // that the google autocomplete component expects for it's "predefined places" feature. selector: (waypoints) => - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - (waypoints ? waypoints.slice(0, CONST.RECENT_WAYPOINTS_NUMBER) : []).map((waypoint) => ({ + (waypoints ? waypoints.slice(0, CONST.RECENT_WAYPOINTS_NUMBER as number) : []).map((waypoint) => ({ name: waypoint.name, description: waypoint.address ?? '', geometry: { diff --git a/src/styles/index.ts b/src/styles/index.ts index cf2ff76a1ae9..6d2631c6669f 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -3516,6 +3516,7 @@ const styles = (theme: ThemeColors) => fontSize: variables.fontSizeNormal, lineHeight: variables.fontSizeNormalHeight, fontFamily: FontUtils.fontFamily.platform.EXP_NEUE, + flex: 1, }, searchPressable: { From 6b111840569ebd7702328d816f9d02d9348d1337 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Wed, 12 Jun 2024 13:48:30 +0100 Subject: [PATCH 05/15] refactor: remove unnecessary code and comments --- src/components/AddressSearch/index.tsx | 10 +--------- .../AddressSearch/listViewOverflow/index.native.ts | 4 ---- src/components/AddressSearch/listViewOverflow/index.ts | 4 ---- src/styles/utils/index.ts | 2 -- 4 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 src/components/AddressSearch/listViewOverflow/index.native.ts delete mode 100644 src/components/AddressSearch/listViewOverflow/index.ts diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index e3723b85e3d9..0f7d1f578861 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -23,7 +23,6 @@ import CONST from '@src/CONST'; import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import CurrentLocationButton from './CurrentLocationButton'; import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer'; -import listViewOverflow from './listViewOverflow'; import type {AddressSearchProps, PredefinedPlace} from './types'; /** @@ -439,14 +438,7 @@ function AddressSearch( }} styles={{ textInputContainer: [styles.flexColumn], - listView: [ - StyleUtils.getGoogleListViewStyle(displayListViewBorder), - listViewOverflow, - styles.borderLeft, - styles.borderRight, - styles.flexGrow0, - !isFocused && styles.h0, - ], + listView: [StyleUtils.getGoogleListViewStyle(displayListViewBorder), styles.borderLeft, styles.borderRight, styles.flexGrow0, !isFocused && styles.h0], row: [styles.pv4, styles.ph3, styles.overflowAuto], description: [styles.googleSearchText], separator: [styles.googleSearchSeparator], diff --git a/src/components/AddressSearch/listViewOverflow/index.native.ts b/src/components/AddressSearch/listViewOverflow/index.native.ts deleted file mode 100644 index 36b9f4005376..000000000000 --- a/src/components/AddressSearch/listViewOverflow/index.native.ts +++ /dev/null @@ -1,4 +0,0 @@ -// eslint-disable-next-line no-restricted-imports -import {defaultStyles} from '@styles/index'; - -export default defaultStyles.overflowHidden; diff --git a/src/components/AddressSearch/listViewOverflow/index.ts b/src/components/AddressSearch/listViewOverflow/index.ts deleted file mode 100644 index ae8bf35cc80c..000000000000 --- a/src/components/AddressSearch/listViewOverflow/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// eslint-disable-next-line no-restricted-imports -import {defaultStyles} from '@styles/index'; - -export default defaultStyles.overflowAuto; diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index f3c145210764..cfa885ba7be9 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -1428,8 +1428,6 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({ getGoogleListViewStyle: (shouldDisplayBorder: boolean): ViewStyle => { if (shouldDisplayBorder) { - // TODO: Remove this "eslint-disable-next" once the theme switching migration is done and styles are fully typed (GH Issue: https://github.com/Expensify/App/issues/27337) - // eslint-disable-next-line @typescript-eslint/no-unsafe-return return { ...styles.borderTopRounded, ...styles.borderBottomRounded, From fbb2d4add636dda4444da6e2c8ae127c9dbecdb2 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Thu, 13 Jun 2024 14:20:20 +0100 Subject: [PATCH 06/15] refactor: apply suggestion --- src/components/AddressSearch/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index 0f7d1f578861..f2da76513625 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -39,7 +39,7 @@ function isPlaceMatchForSearch(search: string, place: PredefinedPlace): boolean return false; } const fullSearchSentence = `${place.name ?? ''} ${place.description}`; - return search.split(' ').every((searchTerm) => !searchTerm || (searchTerm && fullSearchSentence.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase()))); + return search.split(' ').every((searchTerm) => !searchTerm || fullSearchSentence.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase())); } // The error that's being thrown below will be ignored until we fork the From 6f1994e4e57aed831c6762bd21925aac3600a909 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Wed, 19 Jun 2024 18:19:05 +0100 Subject: [PATCH 07/15] refactor: remove unnecessary styles --- src/components/AddressSearch/index.tsx | 4 ++-- src/pages/iou/request/step/IOURequestStepWaypoint.tsx | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index f2da76513625..275cbbf6f39b 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -438,8 +438,8 @@ function AddressSearch( }} styles={{ textInputContainer: [styles.flexColumn], - listView: [StyleUtils.getGoogleListViewStyle(displayListViewBorder), styles.borderLeft, styles.borderRight, styles.flexGrow0, !isFocused && styles.h0], - row: [styles.pv4, styles.ph3, styles.overflowAuto], + listView: [StyleUtils.getGoogleListViewStyle(displayListViewBorder), styles.borderLeft, styles.borderRight, !isFocused && styles.h0], + row: [styles.pv4, styles.ph3], description: [styles.googleSearchText], separator: [styles.googleSearchSeparator], container: [styles.mh100], diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index 61abb4f0428d..0ba61d92071d 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -160,7 +160,6 @@ function IOURequestStepWaypoint({ onEntryTransitionEnd={() => textInput.current?.focus()} shouldEnableMaxHeight testID={IOURequestStepWaypoint.displayName} - style={styles.overflowHidden} > Date: Tue, 25 Jun 2024 16:22:23 +0100 Subject: [PATCH 08/15] fix: address suggestions list not scrollable on web --- src/components/AddressSearch/index.tsx | 5 +++-- src/components/AddressSearch/isRowScrollable.native.ts | 8 ++++++++ src/components/AddressSearch/isRowScrollable.ts | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/components/AddressSearch/isRowScrollable.native.ts create mode 100644 src/components/AddressSearch/isRowScrollable.ts diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index 925bb5660830..b0acc19cc1dc 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -25,6 +25,7 @@ import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import CurrentLocationButton from './CurrentLocationButton'; import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer'; import type {AddressSearchProps, PredefinedPlace} from './types'; +import isRowScrollable from './isRowScrollable'; /** * Check if the place matches the search by the place name or description. @@ -451,7 +452,7 @@ function AddressSearch( container: [styles.mh100], }} numberOfLines={2} - isRowScrollable={false} + isRowScrollable={isRowScrollable} listHoverColor={theme.border} listUnderlayColor={theme.buttonPressedBG} onLayout={(event: LayoutChangeEvent) => { @@ -473,7 +474,7 @@ function AddressSearch( } placeholder="" listViewDisplayed - disableScroll + disableScroll={!isRowScrollable} > setLocationErrorCode(null)} diff --git a/src/components/AddressSearch/isRowScrollable.native.ts b/src/components/AddressSearch/isRowScrollable.native.ts new file mode 100644 index 000000000000..dd1f0d94be97 --- /dev/null +++ b/src/components/AddressSearch/isRowScrollable.native.ts @@ -0,0 +1,8 @@ +/** + * Whether the address suggestions list is scrollable + * + * On native, this is set to false because the whole screen is scrollable + */ +const isRowScrollable: boolean = false + +export default isRowScrollable \ No newline at end of file diff --git a/src/components/AddressSearch/isRowScrollable.ts b/src/components/AddressSearch/isRowScrollable.ts new file mode 100644 index 000000000000..96cc2f1236ec --- /dev/null +++ b/src/components/AddressSearch/isRowScrollable.ts @@ -0,0 +1,6 @@ +/** + * Whether the address suggestions list is scrollable + */ +const isRowScrollable: boolean = true + +export default isRowScrollable \ No newline at end of file From a5d2f9bfa45ecec17a423124c5aabb6368de3da4 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Wed, 26 Jun 2024 10:11:10 +0100 Subject: [PATCH 09/15] refactor: fix linter issues --- src/components/AddressSearch/isRowScrollable.native.ts | 6 +++--- src/components/AddressSearch/isRowScrollable.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/AddressSearch/isRowScrollable.native.ts b/src/components/AddressSearch/isRowScrollable.native.ts index dd1f0d94be97..aab4c3e3aa07 100644 --- a/src/components/AddressSearch/isRowScrollable.native.ts +++ b/src/components/AddressSearch/isRowScrollable.native.ts @@ -1,8 +1,8 @@ /** * Whether the address suggestions list is scrollable - * + * * On native, this is set to false because the whole screen is scrollable */ -const isRowScrollable: boolean = false +const isRowScrollable = false; -export default isRowScrollable \ No newline at end of file +export default isRowScrollable; diff --git a/src/components/AddressSearch/isRowScrollable.ts b/src/components/AddressSearch/isRowScrollable.ts index 96cc2f1236ec..3627a5b218a7 100644 --- a/src/components/AddressSearch/isRowScrollable.ts +++ b/src/components/AddressSearch/isRowScrollable.ts @@ -1,6 +1,6 @@ /** * Whether the address suggestions list is scrollable */ -const isRowScrollable: boolean = true +const isRowScrollable = true; -export default isRowScrollable \ No newline at end of file +export default isRowScrollable; From f1c0d53194e40bbba501dc3959dd72b683b195a2 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Wed, 26 Jun 2024 16:33:21 +0100 Subject: [PATCH 10/15] refactor: fix prettier issues --- src/components/AddressSearch/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index b0acc19cc1dc..d37796f65524 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -24,8 +24,8 @@ import CONST from '@src/CONST'; import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import CurrentLocationButton from './CurrentLocationButton'; import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer'; -import type {AddressSearchProps, PredefinedPlace} from './types'; import isRowScrollable from './isRowScrollable'; +import type {AddressSearchProps, PredefinedPlace} from './types'; /** * Check if the place matches the search by the place name or description. From a56370d1359855d30500008bd34ad6c36238eb88 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Thu, 27 Jun 2024 16:02:24 +0100 Subject: [PATCH 11/15] fix: suggestions not wrapping inside row --- src/components/AddressSearch/index.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index d37796f65524..2729edecc49e 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -380,10 +380,11 @@ function AddressSearch( const title = data.isPredefinedPlace ? data.name : data.structured_formatting.main_text; const subtitle = data.isPredefinedPlace ? data.description : data.structured_formatting.secondary_text; return ( - + // ScrollView is used here to allow whole screen scrolling, when the user grabs a row, on web + {!!title && {title}} {subtitle} - + ); }} onPress={(data, details) => { @@ -452,7 +453,7 @@ function AddressSearch( container: [styles.mh100], }} numberOfLines={2} - isRowScrollable={isRowScrollable} + isRowScrollable={false} listHoverColor={theme.border} listUnderlayColor={theme.buttonPressedBG} onLayout={(event: LayoutChangeEvent) => { From fdadd5fa9e3f17d00f837b63bace009d9cdde6ab Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Fri, 28 Jun 2024 12:58:35 +0100 Subject: [PATCH 12/15] fix: scrolling issues --- src/components/AddressSearch/index.tsx | 16 +++++++--------- .../AddressSearch/isRowScrollable.native.ts | 8 -------- src/components/AddressSearch/isRowScrollable.ts | 6 ------ 3 files changed, 7 insertions(+), 23 deletions(-) delete mode 100644 src/components/AddressSearch/isRowScrollable.native.ts delete mode 100644 src/components/AddressSearch/isRowScrollable.ts diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index 2729edecc49e..ca026ac21819 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -24,7 +24,6 @@ import CONST from '@src/CONST'; import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import CurrentLocationButton from './CurrentLocationButton'; import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer'; -import isRowScrollable from './isRowScrollable'; import type {AddressSearchProps, PredefinedPlace} from './types'; /** @@ -301,7 +300,7 @@ function AddressSearch( // eslint-disable-next-line react/jsx-no-useless-fragment <> {(predefinedPlaces?.length ?? 0) > 0 && ( - <> + {/* This will show current location button in list if there are some recent destinations */} {shouldShowCurrentLocationButton && ( )} {!value && {translate('common.recentDestinations')}} - + )} ); @@ -369,6 +368,7 @@ function AddressSearch( ref={containerRef} > + {!!title && {title}} {subtitle} - + ); }} onPress={(data, details) => { @@ -447,9 +446,9 @@ function AddressSearch( styles={{ textInputContainer: [styles.flexColumn], listView: [StyleUtils.getGoogleListViewStyle(displayListViewBorder), styles.borderLeft, styles.borderRight, !isFocused && styles.h0], - row: [styles.pv4, styles.ph3], + row: [styles.pv4, styles.ph3, styles.overflowAuto], description: [styles.googleSearchText], - separator: [styles.googleSearchSeparator], + separator: [styles.googleSearchSeparator, styles.overflowAuto], container: [styles.mh100], }} numberOfLines={2} @@ -475,7 +474,6 @@ function AddressSearch( } placeholder="" listViewDisplayed - disableScroll={!isRowScrollable} > setLocationErrorCode(null)} diff --git a/src/components/AddressSearch/isRowScrollable.native.ts b/src/components/AddressSearch/isRowScrollable.native.ts deleted file mode 100644 index aab4c3e3aa07..000000000000 --- a/src/components/AddressSearch/isRowScrollable.native.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Whether the address suggestions list is scrollable - * - * On native, this is set to false because the whole screen is scrollable - */ -const isRowScrollable = false; - -export default isRowScrollable; diff --git a/src/components/AddressSearch/isRowScrollable.ts b/src/components/AddressSearch/isRowScrollable.ts deleted file mode 100644 index 3627a5b218a7..000000000000 --- a/src/components/AddressSearch/isRowScrollable.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Whether the address suggestions list is scrollable - */ -const isRowScrollable = true; - -export default isRowScrollable; From 785a45ffbde399af248e6c94ca5e34847b7d5a6e Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Tue, 2 Jul 2024 18:04:22 +0100 Subject: [PATCH 13/15] fix: predefined places being filtered in offline mode --- src/components/AddressSearch/index.tsx | 28 ++------------------------ 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index ca026ac21819..de6c8515f9af 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -24,24 +24,7 @@ import CONST from '@src/CONST'; import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import CurrentLocationButton from './CurrentLocationButton'; import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer'; -import type {AddressSearchProps, PredefinedPlace} from './types'; - -/** - * Check if the place matches the search by the place name or description. - * @param search The search string for a place - * @param place The place to check for a match on the search - * @returns true if search is related to place, otherwise it returns false. - */ -function isPlaceMatchForSearch(search: string, place: PredefinedPlace): boolean { - if (!search) { - return true; - } - if (!place) { - return false; - } - const fullSearchSentence = `${place.name ?? ''} ${place.description}`; - return search.split(' ').every((searchTerm) => !searchTerm || fullSearchSentence.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase())); -} +import type {AddressSearchProps} from './types'; // The error that's being thrown below will be ignored until we fork the // react-native-google-places-autocomplete repo and replace the @@ -322,13 +305,6 @@ function AddressSearch( }; }, []); - const filteredPredefinedPlaces = useMemo(() => { - if (!isOffline || !searchValue) { - return predefinedPlaces ?? []; - } - return predefinedPlaces?.filter((predefinedPlace) => isPlaceMatchForSearch(searchValue, predefinedPlace)) ?? []; - }, [isOffline, predefinedPlaces, searchValue]); - const listEmptyComponent = useCallback( () => (!isTyping ? null : {translate('common.noResultsFound')}), [isTyping, styles, translate], @@ -372,7 +348,7 @@ function AddressSearch( fetchDetails suppressDefaultStyles enablePoweredByContainer={false} - predefinedPlaces={filteredPredefinedPlaces} + predefinedPlaces={predefinedPlaces ?? []} listEmptyComponent={listEmptyComponent} listLoaderComponent={listLoader} renderHeaderComponent={renderHeaderComponent} From 0b5bbe3bb00ccf8b966f0b3fb2f0d60400792cdb Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Thu, 4 Jul 2024 19:47:05 +0100 Subject: [PATCH 14/15] Revert "fix: predefined places being filtered in offline mode" This reverts commit 785a45ffbde399af248e6c94ca5e34847b7d5a6e. --- src/components/AddressSearch/index.tsx | 28 ++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index de6c8515f9af..ca026ac21819 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -24,7 +24,24 @@ import CONST from '@src/CONST'; import type {Address} from '@src/types/onyx/PrivatePersonalDetails'; import CurrentLocationButton from './CurrentLocationButton'; import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer'; -import type {AddressSearchProps} from './types'; +import type {AddressSearchProps, PredefinedPlace} from './types'; + +/** + * Check if the place matches the search by the place name or description. + * @param search The search string for a place + * @param place The place to check for a match on the search + * @returns true if search is related to place, otherwise it returns false. + */ +function isPlaceMatchForSearch(search: string, place: PredefinedPlace): boolean { + if (!search) { + return true; + } + if (!place) { + return false; + } + const fullSearchSentence = `${place.name ?? ''} ${place.description}`; + return search.split(' ').every((searchTerm) => !searchTerm || fullSearchSentence.toLocaleLowerCase().includes(searchTerm.toLocaleLowerCase())); +} // The error that's being thrown below will be ignored until we fork the // react-native-google-places-autocomplete repo and replace the @@ -305,6 +322,13 @@ function AddressSearch( }; }, []); + const filteredPredefinedPlaces = useMemo(() => { + if (!isOffline || !searchValue) { + return predefinedPlaces ?? []; + } + return predefinedPlaces?.filter((predefinedPlace) => isPlaceMatchForSearch(searchValue, predefinedPlace)) ?? []; + }, [isOffline, predefinedPlaces, searchValue]); + const listEmptyComponent = useCallback( () => (!isTyping ? null : {translate('common.noResultsFound')}), [isTyping, styles, translate], @@ -348,7 +372,7 @@ function AddressSearch( fetchDetails suppressDefaultStyles enablePoweredByContainer={false} - predefinedPlaces={predefinedPlaces ?? []} + predefinedPlaces={filteredPredefinedPlaces} listEmptyComponent={listEmptyComponent} listLoaderComponent={listLoader} renderHeaderComponent={renderHeaderComponent} From 363ab6ff24ca60945268d2a8e67b069a333e0bb0 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Thu, 4 Jul 2024 19:51:31 +0100 Subject: [PATCH 15/15] fix: address search not showing recent waypoints while offline --- src/components/AddressSearch/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/AddressSearch/index.tsx b/src/components/AddressSearch/index.tsx index ca026ac21819..2679a550f72f 100644 --- a/src/components/AddressSearch/index.tsx +++ b/src/components/AddressSearch/index.tsx @@ -90,7 +90,7 @@ function AddressSearch( const [isTyping, setIsTyping] = useState(false); const [isFocused, setIsFocused] = useState(false); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const [searchValue, setSearchValue] = useState(value || defaultValue || ''); + const [searchValue, setSearchValue] = useState(''); const [locationErrorCode, setLocationErrorCode] = useState(null); const [isFetchingCurrentLocation, setIsFetchingCurrentLocation] = useState(false); const shouldTriggerGeolocationCallbacks = useRef(true); @@ -323,11 +323,11 @@ function AddressSearch( }, []); const filteredPredefinedPlaces = useMemo(() => { - if (!isOffline || !searchValue) { + if (!searchValue) { return predefinedPlaces ?? []; } return predefinedPlaces?.filter((predefinedPlace) => isPlaceMatchForSearch(searchValue, predefinedPlace)) ?? []; - }, [isOffline, predefinedPlaces, searchValue]); + }, [predefinedPlaces, searchValue]); const listEmptyComponent = useCallback( () => (!isTyping ? null : {translate('common.noResultsFound')}),