From d9b23b2ad52a7419b7c81a1c0242e72c473e199a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Tue, 17 Mar 2026 13:54:59 +0100 Subject: [PATCH 1/4] fix: 85431 Improve animations for flows using useSubPage --- src/hooks/useSubPage/index.tsx | 22 ++++--------------- .../ModalStackNavigators/index.tsx | 3 --- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/hooks/useSubPage/index.tsx b/src/hooks/useSubPage/index.tsx index 58506007a4dfe..5004aec670138 100644 --- a/src/hooks/useSubPage/index.tsx +++ b/src/hooks/useSubPage/index.tsx @@ -1,12 +1,10 @@ -import {useRoute} from '@react-navigation/native'; +import {useNavigation, useRoute} from '@react-navigation/native'; import type {ComponentType} from 'react'; import {useEffect} from 'react'; import Navigation from '@libs/Navigation/Navigation'; import {findLastPageIndex, findPageIndex} from '@libs/SubPageUtils'; import type {SubPageProps, UseSubPageProps} from './types'; -const AMOUNT_OF_FRAMES_TO_WAIT_FOR = 20; - /** * @param pages - array of objects with pageName and component to display in each page * @param onFinished - callback triggered after finishing the last page @@ -16,6 +14,7 @@ const AMOUNT_OF_FRAMES_TO_WAIT_FOR = 20; * @param buildRoute - function that returns the route for a given page name and optional action */ export default function useSubPage({pages, onFinished, startFrom = 0, skipPages = [], onPageChange = () => {}, buildRoute}: UseSubPageProps) { + const navigation = useNavigation(); const route = useRoute(); const params = route.params as {subPage?: string; action?: 'edit'} | undefined; const urlPageName = params?.subPage; @@ -29,21 +28,8 @@ export default function useSubPage({pages, onFinish return; } - let requestID: number; - const waitFrames = (framesLeft: number) => { - if (framesLeft <= 0) { - Navigation.navigate(buildRoute(startPageName), {forceReplace: true}); - return; - } - requestID = requestAnimationFrame(() => waitFrames(framesLeft - 1)); - }; - - requestID = requestAnimationFrame(() => waitFrames(AMOUNT_OF_FRAMES_TO_WAIT_FOR)); - - return () => { - cancelAnimationFrame(requestID); - }; - }, [isRedirecting, startPageName, buildRoute]); + navigation.setParams({subPage: startPageName} as Record); + }, [isRedirecting, startPageName, navigation]); const currentPageName = urlPageName ?? startPageName ?? pages.at(0)?.pageName; const pageIndex = findPageIndex(pages, currentPageName); diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 30d5ba47887e8..575742d2f4df6 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -88,9 +88,6 @@ const OPTIONS_PER_SCREEN: Partial [SCREENS.TRAVEL.WORKSPACE_ADDRESS]: { animationTypeForReplace: 'push', }, - [SCREENS.MISSING_PERSONAL_DETAILS]: { - animationTypeForReplace: 'push', - }, [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD]: { animationTypeForReplace: 'push', }, From 50cba233fe1908667d75d33b28d917cddb2f43ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Wed, 18 Mar 2026 13:47:54 +0100 Subject: [PATCH 2/4] tests --- tests/unit/useSubPageTest.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/unit/useSubPageTest.tsx b/tests/unit/useSubPageTest.tsx index 79f7d2e180acf..d1bd47a5bff1e 100644 --- a/tests/unit/useSubPageTest.tsx +++ b/tests/unit/useSubPageTest.tsx @@ -12,19 +12,16 @@ jest.mock('@libs/Navigation/Navigation', () => ({ goBack: jest.fn(), })); -jest.spyOn(global, 'requestAnimationFrame').mockImplementation((callback) => { - callback(0); - return 0; -}); - type AnyRoute = RouteProp | undefined>, string>; const mockUseRoute = jest.fn(); +const mockSetParams = jest.fn(); jest.mock('@react-navigation/native', () => { // eslint-disable-next-line @typescript-eslint/consistent-type-imports const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, useRoute: () => mockUseRoute(), + useNavigation: () => ({setParams: mockSetParams}), }; }); @@ -135,7 +132,7 @@ describe('useSubPage hook', () => { expect(result.current.CurrentPage).toBe(mockSubPageTwo); }); - it('navigates to startFrom page on mount when no subPage param is present', () => { + it('sets params to startFrom page on mount when no subPage param is present', () => { const pages = createMockPages(); const buildRoute = createBuildRoute(); @@ -148,7 +145,7 @@ describe('useSubPage hook', () => { }), ); - expect(Navigation.navigate).toHaveBeenCalledWith(buildRoute('page3'), {forceReplace: true}); + expect(mockSetParams).toHaveBeenCalledWith({subPage: 'page3'}); }); it('returns isRedirecting true when no subPage param is present in URL', () => { From 2c0b915b8c91f425ff9ab69d3aa5899d9ec51ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Wed, 18 Mar 2026 14:06:55 +0100 Subject: [PATCH 3/4] fix: revert animation change --- .../Navigation/AppNavigator/ModalStackNavigators/index.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 936e068e9b205..f12760b74776b 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -88,12 +88,6 @@ const OPTIONS_PER_SCREEN: Partial [SCREENS.TRAVEL.WORKSPACE_ADDRESS]: { animationTypeForReplace: 'push', }, - [SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD]: { - animationTypeForReplace: 'push', - }, - [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: { - animationTypeForReplace: 'push', - }, [SCREENS.MULTIFACTOR_AUTHENTICATION.MAGIC_CODE]: { animationTypeForReplace: 'push', }, From 454a92ad940d6e705623b9c777a77cc5f8702e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Muzyk?= Date: Thu, 19 Mar 2026 11:07:33 +0100 Subject: [PATCH 4/4] fix: safety check when data is not loaded --- src/hooks/useSubPage/index.tsx | 4 ++-- .../MissingPersonalDetails/MissingPersonalDetailsContent.tsx | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hooks/useSubPage/index.tsx b/src/hooks/useSubPage/index.tsx index 5004aec670138..a295cf885255a 100644 --- a/src/hooks/useSubPage/index.tsx +++ b/src/hooks/useSubPage/index.tsx @@ -20,8 +20,8 @@ export default function useSubPage({pages, onFinish const urlPageName = params?.subPage; const isEditing = params?.action === 'edit'; - const startPageName = pages.at(startFrom)?.pageName; - const isRedirecting = !urlPageName && !!startPageName; + const startPageName = startFrom >= 0 ? pages.at(startFrom)?.pageName : undefined; + const isRedirecting = !urlPageName && (!!startPageName || startFrom < 0); useEffect(() => { if (!isRedirecting) { diff --git a/src/pages/MissingPersonalDetails/MissingPersonalDetailsContent.tsx b/src/pages/MissingPersonalDetails/MissingPersonalDetailsContent.tsx index fd35b8d25569e..add80c2988c35 100644 --- a/src/pages/MissingPersonalDetails/MissingPersonalDetailsContent.tsx +++ b/src/pages/MissingPersonalDetails/MissingPersonalDetailsContent.tsx @@ -85,6 +85,9 @@ function MissingPersonalDetailsContent({privatePersonalDetails, draftValues, hea const values = useMemo(() => normalizeCountryCode(getSubPageValues(privatePersonalDetails, draftValues)) as PersonalDetailsForm, [privatePersonalDetails, draftValues]); const startFrom = useMemo(() => { + if (shouldCollectPIN === undefined) { + return -1; + } const initialPage = getInitialSubPage(values, shouldCollectPIN, PIN); return findPageIndex(formPages, initialPage); }, [formPages, values, shouldCollectPIN, PIN]);