From 76d34f00391eed34e217e6c7d02955f4c913809d Mon Sep 17 00:00:00 2001 From: Eskalifer1 Date: Fri, 18 Jul 2025 01:12:03 +0300 Subject: [PATCH 1/6] fix:65746: add scroll ability when keyboard is open on per diem page --- src/components/DestinationPicker.tsx | 1 + src/components/SelectionList/index.native.tsx | 9 +++++++-- src/components/SelectionList/index.tsx | 6 +++++- src/components/SelectionList/types.ts | 3 +++ src/pages/iou/request/IOURequestStartPage.tsx | 3 ++- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/components/DestinationPicker.tsx b/src/components/DestinationPicker.tsx index bda61f34b7337..bc69eff076a50 100644 --- a/src/components/DestinationPicker.tsx +++ b/src/components/DestinationPicker.tsx @@ -81,6 +81,7 @@ function DestinationPicker({selectedDestination, policyID, onSubmit}: Destinatio ListItem={RadioListItem} initiallyFocusedOptionKey={selectedOptionKey ?? undefined} isRowMultilineSupported + shouldHideKeyboardOnScroll={false} /> ); } diff --git a/src/components/SelectionList/index.native.tsx b/src/components/SelectionList/index.native.tsx index 4207f65c639c0..359044dcc6bf7 100644 --- a/src/components/SelectionList/index.native.tsx +++ b/src/components/SelectionList/index.native.tsx @@ -4,13 +4,18 @@ import {Keyboard} from 'react-native'; import BaseSelectionList from './BaseSelectionList'; import type {ListItem, SelectionListHandle, SelectionListProps} from './types'; -function SelectionList(props: SelectionListProps, ref: ForwardedRef) { +function SelectionList({shouldHideKeyboardOnScroll = true, ...props}: SelectionListProps, ref: ForwardedRef) { return ( Keyboard.dismiss()} + onScrollBeginDrag={() => { + if (!shouldHideKeyboardOnScroll) { + return; + } + Keyboard.dismiss(); + }} /> ); } diff --git a/src/components/SelectionList/index.tsx b/src/components/SelectionList/index.tsx index f5ee4d4c4e2df..8007a3625f0c8 100644 --- a/src/components/SelectionList/index.tsx +++ b/src/components/SelectionList/index.tsx @@ -7,7 +7,7 @@ import CONST from '@src/CONST'; import BaseSelectionList from './BaseSelectionList'; import type {ListItem, SelectionListHandle, SelectionListProps} from './types'; -function SelectionList({onScroll, ...props}: SelectionListProps, ref: ForwardedRef) { +function SelectionList({onScroll, shouldHideKeyboardOnScroll = true, ...props}: SelectionListProps, ref: ForwardedRef) { const [isScreenTouched, setIsScreenTouched] = useState(false); const touchStart = () => setIsScreenTouched(true); @@ -62,6 +62,10 @@ function SelectionList({onScroll, ...props}: SelectionLi if (!isScreenTouched) { return; } + + if (!shouldHideKeyboardOnScroll) { + return; + } Keyboard.dismiss(); }; diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index 8c2e66dbc04b5..38108c795773b 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -826,6 +826,9 @@ type SelectionListProps = Partial & { /** Whether product training tooltips can be displayed */ canShowProductTrainingTooltip?: boolean; + + /** Whether to hide the keyboard when scrolling a list */ + shouldHideKeyboardOnScroll?: boolean; } & TRightHandSideComponent; type SelectionListHandle = { diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index 2b859abef349f..1dca1cbc26f3f 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -174,7 +174,8 @@ function IOURequestStartPage({ allPolicies={allPolicies} > Date: Fri, 18 Jul 2025 23:45:56 +0300 Subject: [PATCH 2/6] fix: eslint in DestinationPicker --- src/components/DestinationPicker.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/DestinationPicker.tsx b/src/components/DestinationPicker.tsx index bc69eff076a50..261a815627df8 100644 --- a/src/components/DestinationPicker.tsx +++ b/src/components/DestinationPicker.tsx @@ -3,10 +3,10 @@ import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as PerDiemRequestUtils from '@libs/PerDiemRequestUtils'; +import {getHeaderMessageForNonUserList} from '@libs/OptionsListUtils'; +import {getDestinationListSections} from '@libs/PerDiemRequestUtils'; import type {Destination} from '@libs/PerDiemRequestUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; +import {getPerDiemCustomUnit} from '@libs/PolicyUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import SelectionList from './SelectionList'; @@ -21,8 +21,8 @@ type DestinationPickerProps = { function DestinationPicker({selectedDestination, policyID, onSubmit}: DestinationPickerProps) { const policy = usePolicy(policyID); - const customUnit = PolicyUtils.getPerDiemCustomUnit(policy); - const [policyRecentlyUsedDestinations] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_DESTINATIONS}${policyID}`); + const customUnit = getPerDiemCustomUnit(policy); + const [policyRecentlyUsedDestinations] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_DESTINATIONS}${policyID}`, {canBeMissing: true}); const {translate} = useLocalize(); const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); @@ -49,7 +49,7 @@ function DestinationPicker({selectedDestination, policyID, onSubmit}: Destinatio }, [customUnit?.rates, selectedDestination]); const [sections, headerMessage, shouldShowTextInput] = useMemo(() => { - const destinationOptions = PerDiemRequestUtils.getDestinationListSections({ + const destinationOptions = getDestinationListSections({ searchValue: debouncedSearchValue, selectedOptions, destinations: Object.values(customUnit?.rates ?? {}), @@ -57,7 +57,7 @@ function DestinationPicker({selectedDestination, policyID, onSubmit}: Destinatio }); const destinationData = destinationOptions?.at(0)?.data ?? []; - const header = OptionsListUtils.getHeaderMessageForNonUserList(destinationData.length > 0, debouncedSearchValue); + const header = getHeaderMessageForNonUserList(destinationData.length > 0, debouncedSearchValue); const destinationsCount = Object.values(customUnit?.rates ?? {}).length; const isDestinationsCountBelowThreshold = destinationsCount < CONST.STANDARD_LIST_ITEM_LIMIT; const showInput = !isDestinationsCountBelowThreshold; From 1fb4579bf40076c37379ed53fa266455b58d7d19 Mon Sep 17 00:00:00 2001 From: Eskalifer1 Date: Mon, 21 Jul 2025 11:05:11 +0300 Subject: [PATCH 3/6] fix:65746: added Keyboard.dismiss on tab change in Create Expense --- src/components/SelectionList/index.tsx | 8 ++------ src/pages/iou/request/IOURequestStartPage.tsx | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/components/SelectionList/index.tsx b/src/components/SelectionList/index.tsx index 8007a3625f0c8..c5f26d8c3b1d8 100644 --- a/src/components/SelectionList/index.tsx +++ b/src/components/SelectionList/index.tsx @@ -58,12 +58,8 @@ function SelectionList({onScroll, shouldHideKeyboardOnSc // In SearchPageBottomTab we use useAnimatedScrollHandler from reanimated(for performance reasons) and it returns object instead of function. In that case we cannot change it to a function call, that's why we have to choose between onScroll and defaultOnScroll. const defaultOnScroll = () => { - // Only dismiss the keyboard whenever the user scrolls the screen - if (!isScreenTouched) { - return; - } - - if (!shouldHideKeyboardOnScroll) { + // Only dismiss the keyboard whenever the user scrolls the screen or `shouldHideKeyboardOnScroll` is true + if (!isScreenTouched || !shouldHideKeyboardOnScroll) { return; } Keyboard.dismiss(); diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index 1dca1cbc26f3f..1ae69a932303b 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -1,6 +1,6 @@ import {useFocusEffect} from '@react-navigation/native'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; +import {Keyboard, View} from 'react-native'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; import FocusTrapContainerElement from '@components/FocusTrap/FocusTrapContainerElement'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -115,6 +115,7 @@ function IOURequestStartPage({ const resetIOUTypeIfChanged = useCallback( (newIOUType: IOURequestType) => { + Keyboard.dismiss(); if (transaction?.iouRequestType === newIOUType) { return; } From 750ebb031834a88889ee68d675ad38e3bd39acd5 Mon Sep 17 00:00:00 2001 From: Eskalifer1 Date: Mon, 21 Jul 2025 14:56:47 +0300 Subject: [PATCH 4/6] fix: IOS shouldEnableKeyboardAvoidingView broke the navigation --- src/pages/iou/request/IOURequestStartPage.tsx | 2 +- .../step/IOURequestStepDestination.tsx | 107 ++++++++++-------- 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index 1ae69a932303b..5aef2a6128475 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -175,7 +175,7 @@ function IOURequestStartPage({ allPolicies={allPolicies} > - {isLoading && ( - - )} - {shouldShowOfflineView && {null}} - {shouldShowEmptyState && ( - - + {isLoading && ( + + )} + {shouldShowOfflineView && {null}} + {shouldShowEmptyState && ( + + + {isPolicyAdmin(policy) && !!policy?.areCategoriesEnabled && ( + +