feat: finished fade animation between steps

moved useState props to redux, fixed back button
pull/3056/head
William Grant 1 year ago
parent f196bab2ea
commit e6dedc83fb

@ -2,7 +2,7 @@ import styled from 'styled-components';
import { useRightOverlayMode } from '../../../hooks/useUI';
import { isRtlBody } from '../../../util/i18n';
import { Flex } from '../../basic/Flex';
import { OverlayRightPanelSettings2 } from './overlay/OverlayRightPanelSettings2';
import { OverlayRightPanelSettings } from './overlay/OverlayRightPanelSettings';
import { OverlayDisappearingMessages } from './overlay/disappearing-messages/OverlayDisappearingMessages';
import { OverlayMessageInfo } from './overlay/message-info/OverlayMessageInfo';
@ -107,8 +107,7 @@ const ClosableOverlay = () => {
case 'message_info':
return <OverlayMessageInfo />;
default:
// TODO[epic=ses-50] revert to proper right panel settings later
return <OverlayRightPanelSettings2 />;
return <OverlayRightPanelSettings />;
}
};

@ -1,108 +0,0 @@
import { useEffect, useState } from 'react';
import { MAX_NAME_LENGTH_BYTES } from '../../../../session/constants';
import { ToastUtils } from '../../../../session/utils';
import { sanitizeSessionUsername } from '../../../../session/utils/String';
import { useSelectedConversationKey } from '../../../../state/selectors/selectedConversation';
import { Flex } from '../../../basic/Flex';
import { SessionButton } from '../../../basic/SessionButton';
import { SpacerLG, SpacerXL } from '../../../basic/Text';
import { SessionInput } from '../../../inputs';
import { SessionProgressBar } from '../../../loading';
import { StyledScrollContainer } from './components';
export const OverlayRightPanelSettings2 = () => {
const selectedConvoKey = useSelectedConversationKey();
// TODO[epic=ses-50] move this into already have an account screen
// #region for testing
const [progress, setProgress] = useState(0);
const [inputValue, setInputValue] = useState('');
const [inputError, setInputError] = useState<string | undefined>(undefined);
function sanitizeDisplayNameOrToast(
displayName: string,
setDisplayName: (sanitized: string) => void,
setDisplayNameError: (error: string | undefined) => void
) {
try {
const sanitizedName = sanitizeSessionUsername(displayName);
const trimName = sanitizedName.trim();
setDisplayName(sanitizedName);
setDisplayNameError(!trimName ? window.i18n('displayNameEmpty') : undefined);
} catch (e) {
setDisplayName(displayName);
setDisplayNameError(window.i18n('displayNameTooLong'));
ToastUtils.pushToastError('toolong', window.i18n('displayNameTooLong'));
}
}
const handleInputChanged = (name: string) => {
sanitizeDisplayNameOrToast(name, setInputValue, setInputError);
if (name.length > 8) {
setInputError(window.i18n('displayNameTooLong'));
}
};
const handleEnterPressed = (name: string) => {
if (name) {
sanitizeDisplayNameOrToast(name, setInputValue, setInputError);
ToastUtils.pushToastSuccess('success', window.i18n('done'));
}
};
useEffect(() => {
const interval = setInterval(() => {
setProgress(oldProgress => {
if (oldProgress === 100) {
clearInterval(interval);
return 100;
}
return Math.min(oldProgress + 10, 100);
});
}, 1000);
return () => clearInterval(interval);
}, []);
// #endregion
if (!selectedConvoKey) {
return null;
}
return (
<StyledScrollContainer>
<Flex container={true} flexDirection={'column'} alignItems={'center'}>
<SessionProgressBar
progress={progress}
width={'320px'}
margin={'var(--margins-lg) auto'}
title={window.i18n('waitOneMoment')}
subtitle={window.i18n('loadAccountProgressMessage')}
showPercentage={true}
/>
<SpacerLG />
<SessionInput
placeholder={window.i18n('enterDisplayName')}
value={inputValue}
error={inputError}
maxLength={MAX_NAME_LENGTH_BYTES}
onValueChanged={handleInputChanged}
onEnterPressed={handleEnterPressed}
ctaButton={
<SessionButton
onClick={() => {
window.log.debug(
`WIP: [OverlayRightPanelSettings] clicked continuing your session! `
);
}}
text={window.i18n('continueYourSession')}
/>
}
/>
<SpacerLG />
<SpacerXL />
</Flex>
</StyledScrollContainer>
);
};

@ -1,23 +1,19 @@
import { shell } from 'electron';
import { AnimatePresence } from 'framer-motion';
import { useDispatch } from 'react-redux';
import { useMount } from 'react-use';
import styled from 'styled-components';
import { Data } from '../../data/data';
import { getConversationController } from '../../session/conversations';
import { mnDecode } from '../../session/crypto/mnemonic';
import { StringUtils } from '../../session/utils';
import { fromHex } from '../../session/utils/String';
import {
AccountCreation,
AccountRestoration,
Onboarding,
setGeneratedRecoveryPhrase,
setHexGeneratedPubKey,
} from '../../state/onboarding/ducks/registration';
import {
useOnboardGeneratedRecoveryPhrase,
useOnboardAccountCreationStep,
useOnboardAccountRestorationStep,
useOnboardStep,
} from '../../state/onboarding/selectors/registration';
import { generateMnemonic, sessionGenerateKeyPair } from '../../util/accountManager';
import { Storage } from '../../util/storage';
import { Flex } from '../basic/Flex';
import { SpacerLG, SpacerSM } from '../basic/Text';
@ -49,33 +45,11 @@ const StyledRegistrationContainer = styled(Flex)`
`;
export const RegistrationStages = () => {
const generatedRecoveryPhrase = useOnboardGeneratedRecoveryPhrase();
const step = useOnboardStep();
const dispatch = useDispatch();
const generateMnemonicAndKeyPair = async () => {
if (generatedRecoveryPhrase === '') {
const mnemonic = await generateMnemonic();
let seedHex = mnDecode(mnemonic);
// handle shorter than 32 bytes seeds
const privKeyHexLength = 32 * 2;
if (seedHex.length !== privKeyHexLength) {
seedHex = seedHex.concat('0'.repeat(32));
seedHex = seedHex.substring(0, privKeyHexLength);
}
const seed = fromHex(seedHex);
const keyPair = await sessionGenerateKeyPair(seed);
const newHexPubKey = StringUtils.decode(keyPair.pubKey, 'hex');
dispatch(setGeneratedRecoveryPhrase(mnemonic));
dispatch(setHexGeneratedPubKey(newHexPubKey)); // our 'frontend' sessionID
}
};
const creationStep = useOnboardAccountCreationStep();
const restorationStep = useOnboardAccountRestorationStep();
useMount(() => {
void generateMnemonicAndKeyPair();
void resetRegistration();
});
@ -117,7 +91,10 @@ export const RegistrationStages = () => {
<Flex container={true} flexDirection="column" alignItems="center">
<SpacerLG />
<OnboardContainer key={'onboarding-container'} animate={true} direction="right">
<OnboardContainer
key={`${Onboarding[step]}-${step === Onboarding.CreateAccount ? AccountCreation[creationStep] : AccountRestoration[restorationStep]}`}
animate={step !== Onboarding.Start}
>
{step === Onboarding.Start ? <Start /> : null}
{step === Onboarding.CreateAccount ? <CreateAccount /> : null}
{step === Onboarding.RestoreAccount ? <RestoreAccount /> : null}

@ -1,13 +1,16 @@
import { ReactNode } from 'react';
import { useDispatch } from 'react-redux';
import {
AccountCreation,
AccountRestoration,
Onboarding,
setAccountCreationStep,
setAccountRestorationStep,
setDirection,
setOnboardingStep,
} from '../../../state/onboarding/ducks/registration';
import {
useOnboardAccountRestorationStep,
useOnboardStep,
} from '../../../state/onboarding/selectors/registration';
import { Flex } from '../../basic/Flex';
import { SessionIconButton } from '../../icon';
@ -31,6 +34,9 @@ export const BackButtonWithininContainer = ({
};
export const BackButton = ({ callback }: { callback?: () => void }) => {
const step = useOnboardStep();
const restorationStep = useOnboardAccountRestorationStep();
const dispatch = useDispatch();
return (
@ -40,9 +46,19 @@ export const BackButton = ({ callback }: { callback?: () => void }) => {
iconColor="var(--color-text-primary)"
iconRotation={90}
onClick={() => {
dispatch(setOnboardingStep(Onboarding.Start));
dispatch(setAccountRestorationStep(AccountRestoration.RecoveryPassword));
dispatch(setAccountCreationStep(AccountCreation.DisplayName));
dispatch(setDirection('backward'));
if (step === Onboarding.CreateAccount) {
dispatch(setOnboardingStep(Onboarding.Start));
}
if (step === Onboarding.RestoreAccount) {
if (restorationStep === AccountRestoration.RecoveryPassword) {
dispatch(setOnboardingStep(Onboarding.Start));
} else if (restorationStep === AccountRestoration.DisplayName) {
dispatch(setAccountRestorationStep(AccountRestoration.RecoveryPassword));
}
}
if (callback) {
callback();
}

@ -6,21 +6,18 @@ type OnboardContainerProps = {
animate?: boolean;
children: ReactNode;
key: string;
direction: 'left' | 'right';
};
export const OnboardContainer = (props: OnboardContainerProps) => {
const { animate = false, children, key, direction: _direction } = props;
const { animate = false, children, key } = props;
const OnboardContainerInner = styled(motion.div)`
width: 100%;
`;
const direction = _direction === 'left' ? -1 : 1;
const fadeSlideVariants = {
initial: { x: 50 * direction, opacity: 0 },
animate: { x: 0, opacity: 1 },
exit: { x: -50 * direction, opacity: 0 },
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
};
return (
@ -30,7 +27,7 @@ export const OnboardContainer = (props: OnboardContainerProps) => {
initial={'initial'}
animate={'animate'}
exit={'exit'}
transition={{ duration: 0.5 }}
transition={{ duration: 1 }}
>
{children}
</OnboardContainerInner>

@ -1,4 +1,4 @@
import { Dispatch } from '@reduxjs/toolkit';
import { AnyAction, Dispatch } from '@reduxjs/toolkit';
import { isEmpty } from 'lodash';
import { useEffect } from 'react';
import { ONBOARDING_TIMES } from '../../../session/constants';
@ -13,7 +13,7 @@ let interval: NodeJS.Timeout;
type UseRecoveryProgressEffectProps = {
step: AccountRestoration;
progress: number;
setProgress: (progress: number) => void;
setProgress: (progress: number) => AnyAction;
displayName: string;
dispatch: Dispatch;
};
@ -22,7 +22,7 @@ type UseRecoveryProgressEffectProps = {
* Effect to handle the progress rate of the recovery loading animation
* @param step AccountRestoration the onboarding step we are currently on
* @param progress number the progress of the loading bar
* @param setProgress (progress: number) => void function to set the progress of the loading bar
* @param setProgress (progress: number) => AnyAction redux function to set the progress of the loading bar
* @param displayName string the display name of the user
* @param dispatch
*/
@ -33,7 +33,7 @@ export const useRecoveryProgressEffect = (props: UseRecoveryProgressEffectProps)
if (step === AccountRestoration.Loading) {
interval = setInterval(() => {
if (progress < 100) {
setProgress(progress + 1);
dispatch(setProgress(progress + 1));
}
window.log.debug(
`WIP: [continueYourSession] AccountRestoration.Loading Loading progress ${progress}%`
@ -53,7 +53,7 @@ export const useRecoveryProgressEffect = (props: UseRecoveryProgressEffectProps)
if (step === AccountRestoration.Finishing) {
interval = setInterval(() => {
if (progress < 100) {
setProgress(progress + 1);
dispatch(setProgress(progress + 1));
}
window.log.debug(
`WIP: [continueYourSession] AccountRestoration. Finishing progress ${progress}%`

@ -1,17 +1,29 @@
import { useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { useMount } from 'react-use';
import { SettingsKey } from '../../../data/settings-key';
import { mnDecode } from '../../../session/crypto/mnemonic';
import { StringUtils } from '../../../session/utils';
import { fromHex } from '../../../session/utils/String';
import { trigger } from '../../../shims/events';
import {
AccountCreation,
setAccountCreationStep,
setDisplayName,
setHexGeneratedPubKey,
setRecoveryPassword,
} from '../../../state/onboarding/ducks/registration';
import {
useDisplayName,
useOnboardAccountCreationStep,
useOnboardGeneratedRecoveryPhrase,
useOnboardHexGeneratedPubKey,
useRecoveryPassword,
} from '../../../state/onboarding/selectors/registration';
import { registerSingleDevice } from '../../../util/accountManager';
import {
generateMnemonic,
registerSingleDevice,
sessionGenerateKeyPair,
} from '../../../util/accountManager';
import { Storage, setSignWithRecoveryPhrase } from '../../../util/storage';
import { Flex } from '../../basic/Flex';
import { SessionButton, SessionButtonColor } from '../../basic/SessionButton';
@ -43,16 +55,40 @@ async function signUp(signUpDetails: RecoverDetails) {
export const CreateAccount = () => {
const step = useOnboardAccountCreationStep();
const recoveryPassword = useOnboardGeneratedRecoveryPhrase();
const recoveryPassword = useRecoveryPassword();
const hexGeneratedPubKey = useOnboardHexGeneratedPubKey();
const dispatch = useDispatch();
const [displayName, setDisplayName] = useState('');
const displayName = useDisplayName();
const [displayNameError, setDisplayNameError] = useState<undefined | string>('');
const generateMnemonicAndKeyPair = async () => {
if (recoveryPassword === '') {
const mnemonic = await generateMnemonic();
let seedHex = mnDecode(mnemonic);
// handle shorter than 32 bytes seeds
const privKeyHexLength = 32 * 2;
if (seedHex.length !== privKeyHexLength) {
seedHex = seedHex.concat('0'.repeat(32));
seedHex = seedHex.substring(0, privKeyHexLength);
}
const seed = fromHex(seedHex);
const keyPair = await sessionGenerateKeyPair(seed);
const newHexPubKey = StringUtils.decode(keyPair.pubKey, 'hex');
dispatch(setRecoveryPassword(mnemonic));
dispatch(setHexGeneratedPubKey(newHexPubKey)); // our 'frontend' sessionID
}
};
useMount(() => {
void generateMnemonicAndKeyPair();
});
useEffect(() => {
if (step === AccountCreation.DisplayName) {
if (step === AccountCreation.DisplayName && hexGeneratedPubKey) {
window.Session.setNewSessionID(hexGeneratedPubKey);
}
}, [step, hexGeneratedPubKey]);
@ -85,6 +121,8 @@ export const CreateAccount = () => {
<BackButtonWithininContainer
margin={'2px 0 0 -36px'}
callback={() => {
dispatch(setDisplayName(''));
dispatch(setRecoveryPassword(''));
setDisplayNameError('');
}}
>
@ -101,11 +139,13 @@ export const CreateAccount = () => {
<SpacerLG />
<SessionInput
autoFocus={true}
disabledOnBlur={true}
type="text"
placeholder={window.i18n('enterDisplayName')}
value={displayName}
onValueChanged={(name: string) => {
sanitizeDisplayNameOrToast(name, setDisplayName, setDisplayNameError);
onValueChanged={(_name: string) => {
const name = sanitizeDisplayNameOrToast(_name, setDisplayNameError);
dispatch(setDisplayName(name));
}}
onEnterPressed={signUpWithDetails}
error={displayNameError}

@ -9,8 +9,16 @@ import { NotFoundError } from '../../../session/utils/errors';
import {
AccountRestoration,
setAccountRestorationStep,
setDisplayName,
setProgress,
setRecoveryPassword,
} from '../../../state/onboarding/ducks/registration';
import { useOnboardAccountRestorationStep } from '../../../state/onboarding/selectors/registration';
import {
useDisplayName,
useOnboardAccountRestorationStep,
useProgress,
useRecoveryPassword,
} from '../../../state/onboarding/selectors/registration';
import { registerSingleDevice, signInByLinkingDevice } from '../../../util/accountManager';
import { setSignInByLinking, setSignWithRecoveryPhrase } from '../../../util/storage';
import { Flex } from '../../basic/Flex';
@ -99,15 +107,15 @@ async function signInAndFetchDisplayName(
export const RestoreAccount = () => {
const step = useOnboardAccountRestorationStep();
const [recoveryPassword, setRecoveryPassword] = useState('');
const recoveryPassword = useRecoveryPassword();
const [recoveryPasswordError, setRecoveryPasswordError] = useState(
undefined as string | undefined
);
const [displayName, setDisplayName] = useState('');
const displayName = useDisplayName();
const [displayNameError, setDisplayNameError] = useState<undefined | string>('');
const [progress, setProgress] = useState(0);
const progress = useProgress();
const dispatch = useDispatch();
@ -118,7 +126,7 @@ export const RestoreAccount = () => {
return;
}
setProgress(0);
dispatch(setProgress(0));
try {
const displayNameFromNetwork = await signInAndFetchDisplayName({
recoveryPassword,
@ -129,7 +137,7 @@ export const RestoreAccount = () => {
dispatch(setAccountRestorationStep(AccountRestoration.Loading));
},
});
setDisplayName(displayNameFromNetwork);
dispatch(setDisplayName(displayNameFromNetwork));
dispatch(setAccountRestorationStep(AccountRestoration.Finishing));
} catch (e) {
if (e instanceof NotFoundError) {
@ -161,7 +169,7 @@ export const RestoreAccount = () => {
return;
}
setProgress(0);
dispatch(setProgress(0));
try {
await signInWithNewDisplayName({
displayName,
@ -186,9 +194,12 @@ export const RestoreAccount = () => {
<BackButtonWithininContainer
margin={'2px 0 0 -36px'}
callback={() => {
setDisplayNameError('');
dispatch(setRecoveryPassword(''));
dispatch(setDisplayName(''));
dispatch(setProgress(0));
setRecoveryPasswordError('');
setProgress(0);
setDisplayNameError('');
}}
>
<Flex
@ -220,7 +231,7 @@ export const RestoreAccount = () => {
placeholder={window.i18n('enterRecoveryPhrase')}
value={recoveryPassword}
onValueChanged={(seed: string) => {
setRecoveryPassword(seed);
dispatch(setRecoveryPassword(seed));
setRecoveryPasswordError(
!seed ? window.i18n('recoveryPhraseEmpty') : undefined
);
@ -247,11 +258,13 @@ export const RestoreAccount = () => {
<SpacerLG />
<SessionInput
autoFocus={true}
disabledOnBlur={true}
type="text"
placeholder={window.i18n('enterDisplayName')}
value={displayName}
onValueChanged={(name: string) => {
sanitizeDisplayNameOrToast(name, setDisplayName, setDisplayNameError);
onValueChanged={(_name: string) => {
const name = sanitizeDisplayNameOrToast(_name, setDisplayNameError);
dispatch(setDisplayName(name));
}}
onEnterPressed={recoverAndEnterDisplayName}
error={displayNameError}

@ -5,6 +5,7 @@ import {
Onboarding,
setAccountCreationStep,
setAccountRestorationStep,
setDirection,
setOnboardingStep,
} from '../../../state/onboarding/ducks/registration';
import { SessionButton, SessionButtonColor } from '../../basic/SessionButton';
@ -19,6 +20,7 @@ export const Start = () => {
<SessionButton
buttonColor={SessionButtonColor.White}
onClick={() => {
dispatch(setDirection('forward'));
dispatch(setAccountCreationStep(AccountCreation.DisplayName));
dispatch(setOnboardingStep(Onboarding.CreateAccount));
}}
@ -28,6 +30,7 @@ export const Start = () => {
<SessionButton
buttonColor={SessionButtonColor.White}
onClick={() => {
dispatch(setDirection('forward'));
dispatch(setOnboardingStep(Onboarding.RestoreAccount));
dispatch(setAccountRestorationStep(AccountRestoration.RecoveryPassword));
}}

@ -2,17 +2,16 @@ import { sanitizeSessionUsername } from '../../../session/utils/String';
export function sanitizeDisplayNameOrToast(
displayName: string,
setDisplayName: (sanitized: string) => void,
setDisplayNameError: (error: string | undefined) => void
) {
try {
const sanitizedName = sanitizeSessionUsername(displayName);
const trimName = sanitizedName.trim();
setDisplayName(sanitizedName);
setDisplayNameError(!trimName ? window.i18n('displayNameEmpty') : undefined);
return sanitizedName;
} catch (e) {
setDisplayName(displayName);
setDisplayNameError(window.i18n('displayNameErrorDescriptionShorter'));
return displayName;
}
}

@ -31,32 +31,46 @@ export enum AccountRestoration {
Complete,
}
export type OnboardDirection = 'backward' | 'forward';
export type OnboardingState = {
generatedRecoveryPhrase: string;
recoveryPassword: string;
hexGeneratedPubKey: string;
displayName: string;
progress: number;
step: Onboarding;
accountCreationStep: AccountCreation;
accountRestorationStep: AccountRestoration;
direction: OnboardDirection;
};
const initialState: OnboardingState = {
generatedRecoveryPhrase: '',
recoveryPassword: '',
hexGeneratedPubKey: '',
displayName: '',
progress: 0,
step: Onboarding.Start,
accountRestorationStep: AccountRestoration.RecoveryPassword,
accountCreationStep: AccountCreation.DisplayName,
direction: 'forward',
};
export const registrationSlice = createSlice({
name: 'registration',
initialState,
reducers: {
setGeneratedRecoveryPhrase(state, action: PayloadAction<string>) {
return { ...state, generatedRecoveryPhrase: action.payload };
setRecoveryPassword(state, action: PayloadAction<string>) {
return { ...state, recoveryPassword: action.payload };
},
setHexGeneratedPubKey(state, action: PayloadAction<string>) {
return { ...state, hexGeneratedPubKey: action.payload };
},
setDisplayName(state, action: PayloadAction<string>) {
return { ...state, displayName: action.payload };
},
setProgress(state, action: PayloadAction<number>) {
return { ...state, progress: action.payload };
},
setOnboardingStep(state, action: PayloadAction<Onboarding>) {
return { ...state, step: action.payload };
},
@ -66,14 +80,20 @@ export const registrationSlice = createSlice({
setAccountRestorationStep(state, action: PayloadAction<AccountRestoration>) {
return { ...state, accountRestorationStep: action.payload };
},
setDirection(state, action: PayloadAction<OnboardDirection>) {
return { ...state, direction: action.payload };
},
},
});
export const {
setGeneratedRecoveryPhrase,
setRecoveryPassword,
setHexGeneratedPubKey,
setDisplayName,
setProgress,
setOnboardingStep,
setAccountCreationStep,
setAccountRestorationStep,
setDirection,
} = registrationSlice.actions;
export default registrationSlice.reducer;

@ -3,6 +3,7 @@ import { useSelector } from 'react-redux';
import {
AccountCreation,
AccountRestoration,
OnboardDirection,
Onboarding,
OnboardingState,
} from '../ducks/registration';
@ -13,9 +14,9 @@ const getRegistration = (state: OnboardingStoreState): OnboardingState => {
return state.registration;
};
const getGeneratedRecoveryPhrase = createSelector(
const getRecoveryPassword = createSelector(
getRegistration,
(state: OnboardingState): string => state.generatedRecoveryPhrase
(state: OnboardingState): string => state.recoveryPassword
);
const getHexGeneratedPubKey = createSelector(
@ -23,6 +24,16 @@ const getHexGeneratedPubKey = createSelector(
(state: OnboardingState): string => state.hexGeneratedPubKey
);
const getDisplayName = createSelector(
getRegistration,
(state: OnboardingState): string => state.displayName
);
const getProgress = createSelector(
getRegistration,
(state: OnboardingState): number => state.progress
);
const getOnboardingStep = createSelector(
getRegistration,
(state: OnboardingState): Onboarding => state.step
@ -37,17 +48,30 @@ const getAccountRestorationStep = createSelector(
getRegistration,
(state: OnboardingState): AccountRestoration => state.accountRestorationStep
);
const getDirection = createSelector(
getRegistration,
(state: OnboardingState): OnboardDirection => state.direction
);
// #endregion
// #region Hooks
export const useOnboardGeneratedRecoveryPhrase = () => {
return useSelector(getGeneratedRecoveryPhrase);
export const useRecoveryPassword = () => {
return useSelector(getRecoveryPassword);
};
export const useOnboardHexGeneratedPubKey = () => {
return useSelector(getHexGeneratedPubKey);
};
export const useDisplayName = () => {
return useSelector(getDisplayName);
};
export const useProgress = () => {
return useSelector(getProgress);
};
export const useOnboardStep = () => {
return useSelector(getOnboardingStep);
};
@ -59,4 +83,8 @@ export const useOnboardAccountCreationStep = () => {
export const useOnboardAccountRestorationStep = () => {
return useSelector(getAccountRestorationStep);
};
export const useOnboardDirection = () => {
return useSelector(getDirection);
};
// #endregion

Loading…
Cancel
Save