From 29840090ae69d9297640d2adc1541ffe0f9cb377 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 7 Jan 2025 16:20:51 +0100 Subject: [PATCH] Fix junky animations for AnimatedStep --- .../AnimatedStep/AnimatedStepContext.ts | 2 +- .../AnimatedStep/AnimatedStepProvider.tsx | 22 ++++++-- src/components/AnimatedStep/index.tsx | 5 +- .../Security/TwoFactorAuth/Steps/GetCode.tsx | 10 +++- .../BaseTwoFactorAuthForm.tsx | 12 +---- .../TwoFactorAuth/TwoFactorAuthPage.tsx | 50 +++++++++---------- .../TwoFactorAuth/TwoFactorAuthSteps.tsx | 9 +--- 7 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/components/AnimatedStep/AnimatedStepContext.ts b/src/components/AnimatedStep/AnimatedStepContext.ts index a95669c6b626..61b2cfc75cc5 100644 --- a/src/components/AnimatedStep/AnimatedStepContext.ts +++ b/src/components/AnimatedStep/AnimatedStepContext.ts @@ -9,7 +9,7 @@ type StepContext = { currentStep: string; previousStep: string | null; setStep: (newStep: string, direction: AnimationDirection) => void; - renderStep: (stepName: string) => React.ReactNode; + renderStep: () => React.ReactNode; currentScreenAnimatedStyle: StyleProp; previousScreenAnimatedStyle: StyleProp; }; diff --git a/src/components/AnimatedStep/AnimatedStepProvider.tsx b/src/components/AnimatedStep/AnimatedStepProvider.tsx index 9b607fc07eef..ac12986ea827 100644 --- a/src/components/AnimatedStep/AnimatedStepProvider.tsx +++ b/src/components/AnimatedStep/AnimatedStepProvider.tsx @@ -1,3 +1,4 @@ +import type {ReactNode} from 'react'; import React, {useCallback, useMemo, useState} from 'react'; import {Easing, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -12,10 +13,10 @@ const ANIMATED_SCREEN_TRANSITION = 400; type AnimatedStepProviderProps = ChildrenProps & { initialStep: string; - renderStep: (name: string) => React.ReactNode; + steps: Record; }; -function AnimatedStepProvider({children, renderStep, initialStep}: AnimatedStepProviderProps): React.ReactNode { +function AnimatedStepProvider({children, steps, initialStep}: AnimatedStepProviderProps): React.ReactNode { const [animationDirection, setAnimationDirection] = useState(CONST.ANIMATION_DIRECTION.IN); const [currentStep, setCurrentStep] = useState(initialStep); const [previousStep, setPreviousStep] = useState(null); @@ -30,6 +31,10 @@ function AnimatedStepProvider({children, renderStep, initialStep}: AnimatedStepP const setStep = useCallback( (newStep: string, direction: AnimationDirection) => { + if (currentStep === newStep || !!previousStep) { + return; + } + setAnimationDirection(direction); setPreviousStep(currentStep); setCurrentStep(newStep); @@ -44,7 +49,7 @@ function AnimatedStepProvider({children, renderStep, initialStep}: AnimatedStepP prevTranslateX.set(0); prevTranslateX.set(withTiming(previousStepPosition, {duration: ANIMATED_SCREEN_TRANSITION, easing: Easing.inOut(Easing.cubic)})); }, - [currentStep, currentTranslateX, prevTranslateX, isSmallScreenWidth, windowWidth], + [currentStep, previousStep, isSmallScreenWidth, windowWidth, currentTranslateX, prevTranslateX], ); const currentScreenAnimatedStyle = useAnimatedStyle(() => ({ @@ -63,9 +68,16 @@ function AnimatedStepProvider({children, renderStep, initialStep}: AnimatedStepP setStep, currentScreenAnimatedStyle, previousScreenAnimatedStyle, - renderStep, + renderStep: () => { + return ( + <> + {steps[currentStep]} + {previousStep && steps[previousStep]} + + ); + }, }), - [currentStep, previousStep, setStep, currentScreenAnimatedStyle, previousScreenAnimatedStyle, renderStep], + [currentStep, previousStep, setStep, currentScreenAnimatedStyle, previousScreenAnimatedStyle, steps], ); return {children}; diff --git a/src/components/AnimatedStep/index.tsx b/src/components/AnimatedStep/index.tsx index 0beffc72c3dd..914ef67acf9b 100644 --- a/src/components/AnimatedStep/index.tsx +++ b/src/components/AnimatedStep/index.tsx @@ -41,10 +41,7 @@ function AnimatedStep({stepName, title = '', stepCounter, onBackButtonPress, chi }, [onEntryTransitionEnd, previousStep]); return ( - + { + if (account?.requiresTwoFactorAuth) { + return; + } + + setStep(CONST.TWO_FACTOR_AUTH_STEPS.DISABLED); + }, [account?.requiresTwoFactorAuth, setStep]); + return ( (null); const shouldClearData = account?.needsTwoFactorAuthSetup ?? false; - const {setStep} = useTwoFactorAuthContext(); /** * Handle text input and clear formError upon text change @@ -44,13 +41,6 @@ function BaseTwoFactorAuthForm({autoComplete, validateInsteadOfDisable}: BaseTwo [account?.errors], ); - useEffect(() => { - if (!account || account?.requiresTwoFactorAuth) { - return; - } - - setStep(CONST.TWO_FACTOR_AUTH_STEPS.DISABLED); - }, [account, setStep]); /** * Check that all the form fields are valid, then trigger the submit callback */ diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.tsx b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.tsx index dfc81d8c31e1..56708bca7e69 100644 --- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.tsx +++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import type {ReactNode} from 'react'; +import React, {useMemo} from 'react'; import {useOnyx} from 'react-native-onyx'; import AnimatedStepProvider from '@components/AnimatedStep/AnimatedStepProvider'; import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper'; @@ -26,29 +27,28 @@ function TwoFactorAuthPage({route}: TwoFactorAuthPageProps) { const backTo = route.params?.backTo ?? ''; const forwardTo = route.params?.forwardTo ?? ''; - const renderStep = (name: string) => { - switch (name) { - case CONST.TWO_FACTOR_AUTH_STEPS.CODES: - return ; - case CONST.TWO_FACTOR_AUTH_STEPS.VERIFY: - return ; - case CONST.TWO_FACTOR_AUTH_STEPS.SUCCESS: - return ( - - ); - case CONST.TWO_FACTOR_AUTH_STEPS.ENABLED: - return ; - case CONST.TWO_FACTOR_AUTH_STEPS.DISABLED: - return ; - case CONST.TWO_FACTOR_AUTH_STEPS.GETCODE: - return ; - default: - return ; - } - }; + const steps: Record = useMemo( + () => ({ + [CONST.TWO_FACTOR_AUTH_STEPS.CODES]: ( + + ), + [CONST.TWO_FACTOR_AUTH_STEPS.VERIFY]: , + [CONST.TWO_FACTOR_AUTH_STEPS.SUCCESS]: ( + + ), + [CONST.TWO_FACTOR_AUTH_STEPS.ENABLED]: , + [CONST.TWO_FACTOR_AUTH_STEPS.DISABLED]: , + [CONST.TWO_FACTOR_AUTH_STEPS.GETCODE]: , + }), + [backTo, forwardTo], + ); if (isActingAsDelegate) { return ( @@ -65,7 +65,7 @@ function TwoFactorAuthPage({route}: TwoFactorAuthPageProps) { return ( diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx index 5e92a31f8086..e432eea462d8 100644 --- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx +++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx @@ -7,7 +7,7 @@ import type {TwoFactorAuthStep} from '@src/types/onyx/Account'; import TwoFactorAuthContext from './TwoFactorAuthContext'; function TwoFactorAuthSteps() { - const {currentStep, previousStep, renderStep, setStep} = useAnimatedStepContext(); + const {renderStep, setStep} = useAnimatedStepContext(); useEffect(() => () => TwoFactorAuthActions.clearTwoFactorAuthData(), []); @@ -20,12 +20,7 @@ function TwoFactorAuthSteps() { [setStep], ); - return ( - - {renderStep(currentStep)} - {previousStep && renderStep(previousStep)} - - ); + return {renderStep()}; } export default TwoFactorAuthSteps;