From f603cd8670410e221aad5ccca6e95e9173ca5c06 Mon Sep 17 00:00:00 2001 From: Usame Algan Date: Tue, 10 Oct 2023 12:28:12 +0200 Subject: [PATCH 1/7] feat: Implement account center redesign --- public/images/common/lock.svg | 3 ++ .../common/ConnectWallet/AccountCenter.tsx | 48 ++++++++----------- .../common/ConnectWallet/MPCLogin.tsx | 11 ++++- .../common/ConnectWallet/WalletDetails.tsx | 29 +++++++---- .../common/ConnectWallet/styles.module.css | 25 +++++++++- .../common/SocialLoginInfo/index.tsx | 42 ++++++++++++++++ .../common/SocialLoginInfo/styles.module.css | 23 +++++++++ .../welcome/WelcomeLogin/WalletLogin.tsx | 2 +- 8 files changed, 142 insertions(+), 41 deletions(-) create mode 100644 public/images/common/lock.svg create mode 100644 src/components/common/SocialLoginInfo/index.tsx create mode 100644 src/components/common/SocialLoginInfo/styles.module.css diff --git a/public/images/common/lock.svg b/public/images/common/lock.svg new file mode 100644 index 0000000000..9535a642e0 --- /dev/null +++ b/public/images/common/lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/common/ConnectWallet/AccountCenter.tsx b/src/components/common/ConnectWallet/AccountCenter.tsx index 03a0aab974..a4208e8af1 100644 --- a/src/components/common/ConnectWallet/AccountCenter.tsx +++ b/src/components/common/ConnectWallet/AccountCenter.tsx @@ -1,6 +1,6 @@ import type { MouseEvent } from 'react' import { useState } from 'react' -import { Box, Button, ButtonBase, Paper, Popover, Typography } from '@mui/material' +import { Box, Button, ButtonBase, Paper, Popover } from '@mui/material' import css from '@/components/common/ConnectWallet/styles.module.css' import EthHashInfo from '@/components/common/EthHashInfo' import ExpandLessIcon from '@mui/icons-material/ExpandLess' @@ -8,11 +8,13 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import useOnboard, { switchWallet } from '@/hooks/wallets/useOnboard' import { useAppSelector } from '@/store' import { selectChainById } from '@/store/chainsSlice' -import Identicon from '@/components/common/Identicon' import ChainSwitcher from '../ChainSwitcher' import useAddressBook from '@/hooks/useAddressBook' import { type ConnectedWallet } from '@/hooks/wallets/useOnboard' -import WalletInfo, { UNKNOWN_CHAIN_NAME } from '../WalletInfo' +import WalletInfo from '../WalletInfo' +import ChainIndicator from '@/components/common/ChainIndicator' +import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/module' +import SocialLoginInfo from '@/components/common/SocialLoginInfo' const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => { const [anchorEl, setAnchorEl] = useState(null) @@ -77,31 +79,21 @@ const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => { sx={{ marginTop: 1 }} > - - - - {addressBook[wallet.address] || wallet.ens} - - - - - - - - - Wallet - {wallet.label} - - - Connected network - {chainInfo?.chainName || UNKNOWN_CHAIN_NAME} + + + + {wallet.label === ONBOARD_MPC_MODULE_LABEL ? ( + + ) : ( + + )} diff --git a/src/components/common/ConnectWallet/MPCLogin.tsx b/src/components/common/ConnectWallet/MPCLogin.tsx index e55a32647b..3c64d87e76 100644 --- a/src/components/common/ConnectWallet/MPCLogin.tsx +++ b/src/components/common/ConnectWallet/MPCLogin.tsx @@ -34,7 +34,7 @@ const MPCLogin = ({ onLogin }: { onLogin?: () => void }) => { <> ) : ( - + + + or + + + ) diff --git a/src/components/common/ConnectWallet/styles.module.css b/src/components/common/ConnectWallet/styles.module.css index aa127889c6..0736c50027 100644 --- a/src/components/common/ConnectWallet/styles.module.css +++ b/src/components/common/ConnectWallet/styles.module.css @@ -12,11 +12,11 @@ .popoverContainer { padding: var(--space-2); - width: 250px; + width: 300px; display: flex; flex-direction: column; align-items: center; - gap: var(--space-2); + gap: var(--space-1); border: 1px solid var(--color-border-light); } @@ -66,6 +66,27 @@ gap: var(--space-2); } +.loginButton { + min-height: 42px; +} + +.accountContainer { + width: 100%; + margin-bottom: var(--space-1); +} + +.accountContainer > span { + border-radius: 8px 8px 0 0; +} + +.addressContainer { + border-radius: 0 0 8px 8px; + padding: 12px; + border: 1px solid var(--color-border-light); + border-top: 0; + font-size: 14px; +} + @media (max-width: 599.95px) { .buttonContainer { transform: scale(0.8); diff --git a/src/components/common/SocialLoginInfo/index.tsx b/src/components/common/SocialLoginInfo/index.tsx new file mode 100644 index 0000000000..6925fe2da0 --- /dev/null +++ b/src/components/common/SocialLoginInfo/index.tsx @@ -0,0 +1,42 @@ +import { Box, Typography } from '@mui/material' +import css from './styles.module.css' +import { useContext } from 'react' +import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk' +import { type ConnectedWallet } from '@/services/onboard' +import { MpcWalletContext } from '@/components/common/ConnectWallet/MPCWalletProvider' +import CopyAddressButton from '@/components/common/CopyAddressButton' +import ExplorerButton from '@/components/common/ExplorerButton' +import { getBlockExplorerLink } from '@/utils/chains' +import { useAppSelector } from '@/store' +import { selectSettings } from '@/store/settingsSlice' + +const SocialLoginInfo = ({ wallet, chainInfo }: { wallet: ConnectedWallet; chainInfo?: ChainInfo }) => { + const { userInfo } = useContext(MpcWalletContext) + const prefix = chainInfo?.shortName + const link = chainInfo ? getBlockExplorerLink(chainInfo, wallet.address) : undefined + const settings = useAppSelector(selectSettings) + + if (!userInfo) return <> + + return ( + + Profile Image +
+ + {userInfo.name} + + + {userInfo.email} + +
+
+ + + + +
+
+ ) +} + +export default SocialLoginInfo diff --git a/src/components/common/SocialLoginInfo/styles.module.css b/src/components/common/SocialLoginInfo/styles.module.css new file mode 100644 index 0000000000..6b694addb6 --- /dev/null +++ b/src/components/common/SocialLoginInfo/styles.module.css @@ -0,0 +1,23 @@ +.profileImg { + border-radius: var(--space-2); + width: 32px; + height: 32px; +} + +.profileData { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 2px; +} + +.text { + font-size: 12px; + line-height: 14px; +} + +.actionButtons { + display: flex; + justify-self: flex-end; + margin-left: auto; +} diff --git a/src/components/welcome/WelcomeLogin/WalletLogin.tsx b/src/components/welcome/WelcomeLogin/WalletLogin.tsx index 758a3b23c7..b40826d9ee 100644 --- a/src/components/welcome/WelcomeLogin/WalletLogin.tsx +++ b/src/components/welcome/WelcomeLogin/WalletLogin.tsx @@ -47,7 +47,7 @@ const WalletLogin = ({ onLogin }: { onLogin?: () => void }) => { } return ( - ) From 34921dd114ca700d0595d5fd536cfd125644634b Mon Sep 17 00:00:00 2001 From: Usame Algan Date: Tue, 10 Oct 2023 12:41:39 +0200 Subject: [PATCH 2/7] fix: Continue as button spacing --- src/components/common/ConnectWallet/MPCLogin.tsx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/components/common/ConnectWallet/MPCLogin.tsx b/src/components/common/ConnectWallet/MPCLogin.tsx index 3c64d87e76..2f0dfc3653 100644 --- a/src/components/common/ConnectWallet/MPCLogin.tsx +++ b/src/components/common/ConnectWallet/MPCLogin.tsx @@ -34,20 +34,13 @@ const MPCLogin = ({ onLogin }: { onLogin?: () => void }) => { <> From 499a656f3962c9fd3d9538158e34f778e60b0259 Mon Sep 17 00:00:00 2001 From: Usame Algan Date: Tue, 10 Oct 2023 13:30:20 +0200 Subject: [PATCH 3/7] fix: Failing e2e tests --- cypress/e2e/pages/create_wallet.pages.js | 2 +- cypress/e2e/pages/load_safe.pages.js | 4 ++-- cypress/e2e/smoke/import_export_data.cy.js | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cypress/e2e/pages/create_wallet.pages.js b/cypress/e2e/pages/create_wallet.pages.js index 57ad95b318..5f1b3eefb3 100644 --- a/cypress/e2e/pages/create_wallet.pages.js +++ b/cypress/e2e/pages/create_wallet.pages.js @@ -1,6 +1,6 @@ import * as constants from '../../support/constants' -const newAccountBtnStr = 'Create new Account' +const newAccountBtnStr = 'Continue with E2E Wallet' const nameInput = 'input[name="name"]' const selectNetworkBtn = '[data-cy="create-safe-select-network"]' diff --git a/cypress/e2e/pages/load_safe.pages.js b/cypress/e2e/pages/load_safe.pages.js index 3d36669e48..d1d02d9edb 100644 --- a/cypress/e2e/pages/load_safe.pages.js +++ b/cypress/e2e/pages/load_safe.pages.js @@ -1,6 +1,6 @@ import * as constants from '../../support/constants' -const addExistingAccountBtnStr = 'Add existing Account' +const addExistingAccountBtnStr = 'Add existing one' const contactStr = 'Name, address & network' const invalidAddressFormatErrorMsg = 'Invalid address format' @@ -16,7 +16,7 @@ const ownersConfirmationsStr = 'Owners and confirmations' const transactionStr = 'Transactions' export function openLoadSafeForm() { - cy.contains('button', addExistingAccountBtnStr).click() + cy.contains('a', addExistingAccountBtnStr).click() cy.contains(contactStr) } diff --git a/cypress/e2e/smoke/import_export_data.cy.js b/cypress/e2e/smoke/import_export_data.cy.js index 55ea6fedae..f6e5f1623d 100644 --- a/cypress/e2e/smoke/import_export_data.cy.js +++ b/cypress/e2e/smoke/import_export_data.cy.js @@ -3,7 +3,8 @@ import * as file from '../pages/import_export.pages' import * as main from '../pages/main.page' import * as constants from '../../support/constants' -describe('Import Export Data', () => { +// TODO: This is currently removed from the welcome page +describe.skip('Import Export Data', () => { before(() => { cy.clearLocalStorage() cy.visit(constants.welcomeUrl) From 13036f247e792ec0e337a1bca590f6417d1ea47d Mon Sep 17 00:00:00 2001 From: Usame Algan Date: Tue, 10 Oct 2023 15:36:20 +0200 Subject: [PATCH 4/7] refactor: useConnectWallet hook, explicit onLogin handling --- .../common/ConnectWallet/MPCLogin.tsx | 28 ++++++++++--------- .../ConnectWallet/MPCWalletProvider.tsx | 28 ++++--------------- .../common/ConnectWallet/WalletDetails.tsx | 26 +++-------------- .../common/ConnectWallet/useConnectWallet.ts | 14 ++++------ .../welcome/WelcomeLogin/WalletLogin.tsx | 14 ++-------- src/components/welcome/styles.module.css | 1 + src/hooks/wallets/mpc/useMPCWallet.ts | 10 +++++-- 7 files changed, 40 insertions(+), 81 deletions(-) diff --git a/src/components/common/ConnectWallet/MPCLogin.tsx b/src/components/common/ConnectWallet/MPCLogin.tsx index 2f0dfc3653..03ead96b6e 100644 --- a/src/components/common/ConnectWallet/MPCLogin.tsx +++ b/src/components/common/ConnectWallet/MPCLogin.tsx @@ -1,32 +1,34 @@ import { MPCWalletState } from '@/hooks/wallets/mpc/useMPCWallet' import { Box, Button, SvgIcon, Typography } from '@mui/material' -import { useContext, useEffect, useState } from 'react' +import { useContext } from 'react' import { MpcWalletContext } from './MPCWalletProvider' import { PasswordRecovery } from './PasswordRecovery' import GoogleLogo from '@/public/images/welcome/logo-google.svg' import css from './styles.module.css' import useWallet from '@/hooks/wallets/useWallet' -import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/module' const MPCLogin = ({ onLogin }: { onLogin?: () => void }) => { - const { loginPending, triggerLogin, userInfo, walletState, recoverFactorWithPassword } = useContext(MpcWalletContext) + const { triggerLogin, userInfo, walletState, recoverFactorWithPassword } = useContext(MpcWalletContext) const wallet = useWallet() - - const [loginTriggered, setLoginTriggered] = useState(false) + const loginPending = walletState === MPCWalletState.AUTHENTICATING const login = async () => { - setLoginTriggered(true) - await triggerLogin() + const success = await triggerLogin() + + if (success) { + onLogin?.() + } } - // If login was triggered through the Button we immediately continue if logged in - useEffect(() => { - if (loginTriggered && wallet && wallet.label === ONBOARD_MPC_MODULE_LABEL && onLogin) { - onLogin() + const recoverPassword = async (password: string, storeDeviceFactor: boolean) => { + const success = await recoverFactorWithPassword(password, storeDeviceFactor) + + if (success) { + onLogin?.() } - }, [loginTriggered, onLogin, wallet]) + } return ( <> @@ -73,7 +75,7 @@ const MPCLogin = ({ onLogin }: { onLogin?: () => void }) => { )} {walletState === MPCWalletState.MANUAL_RECOVERY && ( - + )} ) diff --git a/src/components/common/ConnectWallet/MPCWalletProvider.tsx b/src/components/common/ConnectWallet/MPCWalletProvider.tsx index 4f91450e26..a8f0f6fb83 100644 --- a/src/components/common/ConnectWallet/MPCWalletProvider.tsx +++ b/src/components/common/ConnectWallet/MPCWalletProvider.tsx @@ -1,35 +1,17 @@ -import { useMPCWallet, MPCWalletState } from '@/hooks/wallets/mpc/useMPCWallet' -import { type UserInfo } from '@web3auth/mpc-core-kit' +import { useMPCWallet, MPCWalletState, type MPCWalletHook } from '@/hooks/wallets/mpc/useMPCWallet' import { createContext, type ReactElement } from 'react' -type MPCWalletContext = { - loginPending: boolean - triggerLogin: () => Promise - resetAccount: () => Promise - upsertPasswordBackup: (password: string) => Promise - recoverFactorWithPassword: (password: string, storeDeviceFactor: boolean) => Promise - walletState: MPCWalletState - userInfo: UserInfo | undefined -} - -export const MpcWalletContext = createContext({ - loginPending: false, +export const MpcWalletContext = createContext({ walletState: MPCWalletState.NOT_INITIALIZED, - triggerLogin: () => Promise.resolve(), + triggerLogin: () => Promise.resolve(false), resetAccount: () => Promise.resolve(), upsertPasswordBackup: () => Promise.resolve(), - recoverFactorWithPassword: () => Promise.resolve(), + recoverFactorWithPassword: () => Promise.resolve(false), userInfo: undefined, }) export const MpcWalletProvider = ({ children }: { children: ReactElement }) => { const mpcValue = useMPCWallet() - return ( - - {children} - - ) + return {children} } diff --git a/src/components/common/ConnectWallet/WalletDetails.tsx b/src/components/common/ConnectWallet/WalletDetails.tsx index ace0817980..29c09582a4 100644 --- a/src/components/common/ConnectWallet/WalletDetails.tsx +++ b/src/components/common/ConnectWallet/WalletDetails.tsx @@ -1,34 +1,16 @@ -import { Button, Divider, Typography } from '@mui/material' +import { Divider, Typography } from '@mui/material' import type { ReactElement } from 'react' import LockIcon from '@/public/images/common/lock.svg' -import useConnectWallet from '@/components/common/ConnectWallet/useConnectWallet' import MPCLogin from './MPCLogin' -import css from './styles.module.css' - -const WalletDetails = ({ onConnect }: { onConnect?: () => void }): ReactElement => { - const connectWallet = useConnectWallet() - - const handleConnect = () => { - onConnect?.() - connectWallet() - } +import WalletLogin from '@/components/welcome/WelcomeLogin/WalletLogin' +const WalletDetails = ({ onConnect }: { onConnect: () => void }): ReactElement => { return ( <> - + diff --git a/src/components/common/ConnectWallet/useConnectWallet.ts b/src/components/common/ConnectWallet/useConnectWallet.ts index 9dc10e7930..b3f832229e 100644 --- a/src/components/common/ConnectWallet/useConnectWallet.ts +++ b/src/components/common/ConnectWallet/useConnectWallet.ts @@ -1,19 +1,17 @@ -import { useMemo } from 'react' +import { useCallback } from 'react' import useOnboard, { connectWallet } from '@/hooks/wallets/useOnboard' import { OVERVIEW_EVENTS, trackEvent } from '@/services/analytics' -const useConnectWallet = (): (() => void) => { +const useConnectWallet = () => { const onboard = useOnboard() - return useMemo(() => { + return useCallback(() => { if (!onboard) { - return () => {} + return Promise.resolve(undefined) } - return () => { - trackEvent(OVERVIEW_EVENTS.OPEN_ONBOARD) - connectWallet(onboard) - } + trackEvent(OVERVIEW_EVENTS.OPEN_ONBOARD) + return connectWallet(onboard) }, [onboard]) } diff --git a/src/components/welcome/WelcomeLogin/WalletLogin.tsx b/src/components/welcome/WelcomeLogin/WalletLogin.tsx index b40826d9ee..451bf5d502 100644 --- a/src/components/welcome/WelcomeLogin/WalletLogin.tsx +++ b/src/components/welcome/WelcomeLogin/WalletLogin.tsx @@ -3,26 +3,16 @@ import useWallet from '@/hooks/wallets/useWallet' import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/module' import { Box, Button, Typography } from '@mui/material' import { EthHashInfo } from '@safe-global/safe-react-components' -import { useState, useEffect } from 'react' -const WalletLogin = ({ onLogin }: { onLogin?: () => void }) => { +const WalletLogin = ({ onLogin }: { onLogin: () => void }) => { const wallet = useWallet() const connectWallet = useConnectWallet() - const [loginTriggered, setLoginTriggered] = useState(false) - const login = async () => { - setLoginTriggered(true) await connectWallet() + onLogin() } - // If login was triggered through the Button we immediately continue if logged in - useEffect(() => { - if (loginTriggered && wallet && onLogin) { - onLogin() - } - }, [loginTriggered, onLogin, wallet]) - if (wallet !== null && wallet?.label !== ONBOARD_MPC_MODULE_LABEL) { return (