diff --git a/src/components/common/BuyCryptoButton/index.tsx b/src/components/common/BuyCryptoButton/index.tsx index d85611e7ed..4719d9b27c 100644 --- a/src/components/common/BuyCryptoButton/index.tsx +++ b/src/components/common/BuyCryptoButton/index.tsx @@ -50,7 +50,47 @@ const BuyCryptoOption = ({ name, children }: { name: string; children: ReactNode ) } -const _BuyCryptoButton = ({ href, pagePath }: { href?: LinkProps['href']; pagePath: string }) => { +const _BuyCryptoOptions = ({ rampLink }: { rampLink?: LinkProps['href'] }) => { + const { safeAddress } = useSafeInfo() + + const moonPayLink = `${MOONPAY_URL}?defaultCurrencyCode=eth&walletAddress=${safeAddress}` + const mercuryoLink = MERCURYO_URL + + return ( + <> + {rampLink && ( + + + + + + + + +
Safe integrated app
+
+ )} + + + + + + + + + + + + + + + + + + ) +} + +const _BuyCryptoButton = ({ pagePath }: { pagePath: string }) => { const [open, setOpen] = useState(false) const { safeAddress } = useSafeInfo() @@ -58,9 +98,6 @@ const _BuyCryptoButton = ({ href, pagePath }: { href?: LinkProps['href']; pagePa setOpen((prev) => !prev) } - const moonPayLink = `${MOONPAY_URL}?defaultCurrencyCode=eth&walletAddress=${safeAddress}` - const mercuryoLink = MERCURYO_URL - return ( <> @@ -78,34 +115,8 @@ const _BuyCryptoButton = ({ href, pagePath }: { href?: LinkProps['href']; pagePa Choose one of the available options - {href && ( - - - - - - - - -
Safe integrated app
-
- )} - - - - - - - - - - - - - - - + @@ -123,8 +134,11 @@ const _BuyCryptoButton = ({ href, pagePath }: { href?: LinkProps['href']; pagePa } const BuyCryptoButton = madProps(_BuyCryptoButton, { - href: useBuyCryptoHref, pagePath: usePathname, }) +export const BuyCryptoOptions = madProps(_BuyCryptoOptions, { + rampLink: useBuyCryptoHref, +}) + export default BuyCryptoButton diff --git a/src/components/dashboard/FirstSteps/index.tsx b/src/components/dashboard/FirstSteps/index.tsx index e9b1c932e2..1263f5c6cc 100644 --- a/src/components/dashboard/FirstSteps/index.tsx +++ b/src/components/dashboard/FirstSteps/index.tsx @@ -1,19 +1,27 @@ +import { BuyCryptoOptions } from '@/components/common/BuyCryptoButton' +import EthHashInfo from '@/components/common/EthHashInfo' +import ModalDialog from '@/components/common/ModalDialog' +import useDismissFirstSteps from '@/components/dashboard/FirstSteps/useDismissFirstSteps' import { TxModalContext } from '@/components/tx-flow' -import { ActivateAccountFlow } from '@/features/counterfactual/ActivateAccount' +import { NewTxFlow } from '@/components/tx-flow/flows' import useBalances from '@/hooks/useBalances' +import { useCurrentChain } from '@/hooks/useChains' import useSafeInfo from '@/hooks/useSafeInfo' import { useAppSelector } from '@/store' import { selectOutgoingTransactions } from '@/store/txHistorySlice' -import React, { useContext, useMemo } from 'react' +import classnames from 'classnames' +import { type ReactNode, useContext, useState } from 'react' import { Card, WidgetBody, WidgetContainer } from '@/components/dashboard/styled' -import { Button, CircularProgress, Grid, Link, Typography } from '@mui/material' +import { Box, Button, CircularProgress, Grid, IconButton, Typography } from '@mui/material' import CircleOutlinedIcon from '@mui/icons-material/CircleOutlined' import CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded' +import CheckCircleOutlineRoundedIcon from '@mui/icons-material/CheckCircleOutlineRounded' +import CloseRoundedIcon from '@mui/icons-material/CloseRounded' import css from './styles.module.css' -const calculateProgress = (items: StatusProgressItems) => { +const calculateProgress = (items: boolean[]) => { const totalNumberOfItems = items.length - const completedItems = items.filter((item) => item.completed) + const completedItems = items.filter((item) => item) return Math.round((completedItems.length / totalNumberOfItems) * 100) } @@ -22,11 +30,13 @@ const StatusCard = ({ title, content, completed, + children, }: { badge: string title: string content: string completed: boolean + children: ReactNode }) => { return ( @@ -44,60 +54,120 @@ const StatusCard = ({ {title} {content} + {children} ) } -type StatusProgressItem = { - title: string - content: string - completed?: boolean +const AddFundsWidget = ({ completed }: { completed: boolean }) => { + const { safeAddress } = useSafeInfo() + const [open, setOpen] = useState(false) + + const chain = useCurrentChain() + const title = 'Add native assets' + const content = `Receive ${chain?.nativeCurrency.name} to start interacting with your account.` + + const toggleDialog = () => { + setOpen((prev) => !prev) + } + + return ( + + {!completed && ( + <> + + + + + + + Add funds directly from your bank account or copy your address to send tokens from a different account. + + + + Account address + + + + + + + Buy crypto with fiat: + + + + + )} + + ) } -type StatusProgressItems = Array +const FirstTransactionWidget = ({ completed }: { completed: boolean }) => { + const { setTxFlow } = useContext(TxModalContext) + + const title = 'Create your first transaction' + const content = 'Simply send funds, add a new signer or swap tokens through a safe app.' + + const handleNewTx = () => { + setTxFlow(, undefined, false) + } + + return ( + + {!completed && ( + + )} + + ) +} -const FirstStepsContent: StatusProgressItems = [ - { - title: 'Add funds', - content: 'Receive assets to start interacting with your account.', - }, - { - title: 'Create your first transaction', - content: 'Do a simple transfer or use a safe app to create your first transaction.', - }, -] +const AccountReadyWidget = ({ completed }: { completed: boolean }) => { + return ( + +
+ +
+ + Safe Account is ready! + + Continue to improve your account security and unlock more features +
+ ) +} const FirstSteps = () => { const { balances } = useBalances() const { safe } = useSafeInfo() const outgoingTransactions = useAppSelector(selectOutgoingTransactions) - const { setTxFlow } = useContext(TxModalContext) + const { dismissFirstSteps, setDismissFirstSteps } = useDismissFirstSteps() const hasNonZeroBalance = balances && (balances.items.length > 1 || BigInt(balances.items[0]?.balance || 0) > 0) const hasOutgoingTransactions = !!outgoingTransactions && outgoingTransactions.length > 0 + const completedItems = [hasNonZeroBalance, hasOutgoingTransactions] - const items = useMemo( - () => [ - { ...FirstStepsContent[0], completed: hasNonZeroBalance }, - { ...FirstStepsContent[1], completed: hasOutgoingTransactions }, - ], - [hasNonZeroBalance, hasOutgoingTransactions], - ) + const progress = calculateProgress(completedItems) + const stepsCompleted = completedItems.filter((item) => item).length - const activateAccount = () => { - setTxFlow() + const dismissWidget = () => { + setDismissFirstSteps(true) } - const progress = calculateProgress(items) - const stepsCompleted = items.filter((item) => item.completed).length - - if (safe.deployed) return null + if (dismissFirstSteps) return null return ( - - + + { @@ -129,37 +199,30 @@ const FirstSteps = () => { - {stepsCompleted} of {items.length} steps completed. + {stepsCompleted} of {completedItems.length} steps completed. {' '} - {progress === 100 ? ( - <> - Congratulations! You finished the first steps. Hide this section - - ) : ( - 'Finish the next steps to start using all Safe Account features:' - )} + Finish the next steps to start using all Safe Account features: + {safe.deployed && ( + + + + + + )} - {items.map((item) => { - return ( - - - - ) - })} + + + - - - Skip first steps - - Pay a network fee to immediately access all Safe Account features. - - + + + + + diff --git a/src/components/dashboard/FirstSteps/styles.module.css b/src/components/dashboard/FirstSteps/styles.module.css index 767ecf1068..9ef4a86ab6 100644 --- a/src/components/dashboard/FirstSteps/styles.module.css +++ b/src/components/dashboard/FirstSteps/styles.module.css @@ -38,3 +38,23 @@ opacity: 0; visibility: hidden; } + +.accountReady { + text-align: center; + align-items: center; + justify-content: center; + padding: var(--space-4); + color: var(--color-text-secondary); +} + +.accountReady.completed { + color: var(--color-text-primary); +} + +.checkIcon { + color: var(--color-border-light); +} + +.checkIcon.completed { + color: var(--color-success-main); +} diff --git a/src/components/dashboard/FirstSteps/useDismissFirstSteps.ts b/src/components/dashboard/FirstSteps/useDismissFirstSteps.ts new file mode 100644 index 0000000000..8c72ba329e --- /dev/null +++ b/src/components/dashboard/FirstSteps/useDismissFirstSteps.ts @@ -0,0 +1,11 @@ +import useLocalStorage from '@/services/local-storage/useLocalStorage' + +const DISMISS_FIRST_STEPS_KEY = 'dismissFirstSteps' + +const useDismissFirstSteps = () => { + const [dismissFirstSteps, setDismissFirstSteps] = useLocalStorage(DISMISS_FIRST_STEPS_KEY) + + return { dismissFirstSteps, setDismissFirstSteps } +} + +export default useDismissFirstSteps diff --git a/src/components/dashboard/index.tsx b/src/components/dashboard/index.tsx index bc09c4205b..c2b31a3bf7 100644 --- a/src/components/dashboard/index.tsx +++ b/src/components/dashboard/index.tsx @@ -1,4 +1,4 @@ -import AddFundsCTA from '@/components/common/AddFunds' +import ActivateAccount from '@/features/counterfactual/ActivateAccount' import FirstSteps from '@/components/dashboard/FirstSteps' import useSafeInfo from '@/hooks/useSafeInfo' import type { ReactElement } from 'react' @@ -41,7 +41,7 @@ const Dashboard = (): ReactElement => { - + {safe.deployed && ( diff --git a/src/features/counterfactual/ActivateAccount.tsx b/src/features/counterfactual/ActivateAccount.tsx index e464a02614..195c7580b2 100644 --- a/src/features/counterfactual/ActivateAccount.tsx +++ b/src/features/counterfactual/ActivateAccount.tsx @@ -209,25 +209,34 @@ export const ActivateAccountFlow = () => { ) } -const ActivateAccount = () => { - const { safe } = useSafeInfo() +export const ActivateAccountButton = () => { const { setTxFlow } = useContext(TxModalContext) - if (safe.deployed) return null - const activateAccount = () => { setTxFlow() } return ( - - Activate your account? + + ) +} + +const ActivateAccount = () => { + const { safe } = useSafeInfo() + + if (safe.deployed) return null + + return ( + + + Want to skip onboarding? + Activate your account now by deploying it and paying a network fee. - + ) } diff --git a/src/features/counterfactual/CheckBalance.tsx b/src/features/counterfactual/CheckBalance.tsx index b8e2c97229..889724cf5f 100644 --- a/src/features/counterfactual/CheckBalance.tsx +++ b/src/features/counterfactual/CheckBalance.tsx @@ -1,42 +1,36 @@ -import CooldownButton from '@/components/common/CooldownButton' import ExternalLink from '@/components/common/ExternalLink' -import { getCounterfactualBalance } from '@/features/counterfactual/utils' +import { ActivateAccountButton } from '@/features/counterfactual/ActivateAccount' import { useCurrentChain } from '@/hooks/useChains' import useSafeInfo from '@/hooks/useSafeInfo' -import { useWeb3 } from '@/hooks/wallets/web3' import { getBlockExplorerLink } from '@/utils/chains' -import { Box, Typography } from '@mui/material' +import { Alert, Typography } from '@mui/material' const CheckBalance = () => { const { safe, safeAddress } = useSafeInfo() const chain = useCurrentChain() - const provider = useWeb3() if (safe.deployed) return null - const handleBalanceRefresh = async () => { - void getCounterfactualBalance(safeAddress, provider, chain, true) - } - const blockExplorerLink = chain ? getBlockExplorerLink(chain, safeAddress) : undefined return ( - - + + Don't see your tokens? - - - Refresh balance - - or + + Your Safe Account is not activated yet so we can only display your native balance. Finish the onboarding to + deploy your account onchain and unlock all features.{' '} {blockExplorerLink && ( - - check on Block Explorer - + <> + You can always view all of your assets on the{' '} + Block Explorer + )} - - + + + + ) } diff --git a/src/pages/settings/setup.tsx b/src/pages/settings/setup.tsx index 414c1f0da7..3229762803 100644 --- a/src/pages/settings/setup.tsx +++ b/src/pages/settings/setup.tsx @@ -1,4 +1,3 @@ -import ActivateAccount from '@/features/counterfactual/ActivateAccount' import type { NextPage } from 'next' import Head from 'next/head' import { Grid, Paper, Skeleton, SvgIcon, Tooltip, Typography } from '@mui/material' @@ -25,8 +24,6 @@ const Setup: NextPage = () => {
- -