diff --git a/src/components/DestinationPicker.tsx b/src/components/DestinationPicker.tsx index 8ffee6e20d3f..73b9597fe9bf 100644 --- a/src/components/DestinationPicker.tsx +++ b/src/components/DestinationPicker.tsx @@ -1,4 +1,5 @@ import React, {useMemo} from 'react'; +import type {ForwardedRef} from 'react'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -12,15 +13,17 @@ import ONYXKEYS from '@src/ONYXKEYS'; // eslint-disable-next-line no-restricted-imports import SelectionList from './SelectionListWithSections'; import RadioListItem from './SelectionListWithSections/RadioListItem'; -import type {ListItem} from './SelectionListWithSections/types'; +import type {ListItem, SelectionListHandle} from './SelectionListWithSections/types'; type DestinationPickerProps = { policyID: string; selectedDestination?: string; onSubmit: (item: ListItem & {currency: string}) => void; + ref?: ForwardedRef; + textInputAutoFocus?: boolean; }; -function DestinationPicker({selectedDestination, policyID, onSubmit}: DestinationPickerProps) { +function DestinationPicker({selectedDestination, policyID, onSubmit, ref, textInputAutoFocus = false}: DestinationPickerProps) { const policy = usePolicy(policyID); const customUnit = getPerDiemCustomUnit(policy); const [policyRecentlyUsedDestinations] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_DESTINATIONS}${policyID}`, {canBeMissing: true}); @@ -71,6 +74,7 @@ function DestinationPicker({selectedDestination, policyID, onSubmit}: Destinatio return ( ); diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index b2e52369c9f9..4288e7130970 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -6,6 +6,7 @@ import DragAndDropProvider from '@components/DragAndDrop/Provider'; import FocusTrapContainerElement from '@components/FocusTrap/FocusTrapContainerElement'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import {useProductTrainingContext} from '@components/ProductTrainingContext'; +import type {AnimatedTextInputRef} from '@components/RNTextInput'; import ScreenWrapper from '@components/ScreenWrapper'; import TabSelector from '@components/TabSelector/TabSelector'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; @@ -87,6 +88,8 @@ function IOURequestStartPage({ const [nvpDismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); const hasOnlyPersonalPolicies = useMemo(() => hasOnlyPersonalPoliciesUtil(allPolicies), [allPolicies]); + const perDiemInputRef = useRef(null); + const tabTitles = { [CONST.IOU.TYPE.REQUEST]: translate('iou.createExpense'), [CONST.IOU.TYPE.SUBMIT]: translate('iou.createExpense'), @@ -99,6 +102,18 @@ function IOURequestStartPage({ [CONST.IOU.TYPE.CREATE]: translate('iou.createExpense'), }; + const onTabSelectFocusHandler = ({index}: {index: number}) => { + // We requestAnimationFrame since the function is called in the animate block in the web implementation + // which fixes a locked animation glitch when swiping between tabs, and aligns with the native implementation internal delay + requestAnimationFrame(() => { + // 2 - PerDiem + if (index !== 2) { + return; + } + perDiemInputRef.current?.focus?.(); + }); + }; + const isFromGlobalCreate = isEmptyObject(report?.reportID); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const policiesWithPerDiemEnabledAndHasRates = useMemo( @@ -241,6 +256,8 @@ function IOURequestStartPage({ useHandleBackButton(onBackButtonPress); + const shouldShowWorkspaceSelectForPerDiem = moreThanOnePerDiemExist && !hasCurrentPolicyPerDiemEnabled; + return ( {() => ( - {moreThanOnePerDiemExist && !hasCurrentPolicyPerDiemEnabled ? ( + {shouldShowWorkspaceSelectForPerDiem ? ( ) : ( void; +}; + type IOURequestStepDestinationProps = WithWritableReportOrNotFoundProps & WithFullTransactionOrNotFoundProps & { openedFromStartPage?: boolean; explicitPolicyID?: string; + shouldAutoFocusInput?: boolean; + ref: ForwardedRef; }; function IOURequestStepDestination({ @@ -57,6 +64,8 @@ function IOURequestStepDestination({ transaction, openedFromStartPage = false, explicitPolicyID, + shouldAutoFocusInput = true, + ref, }: IOURequestStepDestinationProps) { const [policy, policyMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${explicitPolicyID ?? getIOURequestPolicyID(transaction, report)}`, {canBeMissing: false}); const personalPolicy = usePersonalPolicy(); @@ -70,6 +79,12 @@ function IOURequestStepDestination({ const illustrations = useMemoizedLazyIllustrations(['EmptyStateExpenses']); const {translate} = useLocalize(); + const destinationSelectionListRef = useRef(null); + + useImperativeHandle(ref, () => ({ + focus: destinationSelectionListRef.current?.focusTextInput, + })); + // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = isEmptyObject(policy); @@ -196,6 +211,8 @@ function IOURequestStepDestination({ )} {!shouldShowEmptyState && !isLoading && !shouldShowOfflineView && !!policy?.id && (