diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d9bf694363..bc77009b65 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,6 +7,7 @@ concurrency: jobs: eslint: + permissions: write-all runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a25c47ab2a..3a1dd52e3c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,7 @@ concurrency: jobs: test: + permissions: write-all runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/src/components/common/ErrorBoundary/index.tsx b/src/components/common/ErrorBoundary/index.tsx index e277db308a..f25c1bbcfa 100644 --- a/src/components/common/ErrorBoundary/index.tsx +++ b/src/components/common/ErrorBoundary/index.tsx @@ -33,7 +33,7 @@ const ErrorBoundary: FallbackRender = ({ error, componentStack }) => { {componentStack} )} - + Go home diff --git a/src/components/common/Footer/index.tsx b/src/components/common/Footer/index.tsx index afd19922e0..545b1f43aa 100644 --- a/src/components/common/Footer/index.tsx +++ b/src/components/common/Footer/index.tsx @@ -11,7 +11,7 @@ import MUILink from '@mui/material/Link' import { IS_DEV, IS_OFFICIAL_HOST } from '@/config/constants' const footerPages = [ - AppRoutes.welcome, + AppRoutes.welcome.index, AppRoutes.settings.index, AppRoutes.imprint, AppRoutes.privacy, diff --git a/src/components/common/Header/index.tsx b/src/components/common/Header/index.tsx index 6930e44840..3949faba5d 100644 --- a/src/components/common/Header/index.tsx +++ b/src/components/common/Header/index.tsx @@ -29,7 +29,7 @@ const Header = ({ onMenuToggle, onBatchToggle }: HeaderProps): ReactElement => { const router = useRouter() // Logo link: if on Dashboard, link to Welcome, otherwise to the root (which redirects to either Dashboard or Welcome) - const logoHref = router.pathname === AppRoutes.home ? AppRoutes.welcome : AppRoutes.index + const logoHref = router.pathname === AppRoutes.home ? AppRoutes.welcome.index : AppRoutes.index const handleMenuToggle = () => { if (onMenuToggle) { diff --git a/src/components/common/NetworkSelector/index.tsx b/src/components/common/NetworkSelector/index.tsx index 4588d4d403..c795eecf59 100644 --- a/src/components/common/NetworkSelector/index.tsx +++ b/src/components/common/NetworkSelector/index.tsx @@ -15,7 +15,7 @@ import useWallet from '@/hooks/wallets/useWallet' import { isSocialWalletEnabled } from '@/hooks/wallets/wallets' import { isSocialLoginWallet } from '@/services/mpc/SocialLoginModule' -const keepPathRoutes = [AppRoutes.welcome, AppRoutes.newSafe.create, AppRoutes.newSafe.load] +const keepPathRoutes = [AppRoutes.welcome.index, AppRoutes.newSafe.create, AppRoutes.newSafe.load] const MenuWithTooltip = forwardRef(function MenuWithTooltip(props: any, ref) { return ( diff --git a/src/components/common/SafeLoadingError/index.tsx b/src/components/common/SafeLoadingError/index.tsx index a26fadf719..a9c17acf27 100644 --- a/src/components/common/SafeLoadingError/index.tsx +++ b/src/components/common/SafeLoadingError/index.tsx @@ -15,7 +15,7 @@ const SafeLoadingError = ({ children }: { children: ReactNode }): ReactElement = img={A vault with a red icon in the bottom right corner} text="This Safe Account couldn't be loaded" > - + diff --git a/src/components/new-safe/create/__tests__/useSyncSafeCreationStep.test.ts b/src/components/new-safe/create/__tests__/useSyncSafeCreationStep.test.ts index 310b09fbf7..a9ee033841 100644 --- a/src/components/new-safe/create/__tests__/useSyncSafeCreationStep.test.ts +++ b/src/components/new-safe/create/__tests__/useSyncSafeCreationStep.test.ts @@ -36,7 +36,7 @@ describe('useSyncSafeCreationStep', () => { renderHook(() => useSyncSafeCreationStep(mockSetStep)) expect(mockSetStep).not.toHaveBeenCalled() - expect(mockPushRoute).toHaveBeenCalledWith({ pathname: AppRoutes.welcome, query: undefined }) + expect(mockPushRoute).toHaveBeenCalledWith({ pathname: AppRoutes.welcome.index, query: undefined }) }) it('should go to the fourth step if there is a pending safe', async () => { diff --git a/src/components/new-safe/create/index.tsx b/src/components/new-safe/create/index.tsx index 1cb5429301..0231027e5e 100644 --- a/src/components/new-safe/create/index.tsx +++ b/src/components/new-safe/create/index.tsx @@ -169,7 +169,7 @@ const CreateSafe = () => { const initialStep = isSocialLogin ? 2 : 0 const onClose = () => { - router.push(AppRoutes.welcome) + router.push(AppRoutes.welcome.index) } return ( diff --git a/src/components/new-safe/create/steps/SetNameStep/index.tsx b/src/components/new-safe/create/steps/SetNameStep/index.tsx index 898d3ddd84..e6efd1fcad 100644 --- a/src/components/new-safe/create/steps/SetNameStep/index.tsx +++ b/src/components/new-safe/create/steps/SetNameStep/index.tsx @@ -63,7 +63,7 @@ function SetNameStep({ const onCancel = () => { trackEvent(CREATE_SAFE_EVENTS.CANCEL_CREATE_SAFE_FORM) - router.push(AppRoutes.welcome) + router.push(AppRoutes.welcome.index) } const isDisabled = isWrongChain || !isValid diff --git a/src/components/new-safe/create/steps/StatusStep/index.tsx b/src/components/new-safe/create/steps/StatusStep/index.tsx index 255ad37572..642b2ccd05 100644 --- a/src/components/new-safe/create/steps/StatusStep/index.tsx +++ b/src/components/new-safe/create/steps/StatusStep/index.tsx @@ -49,7 +49,7 @@ export const CreateSafeStatus = ({ data, setProgressColor, setStep }: StepRender const onClose = useCallback(() => { setPendingSafe(undefined) - router.push(AppRoutes.welcome) + router.push(AppRoutes.welcome.index) }, [router, setPendingSafe]) const handleRetry = useCallback(() => { diff --git a/src/components/new-safe/create/useSyncSafeCreationStep.ts b/src/components/new-safe/create/useSyncSafeCreationStep.ts index 9604114671..ef4294bee5 100644 --- a/src/components/new-safe/create/useSyncSafeCreationStep.ts +++ b/src/components/new-safe/create/useSyncSafeCreationStep.ts @@ -22,7 +22,7 @@ const useSyncSafeCreationStep = (setStep: StepRenderProps['setS // Jump to connect wallet step if there is no wallet and no pending Safe if (!wallet) { - router.push({ pathname: AppRoutes.welcome, query: router.query }) + router.push({ pathname: AppRoutes.welcome.index, query: router.query }) } // Jump to choose name and network step if the wallet is connected to the wrong chain and there is no pending Safe diff --git a/src/components/new-safe/load/index.tsx b/src/components/new-safe/load/index.tsx index 727d39a840..84c24c91ee 100644 --- a/src/components/new-safe/load/index.tsx +++ b/src/components/new-safe/load/index.tsx @@ -46,7 +46,7 @@ const LoadSafe = ({ initialData }: { initialData?: TxStepperProps { - router.push(AppRoutes.welcome) + router.push(AppRoutes.welcome.index) } const initialSafe = initialData ?? loadSafeDefaultData diff --git a/src/components/sidebar/SafeList/index.tsx b/src/components/sidebar/SafeList/index.tsx index 3689c7831a..c004462395 100644 --- a/src/components/sidebar/SafeList/index.tsx +++ b/src/components/sidebar/SafeList/index.tsx @@ -82,7 +82,7 @@ const SafeList = ({ closeDrawer }: { closeDrawer?: () => void }): ReactElement = const hasWallet = !!wallet const hasNoSafes = Object.keys(ownedSafes).length === 0 && Object.keys(addedSafes).length === 0 - const isWelcomePage = router.pathname === AppRoutes.welcome + const isWelcomePage = router.pathname === AppRoutes.welcome.index || router.pathname === AppRoutes.welcome.socialLogin const isSingleTxPage = router.pathname === AppRoutes.transactions.tx /** @@ -110,7 +110,7 @@ const SafeList = ({ closeDrawer }: { closeDrawer?: () => void }): ReactElement = {!isWelcomePage && ( @@ -136,7 +136,7 @@ const SafeList = ({ closeDrawer }: { closeDrawer?: () => void }): ReactElement = {!isWelcomePage ? ( - + {NO_SAFE_MESSAGE} ) : ( @@ -193,7 +193,7 @@ const SafeList = ({ closeDrawer }: { closeDrawer?: () => void }): ReactElement = {!addedSafeEntriesOnChain.length && !ownedSafesOnChain.length && ( {!isWelcomePage ? ( - + {NO_SAFE_MESSAGE} ) : ( diff --git a/src/components/sidebar/Sidebar/index.tsx b/src/components/sidebar/Sidebar/index.tsx index f25d8798d3..b8b46e9a5c 100644 --- a/src/components/sidebar/Sidebar/index.tsx +++ b/src/components/sidebar/Sidebar/index.tsx @@ -10,7 +10,7 @@ import SidebarFooter from '@/components/sidebar/SidebarFooter' import css from './styles.module.css' import { trackEvent, OVERVIEW_EVENTS } from '@/services/analytics' -import { DataWidget } from '@/components/welcome/DataWidget' +import { DataWidget } from '@/components/welcome/SafeListDrawer/DataWidget' const Sidebar = (): ReactElement => { const [isDrawerOpen, setIsDrawerOpen] = useState(false) diff --git a/src/components/welcome/NewSafe.tsx b/src/components/welcome/NewSafe.tsx index 409b495b16..46d51deb55 100644 --- a/src/components/welcome/NewSafe.tsx +++ b/src/components/welcome/NewSafe.tsx @@ -1,17 +1,10 @@ -import React, { useState } from 'react' -import { Accordion, AccordionSummary, Box, Drawer, Grid, IconButton, SvgIcon, Typography } from '@mui/material' -import SafeList from '@/components/sidebar/SafeList' +import React from 'react' +import { Box, Grid, SvgIcon, Typography } from '@mui/material' import css from './styles.module.css' import CheckFilled from '@/public/images/common/check-filled.svg' -import ChevronRightIcon from '@mui/icons-material/ChevronRight' -import { DataWidget } from '@/components/welcome/DataWidget' import WelcomeLogin from './WelcomeLogin' -import { useAppSelector } from '@/store' -import { selectTotalAdded } from '@/store/addedSafesSlice' - -import drawerCSS from '@/components/sidebar/Sidebar/styles.module.css' -import useOwnedSafes from '@/hooks/useOwnedSafes' +import SafeListDrawer from '@/components/welcome/SafeListDrawer' const BulletListItem = ({ text }: { text: string }) => (
  • @@ -23,26 +16,8 @@ const BulletListItem = ({ text }: { text: string }) => ( ) const NewSafe = () => { - const numberOfAddedSafes = useAppSelector(selectTotalAdded) - const ownedSafes = useOwnedSafes() - const numberOfOwnedSafes = Object.values(ownedSafes).reduce((acc, curr) => acc + curr.length, 0) - const totalNumberOfSafes = numberOfOwnedSafes + numberOfAddedSafes - - const [showSidebar, setShowSidebar] = useState(false) - - const closeSidebar = () => setShowSidebar(false) - return ( <> - -
    - - -
    - -
    -
    -
    @@ -50,24 +25,7 @@ const NewSafe = () => {
    - {totalNumberOfSafes > 0 ? ( - - - setShowSidebar(true)} expanded={false}> - - - - - - - My Safe Accounts ({totalNumberOfSafes}) - - - - - - - ) : null} + diff --git a/src/components/welcome/NewSafeSocial.tsx b/src/components/welcome/NewSafeSocial.tsx new file mode 100644 index 0000000000..26c1d1da77 --- /dev/null +++ b/src/components/welcome/NewSafeSocial.tsx @@ -0,0 +1,87 @@ +import React from 'react' +import { Box, Button, Grid, Typography } from '@mui/material' +import css from './styles.module.css' +import Link from 'next/link' + +import ChevronLeftIcon from '@mui/icons-material/ChevronLeft' +import WelcomeLogin from './WelcomeLogin' +import GnosisChainLogo from '@/public/images/common/gnosis-chain-logo.png' +import Image from 'next/image' +import SafeListDrawer from '@/components/welcome/SafeListDrawer' + +const BulletListItem = ({ text }: { text: string }) => ( +
  • + + {text} + +
  • +) + +const MarqueeItem = () => { + return ( +
  • + Free on + Gnosis Chain logo + Gnosis Chain +
  • + ) +} + +const NewSafeSocial = () => { + return ( + <> + + + + + +
    + + + + + + + Get started in 30 seconds with your Google Account + + +
      + + + +
    + + {/* TODO: Replace with actual link and possibly add tracking */} + + + +
    + +
    +
      + + + +
    + +
    +
    +
    +
    + + ) +} + +export default NewSafeSocial diff --git a/src/components/welcome/DataWidget.tsx b/src/components/welcome/SafeListDrawer/DataWidget.tsx similarity index 100% rename from src/components/welcome/DataWidget.tsx rename to src/components/welcome/SafeListDrawer/DataWidget.tsx diff --git a/src/components/welcome/SafeListDrawer/index.tsx b/src/components/welcome/SafeListDrawer/index.tsx new file mode 100644 index 0000000000..afa8f5418d --- /dev/null +++ b/src/components/welcome/SafeListDrawer/index.tsx @@ -0,0 +1,55 @@ +import React, { useState } from 'react' +import SafeList from '@/components/sidebar/SafeList' +import { DataWidget } from '@/components/welcome/SafeListDrawer/DataWidget' +import { Button, Drawer, Typography } from '@mui/material' +import ChevronRightIcon from '@mui/icons-material/ChevronRight' +import { useAppSelector } from '@/store' +import { selectTotalAdded } from '@/store/addedSafesSlice' +import useOwnedSafes from '@/hooks/useOwnedSafes' +import drawerCSS from '@/components/sidebar/Sidebar/styles.module.css' +import css from './styles.module.css' + +const SafeListDrawer = () => { + const numberOfAddedSafes = useAppSelector(selectTotalAdded) + const ownedSafes = useOwnedSafes() + const numberOfOwnedSafes = Object.values(ownedSafes).reduce((acc, curr) => acc + curr.length, 0) + const totalNumberOfSafes = numberOfOwnedSafes + numberOfAddedSafes + const [showSidebar, setShowSidebar] = useState(false) + + const closeSidebar = () => setShowSidebar(false) + + if (totalNumberOfSafes <= 0) { + return null + } + + return ( + <> + +
    + + +
    + +
    +
    +
    + + + ) +} + +export default SafeListDrawer diff --git a/src/components/welcome/SafeListDrawer/styles.module.css b/src/components/welcome/SafeListDrawer/styles.module.css new file mode 100644 index 0000000000..5aed51e96f --- /dev/null +++ b/src/components/welcome/SafeListDrawer/styles.module.css @@ -0,0 +1,33 @@ +.button { + padding: var(--space-2); +} + +.buttonText { + align-self: center; + margin: auto; + display: flex; + gap: var(--space-1); +} + +.fileIcon { + display: flex; + align-items: center; + padding: var(--space-1); + background-color: var(--color-background-main); +} + +.card { + padding: var(--space-3); + gap: var(--space-2); + display: flex; + flex-direction: column; +} + +.card :global .MuiCardHeader-root, +.card :global .MuiCardContent-root { + padding: 0; +} + +.cardHeader { + text-align: left; +} diff --git a/src/components/welcome/styles.module.css b/src/components/welcome/styles.module.css index 2b8c377b76..fe9fa566d5 100644 --- a/src/components/welcome/styles.module.css +++ b/src/components/welcome/styles.module.css @@ -1,22 +1,3 @@ -.accordion :global .MuiAccordionDetails-root > div > div:first-child { - display: none; -} - -.accordion { - border: 0; - height: 100%; -} - -.accordion :global .MuiAccordionSummary-root { - background: transparent !important; - padding: var(--space-2); - border-bottom: 1px solid var(--color-border-light); -} - -.accordion :global .MuiAccordionSummary-content { - margin: 0; -} - .sidebar { max-height: calc(100vh - var(--header-height) - var(--footer-height) - 8px); overflow-y: auto; @@ -39,52 +20,87 @@ margin-bottom: var(--space-2); } -.content { - background: linear-gradient(-90deg, #10ff84, #5fddff); - background-size: 200% 200%; - animation: gradient 15s ease infinite; - border-radius: 6px; - padding: var(--space-3); +.numberList { + margin: var(--space-5) 0; + padding: 0; + list-style: none; +} + +.numberList li { display: flex; - flex-direction: column; - justify-content: center; - gap: var(--space-2); - width: 100%; - height: 100%; + flex-direction: row; + gap: var(--space-1); + align-items: center; + margin-bottom: var(--space-2); + counter-increment: item; } -.checkIcon { - color: var(--color-static-main); +.numberList li:before { + margin-right: var(--space-1); + content: counter(item); + background: var(--color-static-main); + border-radius: 100%; + color: white; + width: 32px; + height: 32px; + line-height: 32px; + font-size: 18px; + text-align: center; + flex-shrink: 0; } -.createAddCard { +.marquee { display: flex; - flex-direction: column; - padding: var(--space-4); - height: 100%; + overflow: hidden; + user-select: none; + gap: var(--space-6); + background-color: var(--color-static-main); + color: white; + padding: 20px; + margin: var(--space-3) calc(-1 * var(--space-9)) calc(-1 * var(--space-3)); } -.fileIcon { +.marqueeContent { + margin: 0; + padding: 0; + flex-shrink: 0; + display: flex; + justify-content: space-around; + min-width: 100%; + gap: var(--space-6); + animation: scroll 10s linear infinite; +} + +.marqueeItem { + font-size: 18px; display: flex; align-items: center; - padding: var(--space-1); - background-color: var(--color-background-main); } -.card { - padding: var(--space-3); - gap: var(--space-2); +.marqueeItem img { + margin: 0 var(--space-1); +} + +.content { + background: linear-gradient(-90deg, #10ff84, #5fddff); + background-size: 200% 200%; + animation: gradient 15s ease infinite; + border-radius: 6px; + padding: var(--space-9); display: flex; flex-direction: column; + justify-content: center; + gap: var(--space-2); + width: 100%; + height: 100%; } -.card :global .MuiCardHeader-root, -.card :global .MuiCardContent-root { - padding: 0; +.checkIcon { + color: var(--color-static-main); } -.cardHeader { - text-align: left; +.button { + color: var(--color-static-main); } @media (max-width: 899.95px) { @@ -92,23 +108,23 @@ height: 100%; } - .accordion { - height: auto; - } - - .accordion :global .MuiAccordionSummary-expandIconWrapper { - display: block; - } - .content { padding: var(--space-6); } + + .marquee { + margin: var(--space-3) calc(-1 * var(--space-6)) calc(-1 * var(--space-3)); + } } @media (max-width: 599.95px) { .content { padding: var(--space-4); } + + .marquee { + margin: var(--space-3) calc(-1 * var(--space-4)) 0; + } } @keyframes gradient { @@ -122,3 +138,12 @@ background-position: 0 50%; } } + +@keyframes scroll { + from { + transform: translateX(0); + } + to { + transform: translateX(calc(-100% - var(--space-6))); + } +} diff --git a/src/config/routes.ts b/src/config/routes.ts index 34b6848e00..9ea85b1e18 100644 --- a/src/config/routes.ts +++ b/src/config/routes.ts @@ -1,6 +1,5 @@ export const AppRoutes = { '404': '/404', - welcome: '/welcome', terms: '/terms', privacy: '/privacy', licenses: '/licenses', @@ -50,4 +49,8 @@ export const AppRoutes = { index: '/transactions', history: '/transactions/history', }, + welcome: { + socialLogin: '/welcome/social-login', + index: '/welcome', + }, } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index a2c6442367..738a591942 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -21,8 +21,8 @@ const IndexPage: NextPage = () => { safeAddress ? `${AppRoutes.home}?safe=${safeAddress}` : chain - ? `${AppRoutes.welcome}?chain=${chain}` - : AppRoutes.welcome, + ? `${AppRoutes.welcome.index}?chain=${chain}` + : AppRoutes.welcome.index, ) }, [router, safeAddress, chain]) diff --git a/src/pages/welcome.tsx b/src/pages/welcome/index.tsx similarity index 100% rename from src/pages/welcome.tsx rename to src/pages/welcome/index.tsx diff --git a/src/pages/welcome/social-login.tsx b/src/pages/welcome/social-login.tsx new file mode 100644 index 0000000000..d4cf360333 --- /dev/null +++ b/src/pages/welcome/social-login.tsx @@ -0,0 +1,17 @@ +import type { NextPage } from 'next' +import Head from 'next/head' +import NewSafeSocial from '@/components/welcome/NewSafeSocial' + +const SocialLogin: NextPage = () => { + return ( + <> + + {'Safe{Wallet} – Welcome'} + + + + + ) +} + +export default SocialLogin