diff --git a/src/components/common/SocialSigner/PasswordRecovery.tsx b/src/components/common/SocialSigner/PasswordRecovery.tsx index accd3d8c97..14f61bceae 100644 --- a/src/components/common/SocialSigner/PasswordRecovery.tsx +++ b/src/components/common/SocialSigner/PasswordRecovery.tsx @@ -1,15 +1,5 @@ import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet' -import { - Typography, - FormControlLabel, - Checkbox, - Button, - Box, - Divider, - Grid, - LinearProgress, - FormControl, -} from '@mui/material' +import { Typography, FormControlLabel, Checkbox, Button, Box, Divider, FormControl, Avatar } from '@mui/material' import { useState } from 'react' import Track from '@/components/common/Track' import { FormProvider, useForm } from 'react-hook-form' @@ -60,60 +50,51 @@ export const PasswordRecovery = ({ return (
- - - - Verify your account + + + + + {2} + + + Enter recovery password + + + + Please enter your recovery password. - - + + + + - - - Enter security password - - - This browser is not registered with your Account yet. Please enter your recovery password to restore - access to this Account. - - - - - - - - setStoreDeviceFactor((prev) => !prev)} /> - } - label="Do not ask again on this device" - /> - {error && {error}} - + + setStoreDeviceFactor((prev) => !prev)} />} + label="Do not ask again on this device" + /> + {error && {error}} + - - - - - - - - - - + + + + + + + +
) diff --git a/src/components/common/SocialSigner/SmsRecovery.tsx b/src/components/common/SocialSigner/SmsRecovery.tsx index ff1e6b60fe..2641f2e3c0 100644 --- a/src/components/common/SocialSigner/SmsRecovery.tsx +++ b/src/components/common/SocialSigner/SmsRecovery.tsx @@ -1,5 +1,5 @@ import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet' -import { Typography, FormControlLabel, Checkbox, Button, Box, Divider, Grid, LinearProgress } from '@mui/material' +import { Typography, FormControlLabel, Checkbox, Button, Box, Divider, Avatar } from '@mui/material' import { useCallback, useEffect, useState } from 'react' import Track from '@/components/common/Track' import { FormProvider, useForm } from 'react-hook-form' @@ -8,6 +8,7 @@ import ErrorMessage from '@/components/tx/ErrorMessage' import css from './styles.module.css' import CodeInput from '../CodeInput' import CooldownButton from '../CooldownButton' +import { obfuscateNumber } from '@/utils/phoneNumber' type SmsFormData = { code: string @@ -18,11 +19,13 @@ export const SmsRecovery = ({ sendSmsCode, onSuccess, onBack, + phoneNumber, }: { recoverFactorWithSms: (code: string, storeDeviceFactor: boolean) => Promise sendSmsCode: () => Promise onSuccess?: (() => void) | undefined onBack: () => void + phoneNumber: string | undefined }) => { const [storeDeviceFactor, setStoreDeviceFactor] = useState(false) @@ -65,56 +68,49 @@ export const SmsRecovery = ({ return (
- - - - Verify your account + + + + + {2} + + + Enter recovery code + + + + Please enter the recovery code sent to your phone. - - - - - Enter recovery code - - - This browser is not registered with your Account yet. Please enter the recovery code sent to your - phone to recover your social signer. - - - - - + + + + {obfuscateNumber(phoneNumber)} - - Resend code - + - setStoreDeviceFactor((prev) => !prev)} /> - } - label="Do not ask again on this device" - /> - {error && {error}} - + + Resend code + - - - - - - - - - - + setStoreDeviceFactor((prev) => !prev)} />} + label="Do not ask again on this device" + /> + {error && {error}} + + + + + + + + + +
) diff --git a/src/services/mpc/SocialRecoveryModal.tsx b/src/components/common/SocialSigner/SocialRecoveryModal.tsx similarity index 53% rename from src/services/mpc/SocialRecoveryModal.tsx rename to src/components/common/SocialSigner/SocialRecoveryModal.tsx index f8cca509e8..f922219c5d 100644 --- a/src/services/mpc/SocialRecoveryModal.tsx +++ b/src/components/common/SocialSigner/SocialRecoveryModal.tsx @@ -4,8 +4,9 @@ import TxModalDialog from '@/components/common/TxModalDialog' import { IS_PRODUCTION } from '@/config/constants' import useSocialWallet, { useMfaStore } from '@/hooks/wallets/mpc/useSocialWallet' import ExternalStore from '@/services/ExternalStore' -import { Box, Button, Divider, Grid, Typography } from '@mui/material' -import { useCallback, useState } from 'react' +import { Avatar, Box, Button, Divider, Grid, LinearProgress, Typography } from '@mui/material' +import { type ReactNode, useCallback, useState } from 'react' +import css from './styles.module.css' const { useStore: useCloseCallback, setStore: setCloseCallback } = new ExternalStore<() => void>() @@ -22,6 +23,35 @@ export const close = () => { setCloseCallback(undefined) } +const RecoveryFlow = ({ + children, + progress, + isRecovering, +}: { + children: ReactNode + progress: number + isRecovering: boolean +}) => { + return ( + + + + Verify your account + + + + {children} + + + + ) +} + const RecoveryPicker = ({ smsEnabled, passwordEnabled, @@ -34,53 +64,49 @@ const RecoveryPicker = ({ deleteAccount?: () => void }) => { return ( - - - - Verify your account - - - - + + + + + {2} + + + Choose your recovery method - - This browser is not registered with your Account yet. Please proceed with one of your setup recovery - methods. - - - - - - - - - {!IS_PRODUCTION && ( - <> - - - )} - - + + How would you like to recovery your social login signer? + + + + + + + + + {!IS_PRODUCTION && ( + + )} + + ) } @@ -88,6 +114,7 @@ const SocialRecoveryModal = () => { const socialWalletService = useSocialWallet() const mfaSetup = useMfaStore() const [recoveryMethod, setRecoveryMethod] = useState() + const [isRecovering, setIsRecovering] = useState(false) const closeCallback = useCloseCallback() const open = !!closeCallback @@ -97,7 +124,12 @@ const SocialRecoveryModal = () => { const recoverPassword = async (password: string, storeDeviceFactor: boolean) => { if (!socialWalletService) return - await socialWalletService.recoverAccountWithPassword(password, storeDeviceFactor) + setIsRecovering(true) + try { + await socialWalletService.recoverAccountWithPassword(password, storeDeviceFactor) + } finally { + setIsRecovering(false) + } } const recoverSms = async (code: string, storeDeviceFactor: boolean) => { @@ -107,7 +139,12 @@ const SocialRecoveryModal = () => { if (!number) { throw new Error('No recovery mobile number is set') } - await socialWalletService.recoverAccountWithSms(number, code, storeDeviceFactor) + setIsRecovering(true) + try { + await socialWalletService.recoverAccountWithSms(number, code, storeDeviceFactor) + } finally { + setIsRecovering(false) + } } const deleteAccount = () => { @@ -137,16 +174,17 @@ const SocialRecoveryModal = () => { setRecoveryMethod(undefined) } - const RecoveryComponentMap: Record React.ReactElement> = { - [RecoveryMethod.PASSWORD]: () => ( + const RecoveryComponentMap: Record = { + [RecoveryMethod.PASSWORD]: ( ), - [RecoveryMethod.SMS]: () => ( + [RecoveryMethod.SMS]: ( ), } @@ -155,16 +193,18 @@ const SocialRecoveryModal = () => { return ( - {recoveryMethod !== undefined ? ( - RecoveryComponentMap[recoveryMethod]() - ) : ( - - )} + + {recoveryMethod !== undefined ? ( + RecoveryComponentMap[recoveryMethod] + ) : ( + + )} + ) } diff --git a/src/components/common/SocialSigner/__tests__/SocialSignerLogin.test.tsx b/src/components/common/SocialSigner/__tests__/SocialSignerLogin.test.tsx index c09c60184c..d7bea3cefa 100644 --- a/src/components/common/SocialSigner/__tests__/SocialSignerLogin.test.tsx +++ b/src/components/common/SocialSigner/__tests__/SocialSignerLogin.test.tsx @@ -9,7 +9,7 @@ import { fireEvent } from '@testing-library/react' import { type ISocialWalletService } from '@/services/mpc/interfaces' import { connectedWalletBuilder } from '@/tests/builders/wallet' import { chainBuilder } from '@/tests/builders/chains' -import PasswordRecoveryModal from '@/services/mpc/SocialRecoveryModal' +import PasswordRecoveryModal from '@/components/common/SocialSigner/SocialRecoveryModal' import { MultiFactorType, setMfaStore } from '@/hooks/wallets/mpc/useSocialWallet' const typeInFocusedElement = (text: string) => { diff --git a/src/components/common/SocialSigner/index.tsx b/src/components/common/SocialSigner/index.tsx index f833d0f787..f22ce01096 100644 --- a/src/components/common/SocialSigner/index.tsx +++ b/src/components/common/SocialSigner/index.tsx @@ -19,7 +19,7 @@ import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk' import madProps from '@/utils/mad-props' import { asError } from '@/services/exceptions/utils' import ErrorMessage from '@/components/tx/ErrorMessage' -import { open } from '@/services/mpc/SocialRecoveryModal' +import { open } from '@/components/common/SocialSigner/SocialRecoveryModal' export const _getSupportedChains = (chains: ChainInfo[]) => { return chains diff --git a/src/components/common/SocialSigner/styles.module.css b/src/components/common/SocialSigner/styles.module.css index a36db4bcf2..cc1fb999af 100644 --- a/src/components/common/SocialSigner/styles.module.css +++ b/src/components/common/SocialSigner/styles.module.css @@ -42,3 +42,17 @@ width: 100%; margin: 0; } + +.dot { + width: 20px; + height: 20px; + background-color: var(--color-primary-main); +} + +.phoneNumberDisplay { + font-size: 14px; + padding: var(--space-2); + background-color: var(--color-background-main); + border-radius: 6px; + margin-bottom: var(--space-1); +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 56b5c17bbc..ee1889b0ac 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,5 +1,5 @@ import useRehydrateSocialWallet from '@/hooks/wallets/mpc/useRehydrateSocialWallet' -import PasswordRecoveryModal from '@/services/mpc/SocialRecoveryModal' +import PasswordRecoveryModal from '@/components/common/SocialSigner/SocialRecoveryModal' import Sentry from '@/services/sentry' // needs to be imported first import type { ReactNode } from 'react' import { type ReactElement } from 'react' diff --git a/src/services/mpc/SocialLoginModule.ts b/src/services/mpc/SocialLoginModule.ts index 6ca1ce7464..71ceb82c8d 100644 --- a/src/services/mpc/SocialLoginModule.ts +++ b/src/services/mpc/SocialLoginModule.ts @@ -48,7 +48,7 @@ function MpcModule(chain: ChainInfo): WalletInit { const { _getMPCCoreKitInstance } = await import('@/hooks/wallets/mpc/useMPC') const { getSocialWalletService } = await import('@/hooks/wallets/mpc/useSocialWallet') const { COREKIT_STATUS } = await import('@web3auth/mpc-core-kit') - const { open } = await import('./SocialRecoveryModal') + const { open } = await import('../../components/common/SocialSigner/SocialRecoveryModal') const getMPCProvider = () => _getMPCCoreKitInstance()?.provider