diff --git a/cypress/e2e/smoke/load_safe.cy.js b/cypress/e2e/smoke/load_safe.cy.js
index 599d511d6d..144bb30f83 100644
--- a/cypress/e2e/smoke/load_safe.cy.js
+++ b/cypress/e2e/smoke/load_safe.cy.js
@@ -29,22 +29,20 @@ describe('Load existing Safe', () => {
it('should allow choosing the network where the Safe exists', () => {
// Click the network selector inside the Stepper content
- cy.contains('Select network on which the Safe was created:').contains('span', 'Polygon').click()
+ cy.get('[data-testid=load-safe-form]').contains('Polygon').click()
// Selects Goerli
cy.get('ul li')
.contains(/^G(ö|oe)rli$/)
.click()
- cy.contains('Select network on which the Safe was created:').contains('span', /^G(ö|oe)rli$/)
-
- cy.contains('Continue').click()
+ cy.contains('span', /^G(ö|oe)rli$/)
})
it('should accept name the Safe', () => {
// alias the address input label
cy.get('input[name="address"]').parent().prev('label').as('addressLabel')
- // Name input should have a placeholder ending in 'rinkeby-safe'
+ // Name input should have a placeholder ending in 'goerli-safe'
cy.get('input[name="name"]')
.should('have.attr', 'placeholder')
.should('match', /g(ö|oe)rli-safe/)
@@ -77,7 +75,7 @@ describe('Load existing Safe', () => {
const [, address] = SAFE_QR_CODE_ADDRESS.split(':')
cy.get('input[name="address"]').should('have.value', address)
- cy.contains('Continue').click()
+ cy.contains('Next').click()
})
// TODO: register the goerli ENS for the Safe owner when possible
@@ -92,7 +90,7 @@ describe('Load existing Safe', () => {
it('should set custom name in the first owner', () => {
// Sets a custom name for the first owner
cy.get('input[name="owners.0.name"]').type('Test Owner Name').should('have.value', 'Test Owner Name')
- cy.contains('Continue').click()
+ cy.contains('Next').click()
})
it('should have Safe and owner names in the Review step', () => {
diff --git a/src/components/common/NetworkSelector/index.tsx b/src/components/common/NetworkSelector/index.tsx
index 279a754d0d..15d527a5bd 100644
--- a/src/components/common/NetworkSelector/index.tsx
+++ b/src/components/common/NetworkSelector/index.tsx
@@ -24,7 +24,7 @@ const NetworkSelector = (): ReactElement => {
trackEvent({ ...OVERVIEW_EVENTS.SWITCH_NETWORK, label: selectedChainId })
- const shouldKeepPath = [AppRoutes.load, AppRoutes.open, AppRoutes.newSafe.create].includes(router.pathname)
+ const shouldKeepPath = [AppRoutes.newSafe.create, AppRoutes.newSafe.load].includes(router.pathname)
const newRoute = {
pathname: shouldKeepPath ? router.pathname : '/',
diff --git a/src/components/common/PageLayout/SideDrawer.tsx b/src/components/common/PageLayout/SideDrawer.tsx
index 27166ccf47..61e8300f65 100644
--- a/src/components/common/PageLayout/SideDrawer.tsx
+++ b/src/components/common/PageLayout/SideDrawer.tsx
@@ -20,6 +20,10 @@ const isNewSafeRoute = (pathname: string): boolean => {
return pathname === AppRoutes.newSafe.create
}
+const isLoadSafeRoute = (pathname: string): boolean => {
+ return pathname === AppRoutes.newSafe.load
+}
+
const isAppShareRoute = (pathname: string): boolean => {
return pathname === AppRoutes.share.safeApp
}
@@ -36,7 +40,11 @@ const SideDrawer = ({ isOpen, onToggle }: SideDrawerProps): ReactElement => {
useEffect(() => {
const closeSidebar =
- isSmallScreen || isSafeAppRoute(pathname, query) || isAppShareRoute(pathname) || isNewSafeRoute(pathname)
+ isSmallScreen ||
+ isSafeAppRoute(pathname, query) ||
+ isAppShareRoute(pathname) ||
+ isNewSafeRoute(pathname) ||
+ isLoadSafeRoute(pathname)
onToggle(!closeSidebar)
}, [isSmallScreen, onToggle, pathname, query])
diff --git a/src/components/load-safe/index.tsx b/src/components/load-safe/index.tsx
deleted file mode 100644
index d1a273a8c9..0000000000
--- a/src/components/load-safe/index.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from 'react'
-import { useRouter } from 'next/router'
-
-import type { TxStepperProps } from '@/components/tx/TxStepper/useTxStepper'
-import VerticalTxStepper from '@/components/tx/TxStepper/vertical'
-import { AppRoutes } from '@/config/routes'
-import SafeOwnersStep from '@/components/load-safe/steps/SafeOwnersStep'
-import SetAddressStep from '@/components/load-safe/steps/SetAddressStep'
-import SafeReviewStep from '@/components/load-safe/steps/SafeReviewStep'
-import SelectNetworkStep from '@/components/load-safe/steps/SelectNetworkStep'
-import type { SafeFormData } from '@/components/create-safe/types'
-import { LOAD_SAFE_CATEGORY } from '@/services/analytics'
-
-export const LoadSafeSteps: TxStepperProps['steps'] = [
- {
- label: 'Connect wallet & select network',
- render: (_, onSubmit, onBack) => ,
- },
- {
- label: 'Name and address',
- render: (data, onSubmit, onBack) => (
-
- ),
- },
- {
- label: 'Owners',
- render: (data, onSubmit, onBack) => (
-
- ),
- },
- {
- label: 'Review',
- render: (data, _, onBack) => ,
- },
-]
-
-const LoadSafe = ({
- initialStep,
- initialData,
-}: {
- initialStep?: TxStepperProps['initialStep']
- initialData?: TxStepperProps['initialData']
-}) => {
- const router = useRouter()
-
- return (
- router.push(AppRoutes.welcome)}
- eventCategory={LOAD_SAFE_CATEGORY}
- />
- )
-}
-
-export default LoadSafe
diff --git a/src/components/load-safe/steps/SafeOwnersStep.tsx b/src/components/load-safe/steps/SafeOwnersStep.tsx
deleted file mode 100644
index c913336ded..0000000000
--- a/src/components/load-safe/steps/SafeOwnersStep.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import type { ReactElement } from 'react'
-import React, { useEffect } from 'react'
-import { Box, Button, Divider, Grid, Paper, Typography } from '@mui/material'
-import { FormProvider, useFieldArray, useForm } from 'react-hook-form'
-
-import type { StepRenderProps } from '@/components/tx/TxStepper/useTxStepper'
-import ChainIndicator from '@/components/common/ChainIndicator'
-import useAsync from '@/hooks/useAsync'
-import type { SafeInfo } from '@safe-global/safe-gateway-typescript-sdk'
-import { getSafeInfo } from '@safe-global/safe-gateway-typescript-sdk'
-
-import { OwnerRow } from '@/components/create-safe/steps/OwnerRow'
-import useChainId from '@/hooks/useChainId'
-import type { SafeFormData } from '@/components/create-safe/types'
-
-type Props = {
- params: SafeFormData
- onSubmit: StepRenderProps['onSubmit']
- onBack: StepRenderProps['onBack']
-}
-
-const SafeOwnersStep = ({ params, onSubmit, onBack }: Props): ReactElement => {
- const chainId = useChainId()
- const formMethods = useForm({ defaultValues: params, mode: 'onChange' })
- const { handleSubmit, setValue, control, formState, getValues } = formMethods
-
- const { fields } = useFieldArray({
- control,
- name: 'owners',
- })
-
- const [safeInfo] = useAsync(() => {
- if (params.address) {
- return getSafeInfo(chainId, params.address)
- }
- }, [chainId, params.address])
-
- useEffect(() => {
- if (!safeInfo) return
-
- setValue('threshold', safeInfo.threshold)
-
- const owners = safeInfo.owners.map((owner, i) => ({
- address: owner.value,
- name: getValues(`owners.${i}.name`) || '',
- }))
-
- setValue('owners', owners)
- }, [getValues, safeInfo, setValue])
-
- const onFormBack = () => {
- onBack(getValues())
- }
-
- return (
-
-
-
-
-
- )
-}
-
-export default SafeOwnersStep
diff --git a/src/components/load-safe/steps/SafeReviewStep.tsx b/src/components/load-safe/steps/SafeReviewStep.tsx
deleted file mode 100644
index 7cf8e73345..0000000000
--- a/src/components/load-safe/steps/SafeReviewStep.tsx
+++ /dev/null
@@ -1,183 +0,0 @@
-import React from 'react'
-import { Box, Button, Divider, Grid, Paper, Typography } from '@mui/material'
-import type { StepRenderProps } from '@/components/tx/TxStepper/useTxStepper'
-import ChainIndicator from '@/components/common/ChainIndicator'
-import EthHashInfo from '@/components/common/EthHashInfo'
-import { useAppDispatch } from '@/store'
-import { addOrUpdateSafe } from '@/store/addedSafesSlice'
-import { useRouter } from 'next/router'
-import { AppRoutes } from '@/config/routes'
-import { upsertAddressBookEntry } from '@/store/addressBookSlice'
-import useWallet from '@/hooks/wallets/useWallet'
-import { isOwner } from '@/utils/transaction-guards'
-import { defaultSafeInfo } from '@/store/safeInfoSlice'
-import { useCurrentChain } from '@/hooks/useChains'
-import type { SafeFormData } from '@/components/create-safe/types'
-import { trackEvent, LOAD_SAFE_EVENTS } from '@/services/analytics'
-
-type Props = {
- params: SafeFormData
- onBack: StepRenderProps['onBack']
-}
-
-const SafeReviewStep = ({ params, onBack }: Props) => {
- const dispatch = useAppDispatch()
- const router = useRouter()
- const wallet = useWallet()
- const isSafeOwner = wallet && isOwner(params.owners, wallet.address)
- const currentChain = useCurrentChain()
- const chainId = currentChain?.chainId || ''
-
- const addSafe = () => {
- const safeName = params.name
- const safeAddress = params.address
-
- dispatch(
- addOrUpdateSafe({
- safe: {
- ...defaultSafeInfo,
- address: { value: safeAddress, name: safeName },
- threshold: params.threshold,
- owners: params.owners.map((owner) => ({
- value: owner.address,
- name: owner.name || owner.ens,
- })),
- chainId,
- },
- }),
- )
-
- dispatch(
- upsertAddressBookEntry({
- chainId,
- address: safeAddress,
- name: safeName,
- }),
- )
-
- for (const { address, name, ens } of params.owners) {
- const entryName = name || ens
-
- if (!entryName) {
- continue
- }
-
- dispatch(
- upsertAddressBookEntry({
- chainId,
- address,
- name: entryName,
- }),
- )
- }
-
- trackEvent({
- ...LOAD_SAFE_EVENTS.OWNERS,
- label: params.owners.length,
- })
-
- trackEvent({
- ...LOAD_SAFE_EVENTS.THRESHOLD,
- label: params.threshold,
- })
-
- trackEvent(LOAD_SAFE_EVENTS.GO_TO_SAFE)
-
- router.push({
- pathname: AppRoutes.home,
- query: { safe: `${currentChain?.shortName}:${safeAddress}` },
- })
- }
-
- return (
-
-
-
-
- Details
-
- Network
-
-
-
-
-
- {params.name && (
- <>
-
- Name of the Safe
-
- {params.name}
- >
- )}
-
- Safe address
-
-
-
-
-
- Connected wallet client is owner?
-
- {isSafeOwner ? 'Yes' : 'No'}
-
-
- Any transaction requires the confirmation of:
-
-
- {params.threshold} out of {params.owners.length}
-
-
-
- [undefined, undefined, `1px solid ${palette.border.light}`]}
- borderTop={({ palette }) => [`1px solid ${palette.border.light}`, undefined, 'none']}
- >
- {params.owners.length} Safe owner(s)
-
-
- {params.owners.map((owner) => {
- return (
-
-
-
- )
- })}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default SafeReviewStep
diff --git a/src/components/load-safe/steps/SelectNetworkStep.tsx b/src/components/load-safe/steps/SelectNetworkStep.tsx
deleted file mode 100644
index a52df40d18..0000000000
--- a/src/components/load-safe/steps/SelectNetworkStep.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { Box, Button, Divider, Grid, Paper, Typography } from '@mui/material'
-import type { StepRenderProps } from '@/components/tx/TxStepper/useTxStepper'
-import NetworkSelector from '@/components/common/NetworkSelector'
-
-type Props = {
- onSubmit: StepRenderProps['onSubmit']
- onBack: StepRenderProps['onBack']
-}
-
-const SelectNetworkStep = ({ onSubmit, onBack }: Props) => {
- return (
-
-
-
- Select network on which the Safe was created:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- )
-}
-
-export default SelectNetworkStep
diff --git a/src/components/load-safe/steps/SetAddressStep.tsx b/src/components/load-safe/steps/SetAddressStep.tsx
deleted file mode 100644
index 104471d3f2..0000000000
--- a/src/components/load-safe/steps/SetAddressStep.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import React from 'react'
-import { Box, Button, CircularProgress, Divider, Grid, InputAdornment, Paper, Typography } from '@mui/material'
-import { useForm, FormProvider } from 'react-hook-form'
-import type { StepRenderProps } from '@/components/tx/TxStepper/useTxStepper'
-import ChainIndicator from '@/components/common/ChainIndicator'
-import AddressInput from '@/components/common/AddressInput'
-import { getSafeInfo } from '@safe-global/safe-gateway-typescript-sdk'
-import useChainId from '@/hooks/useChainId'
-import { useAppSelector } from '@/store'
-import { selectAddedSafes } from '@/store/addedSafesSlice'
-import NameInput from '@/components/common/NameInput'
-import { useAddressResolver } from '@/hooks/useAddressResolver'
-import { useMnemonicSafeName } from '@/hooks/useMnemonicName'
-import type { SafeFormData } from '@/components/create-safe/types'
-import { trackEvent, LOAD_SAFE_EVENTS } from '@/services/analytics'
-import ExternalLink from '@/components/common/ExternalLink'
-
-type Props = {
- params: SafeFormData
- onSubmit: StepRenderProps['onSubmit']
- onBack: StepRenderProps['onBack']
-}
-
-enum FormField {
- address = 'address',
- name = 'name',
-}
-
-const SetAddressStep = ({ params, onSubmit, onBack }: Props) => {
- const currentChainId = useChainId()
- const addedSafes = useAppSelector((state) => selectAddedSafes(state, currentChainId))
- const formMethods = useForm({
- mode: 'onChange',
- defaultValues: {
- [FormField.address]: params?.address || '',
- [FormField.name]: params?.name || '',
- },
- })
-
- const { handleSubmit, watch, formState, getValues } = formMethods
-
- const safeAddress = watch('address')
-
- const randomName = useMnemonicSafeName()
- const { ens, name, resolving } = useAddressResolver(safeAddress)
-
- // Address book, ENS, mnemonic
- const fallbackName = name || ens || randomName
-
- const validateSafeAddress = async (address: string) => {
- if (addedSafes && Object.keys(addedSafes).includes(address)) {
- return 'Safe is already added'
- }
-
- try {
- await getSafeInfo(currentChainId, address)
- } catch (error) {
- return 'Address given is not a valid Safe address'
- }
- }
-
- const onFormSubmit = handleSubmit((data: SafeFormData) => {
- onSubmit({
- ...data,
- [FormField.name]: data[FormField.name] || fallbackName,
- })
-
- if (data[FormField.name]) {
- trackEvent(LOAD_SAFE_EVENTS.NAME_SAFE)
- }
- })
-
- const onFormBack = () => {
- onBack({
- ...getValues(),
- [FormField.name]: getValues([FormField.name]) || fallbackName,
- })
- }
-
- return (
-
-
-
-
-
- )
-}
-
-export default SetAddressStep
diff --git a/src/components/new-safe/steps/Step2/OwnerRow.tsx b/src/components/new-safe/OwnerRow/index.tsx
similarity index 88%
rename from src/components/new-safe/steps/Step2/OwnerRow.tsx
rename to src/components/new-safe/OwnerRow/index.tsx
index e582cd560e..8899c1ca50 100644
--- a/src/components/new-safe/steps/Step2/OwnerRow.tsx
+++ b/src/components/new-safe/OwnerRow/index.tsx
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo } from 'react'
-import { CircularProgress, FormControl, Grid, IconButton, SvgIcon } from '@mui/material'
+import { CircularProgress, FormControl, Grid, IconButton, SvgIcon, Typography } from '@mui/material'
import NameInput from '@/components/common/NameInput'
import InputAdornment from '@mui/material/InputAdornment'
import AddressBookInput from '@/components/common/AddressBookInput'
@@ -10,11 +10,8 @@ import EthHashInfo from '@/components/common/EthHashInfo'
import type { NamedAddress } from '@/components/create-safe/types'
import useWallet from '@/hooks/wallets/useWallet'
import { sameAddress } from '@/utils/addresses'
+import css from './styles.module.css'
-/**
- * TODO: this is a slightly modified copy of the old /create-safe/OwnerRow.tsx
- * Once we remove the old safe creation flow we should remove the old file.
- */
export const OwnerRow = ({
index,
groupName,
@@ -66,10 +63,11 @@ export const OwnerRow = ({
}, [ens, setValue, getValues, name, fieldName])
return (
-
-
+
+
{readOnly ? (
-
+
+
+
) : (
)
}
+
+export default OwnerRow
diff --git a/src/components/new-safe/OwnerRow/styles.module.css b/src/components/new-safe/OwnerRow/styles.module.css
new file mode 100644
index 0000000000..434db87c10
--- /dev/null
+++ b/src/components/new-safe/OwnerRow/styles.module.css
@@ -0,0 +1,11 @@
+.name :global .MuiFormHelperText-root {
+ position: absolute;
+ bottom: -20px;
+}
+
+@media (max-width: 900px) {
+ .name :global .MuiFormHelperText-root {
+ position: relative;
+ bottom: 0;
+ }
+}
diff --git a/src/components/new-safe/ReviewRow/index.tsx b/src/components/new-safe/ReviewRow/index.tsx
new file mode 100644
index 0000000000..7478c054c4
--- /dev/null
+++ b/src/components/new-safe/ReviewRow/index.tsx
@@ -0,0 +1,17 @@
+import React, { type ReactElement } from 'react'
+import { Grid, Typography } from '@mui/material'
+
+const ReviewRow = ({ name, value }: { name: string; value: ReactElement }) => {
+ return (
+ <>
+
+ {name}
+
+
+ {value}
+
+ >
+ )
+}
+
+export default ReviewRow
diff --git a/src/components/new-safe/CreateSafeInfos/index.tsx b/src/components/new-safe/create/CreateSafeInfos/index.tsx
similarity index 100%
rename from src/components/new-safe/CreateSafeInfos/index.tsx
rename to src/components/new-safe/create/CreateSafeInfos/index.tsx
diff --git a/src/components/new-safe/NetworkWarning/index.tsx b/src/components/new-safe/create/NetworkWarning/index.tsx
similarity index 100%
rename from src/components/new-safe/NetworkWarning/index.tsx
rename to src/components/new-safe/create/NetworkWarning/index.tsx
diff --git a/src/components/new-safe/OverviewWidget/index.tsx b/src/components/new-safe/create/OverviewWidget/index.tsx
similarity index 95%
rename from src/components/new-safe/OverviewWidget/index.tsx
rename to src/components/new-safe/create/OverviewWidget/index.tsx
index dace52829a..14c02e63c5 100644
--- a/src/components/new-safe/OverviewWidget/index.tsx
+++ b/src/components/new-safe/create/OverviewWidget/index.tsx
@@ -6,7 +6,7 @@ import { Card, Grid, Typography } from '@mui/material'
import type { ReactElement } from 'react'
import SafeLogo from '@/public/images/logo-no-text.svg'
-import css from './styles.module.css'
+import css from '@/components/new-safe/create/OverviewWidget/styles.module.css'
const LOGO_DIMENSIONS = '22px'
diff --git a/src/components/new-safe/OverviewWidget/styles.module.css b/src/components/new-safe/create/OverviewWidget/styles.module.css
similarity index 100%
rename from src/components/new-safe/OverviewWidget/styles.module.css
rename to src/components/new-safe/create/OverviewWidget/styles.module.css
diff --git a/src/components/new-safe/CreateSafe/__tests__/useSyncSafeCreationStep.test.ts b/src/components/new-safe/create/__tests__/useSyncSafeCreationStep.test.ts
similarity index 93%
rename from src/components/new-safe/CreateSafe/__tests__/useSyncSafeCreationStep.test.ts
rename to src/components/new-safe/create/__tests__/useSyncSafeCreationStep.test.ts
index 7472e03927..cd8d2a011e 100644
--- a/src/components/new-safe/CreateSafe/__tests__/useSyncSafeCreationStep.test.ts
+++ b/src/components/new-safe/create/__tests__/useSyncSafeCreationStep.test.ts
@@ -1,5 +1,5 @@
import { renderHook } from '@/tests/test-utils'
-import useSyncSafeCreationStep from '@/components/new-safe/CreateSafe/useSyncSafeCreationStep'
+import useSyncSafeCreationStep from '@/components/new-safe/create/useSyncSafeCreationStep'
import * as wallet from '@/hooks/wallets/useWallet'
import * as localStorage from '@/services/local-storage/useLocalStorage'
import type { ConnectedWallet } from '@/services/onboard'
diff --git a/src/components/new-safe/CreateSafe/index.tsx b/src/components/new-safe/create/index.tsx
similarity index 89%
rename from src/components/new-safe/CreateSafe/index.tsx
rename to src/components/new-safe/create/index.tsx
index 8f05af2d54..e554a3d51c 100644
--- a/src/components/new-safe/CreateSafe/index.tsx
+++ b/src/components/new-safe/create/index.tsx
@@ -2,21 +2,21 @@ import { Container, Typography, Grid } from '@mui/material'
import { useRouter } from 'next/router'
import useWallet from '@/hooks/wallets/useWallet'
-import OverviewWidget from '../OverviewWidget'
+import OverviewWidget from '@/components/new-safe/create/OverviewWidget'
import type { NamedAddress } from '@/components/create-safe/types'
-import type { TxStepperProps } from '../CardStepper/useCardStepper'
-import CreateSafeStep0 from '@/components/new-safe/steps/Step0'
-import CreateSafeStep1 from '@/components/new-safe/steps/Step1'
-import CreateSafeStep2 from '@/components/new-safe/steps/Step2'
-import CreateSafeStep3 from '@/components/new-safe/steps/Step3'
-import { CreateSafeStatus } from '@/components/new-safe/steps/Step4'
+import type { TxStepperProps } from '@/components/new-safe/CardStepper/useCardStepper'
+import CreateSafeStep0 from '@/components/new-safe/create/steps/Step0'
+import CreateSafeStep1 from '@/components/new-safe/create/steps/Step1'
+import CreateSafeStep2 from '@/components/new-safe/create/steps/Step2'
+import CreateSafeStep3 from '@/components/new-safe/create/steps/Step3'
+import { CreateSafeStatus } from '@/components/new-safe/create/steps/Step4'
import useAddressBook from '@/hooks/useAddressBook'
-import { CardStepper } from '../CardStepper'
+import { CardStepper } from '@/components/new-safe/CardStepper'
import { AppRoutes } from '@/config/routes'
import { CREATE_SAFE_CATEGORY } from '@/services/analytics'
import type { AlertColor } from '@mui/material'
-import type { CreateSafeInfoItem } from '../CreateSafeInfos'
-import CreateSafeInfos from '../CreateSafeInfos'
+import type { CreateSafeInfoItem } from '@/components/new-safe/create/CreateSafeInfos'
+import CreateSafeInfos from '@/components/new-safe/create/CreateSafeInfos'
import { type ReactElement, useMemo, useState } from 'react'
import ExternalLink from '@/components/common/ExternalLink'
diff --git a/src/components/new-safe/steps/Step0/index.tsx b/src/components/new-safe/create/steps/Step0/index.tsx
similarity index 89%
rename from src/components/new-safe/steps/Step0/index.tsx
rename to src/components/new-safe/create/steps/Step0/index.tsx
index ee2864f922..48e5c17291 100644
--- a/src/components/new-safe/steps/Step0/index.tsx
+++ b/src/components/new-safe/create/steps/Step0/index.tsx
@@ -4,12 +4,12 @@ import useWallet from '@/hooks/wallets/useWallet'
import { useCurrentChain } from '@/hooks/useChains'
import { isPairingSupported } from '@/services/pairing/utils'
-import type { NewSafeFormData } from '@/components/new-safe/CreateSafe'
+import type { NewSafeFormData } from '@/components/new-safe/create'
import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
-import useSyncSafeCreationStep from '@/components/new-safe/CreateSafe/useSyncSafeCreationStep'
-import layoutCss from '@/components/new-safe/CreateSafe/styles.module.css'
+import useSyncSafeCreationStep from '@/components/new-safe/create/useSyncSafeCreationStep'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
import useLocalStorage from '@/services/local-storage/useLocalStorage'
-import { type PendingSafeData, SAFE_PENDING_CREATION_STORAGE_KEY } from '@/components/new-safe/steps/Step4'
+import { type PendingSafeData, SAFE_PENDING_CREATION_STORAGE_KEY } from '@/components/new-safe/create/steps/Step4'
import useConnectWallet from '@/components/common/ConnectWallet/useConnectWallet'
import KeyholeIcon from '@/components/common/icons/KeyholeIcon'
import PairingDescription from '@/components/common/PairingDetails/PairingDescription'
diff --git a/src/components/new-safe/steps/Step1/index.tsx b/src/components/new-safe/create/steps/Step1/index.tsx
similarity index 88%
rename from src/components/new-safe/steps/Step1/index.tsx
rename to src/components/new-safe/create/steps/Step1/index.tsx
index 0aae2b064f..543b208c7d 100644
--- a/src/components/new-safe/steps/Step1/index.tsx
+++ b/src/components/new-safe/create/steps/Step1/index.tsx
@@ -3,14 +3,14 @@ import { FormProvider, useForm } from 'react-hook-form'
import { useMnemonicSafeName } from '@/hooks/useMnemonicName'
import InfoIcon from '@/public/images/notifications/info.svg'
import NetworkSelector from '@/components/common/NetworkSelector'
-import type { StepRenderProps } from '../../CardStepper/useCardStepper'
-import type { NewSafeFormData } from '../../CreateSafe'
-import useSyncSafeCreationStep from '@/components/new-safe/CreateSafe/useSyncSafeCreationStep'
+import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
+import type { NewSafeFormData } from '@/components/new-safe/create'
+import useSyncSafeCreationStep from '@/components/new-safe/create/useSyncSafeCreationStep'
-import css from './styles.module.css'
-import layoutCss from '@/components/new-safe/CreateSafe/styles.module.css'
+import css from '@/components/new-safe/create/steps/Step1/styles.module.css'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
import useIsWrongChain from '@/hooks/useIsWrongChain'
-import NetworkWarning from '@/components/new-safe/NetworkWarning'
+import NetworkWarning from '@/components/new-safe/create/NetworkWarning'
import NameInput from '@/components/common/NameInput'
import { CREATE_SAFE_EVENTS, trackEvent } from '@/services/analytics'
import ExternalLink from '@/components/common/ExternalLink'
diff --git a/src/components/new-safe/steps/Step1/styles.module.css b/src/components/new-safe/create/steps/Step1/styles.module.css
similarity index 100%
rename from src/components/new-safe/steps/Step1/styles.module.css
rename to src/components/new-safe/create/steps/Step1/styles.module.css
diff --git a/src/components/new-safe/steps/Step2/index.tsx b/src/components/new-safe/create/steps/Step2/index.tsx
similarity index 89%
rename from src/components/new-safe/steps/Step2/index.tsx
rename to src/components/new-safe/create/steps/Step2/index.tsx
index f03e83f39c..8461ed6d06 100644
--- a/src/components/new-safe/steps/Step2/index.tsx
+++ b/src/components/new-safe/create/steps/Step2/index.tsx
@@ -4,19 +4,19 @@ import type { ReactElement } from 'react'
import AddIcon from '@/public/images/common/add.svg'
import InfoIcon from '@/public/images/notifications/info.svg'
-import { OwnerRow } from './OwnerRow'
import type { NamedAddress } from '@/components/create-safe/types'
-import type { StepRenderProps } from '../../CardStepper/useCardStepper'
-import type { NewSafeFormData } from '../../CreateSafe'
-import type { CreateSafeInfoItem } from '../../CreateSafeInfos'
-import { useSafeSetupHints } from './useSafeSetupHints'
-import useSyncSafeCreationStep from '@/components/new-safe/CreateSafe/useSyncSafeCreationStep'
+import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
+import type { NewSafeFormData } from '@/components/new-safe/create'
+import type { CreateSafeInfoItem } from '@/components/new-safe/create/CreateSafeInfos'
+import { useSafeSetupHints } from '@/components/new-safe/create/steps/Step2/useSafeSetupHints'
+import useSyncSafeCreationStep from '@/components/new-safe/create/useSyncSafeCreationStep'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
-import css from './styles.module.css'
-import layoutCss from '@/components/new-safe/CreateSafe/styles.module.css'
-import NetworkWarning from '@/components/new-safe/NetworkWarning'
+import css from '@/components/new-safe/create/steps/Step2/styles.module.css'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
+import NetworkWarning from '@/components/new-safe/create/NetworkWarning'
import useIsWrongChain from '@/hooks/useIsWrongChain'
import { CREATE_SAFE_EVENTS, trackEvent } from '@/services/analytics'
+import OwnerRow from '@/components/new-safe/OwnerRow'
enum CreateSafeStep2Fields {
owners = 'owners',
diff --git a/src/components/new-safe/steps/Step2/styles.module.css b/src/components/new-safe/create/steps/Step2/styles.module.css
similarity index 100%
rename from src/components/new-safe/steps/Step2/styles.module.css
rename to src/components/new-safe/create/steps/Step2/styles.module.css
diff --git a/src/components/new-safe/steps/Step2/useSafeSetupHints.ts b/src/components/new-safe/create/steps/Step2/useSafeSetupHints.ts
similarity index 92%
rename from src/components/new-safe/steps/Step2/useSafeSetupHints.ts
rename to src/components/new-safe/create/steps/Step2/useSafeSetupHints.ts
index dad2b00e39..c8b7c793e6 100644
--- a/src/components/new-safe/steps/Step2/useSafeSetupHints.ts
+++ b/src/components/new-safe/create/steps/Step2/useSafeSetupHints.ts
@@ -1,5 +1,5 @@
import { useEffect } from 'react'
-import type { CreateSafeInfoItem } from '../../CreateSafeInfos'
+import type { CreateSafeInfoItem } from '@/components/new-safe/create/CreateSafeInfos'
export const useSafeSetupHints = (
threshold: number,
diff --git a/src/components/new-safe/steps/Step3/index.tsx b/src/components/new-safe/create/steps/Step3/index.tsx
similarity index 88%
rename from src/components/new-safe/steps/Step3/index.tsx
rename to src/components/new-safe/create/steps/Step3/index.tsx
index 9f88a9e5b8..0b0fa354d0 100644
--- a/src/components/new-safe/steps/Step3/index.tsx
+++ b/src/components/new-safe/create/steps/Step3/index.tsx
@@ -1,4 +1,4 @@
-import { useMemo, type ReactElement } from 'react'
+import { useMemo } from 'react'
import { Button, Grid, Typography, Divider, Box } from '@mui/material'
import ChainIndicator from '@/components/common/ChainIndicator'
import EthHashInfo from '@/components/common/EthHashInfo'
@@ -7,33 +7,21 @@ import useGasPrice from '@/hooks/useGasPrice'
import { useEstimateSafeCreationGas } from '@/components/create-safe/useEstimateSafeCreationGas'
import { formatVisualAmount } from '@/utils/formatters'
import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
-import type { NewSafeFormData } from '@/components/new-safe/CreateSafe'
-import css from './styles.module.css'
-import layoutCss from '@/components/new-safe/CreateSafe/styles.module.css'
+import type { NewSafeFormData } from '@/components/new-safe/create'
+import css from '@/components/new-safe/create/steps/Step3/styles.module.css'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
import { getFallbackHandlerContractInstance } from '@/services/contracts/safeContracts'
import { computeNewSafeAddress } from '@/components/create-safe/logic'
import useWallet from '@/hooks/wallets/useWallet'
import { useWeb3 } from '@/hooks/wallets/web3'
import useLocalStorage from '@/services/local-storage/useLocalStorage'
-import { type PendingSafeData, SAFE_PENDING_CREATION_STORAGE_KEY } from '@/components/new-safe/steps/Step4'
-import useSyncSafeCreationStep from '@/components/new-safe/CreateSafe/useSyncSafeCreationStep'
+import { type PendingSafeData, SAFE_PENDING_CREATION_STORAGE_KEY } from '@/components/new-safe/create/steps/Step4'
+import useSyncSafeCreationStep from '@/components/new-safe/create/useSyncSafeCreationStep'
import ArrowBackIcon from '@mui/icons-material/ArrowBack'
-import NetworkWarning from '@/components/new-safe/NetworkWarning'
+import NetworkWarning from '@/components/new-safe/create/NetworkWarning'
import useIsWrongChain from '@/hooks/useIsWrongChain'
import palette from '@/styles/colors'
-
-const ReviewRow = ({ name, value }: { name: string; value: ReactElement }) => {
- return (
- <>
-
- {name}
-
-
- {value}
-
- >
- )
-}
+import ReviewRow from '@/components/new-safe/ReviewRow'
const CreateSafeStep3 = ({ data, onSubmit, onBack, setStep }: StepRenderProps) => {
const isWrongChain = useIsWrongChain()
diff --git a/src/components/new-safe/steps/Step3/styles.module.css b/src/components/new-safe/create/steps/Step3/styles.module.css
similarity index 81%
rename from src/components/new-safe/steps/Step3/styles.module.css
rename to src/components/new-safe/create/steps/Step3/styles.module.css
index 31a8389b86..e2b53bf895 100644
--- a/src/components/new-safe/steps/Step3/styles.module.css
+++ b/src/components/new-safe/create/steps/Step3/styles.module.css
@@ -2,4 +2,5 @@
display: flex;
flex-direction: column;
gap: var(--space-2);
+ font-size: 14px;
}
diff --git a/src/components/new-safe/steps/Step4/LoadingSpinner/index.tsx b/src/components/new-safe/create/steps/Step4/LoadingSpinner/index.tsx
similarity index 93%
rename from src/components/new-safe/steps/Step4/LoadingSpinner/index.tsx
rename to src/components/new-safe/create/steps/Step4/LoadingSpinner/index.tsx
index 2de0501100..f769059dc9 100644
--- a/src/components/new-safe/steps/Step4/LoadingSpinner/index.tsx
+++ b/src/components/new-safe/create/steps/Step4/LoadingSpinner/index.tsx
@@ -1,7 +1,7 @@
import { Box } from '@mui/material'
-import css from './styles.module.css'
+import css from '@/components/new-safe/create/steps/Step4/LoadingSpinner/styles.module.css'
import classnames from 'classnames'
-import { SafeCreationStatus } from '@/components/new-safe/steps/Step4/useSafeCreation'
+import { SafeCreationStatus } from '@/components/new-safe/create/steps/Step4/useSafeCreation'
import { useCallback, useEffect, useRef } from 'react'
const rectTlEndTransform = 'translateX(0) translateY(20px) scaleY(1.1)'
diff --git a/src/components/new-safe/steps/Step4/LoadingSpinner/styles.module.css b/src/components/new-safe/create/steps/Step4/LoadingSpinner/styles.module.css
similarity index 100%
rename from src/components/new-safe/steps/Step4/LoadingSpinner/styles.module.css
rename to src/components/new-safe/create/steps/Step4/LoadingSpinner/styles.module.css
diff --git a/src/components/new-safe/steps/Step4/StatusMessage.tsx b/src/components/new-safe/create/steps/Step4/StatusMessage.tsx
similarity index 93%
rename from src/components/new-safe/steps/Step4/StatusMessage.tsx
rename to src/components/new-safe/create/steps/Step4/StatusMessage.tsx
index fc70006930..161eff5666 100644
--- a/src/components/new-safe/steps/Step4/StatusMessage.tsx
+++ b/src/components/new-safe/create/steps/Step4/StatusMessage.tsx
@@ -1,6 +1,6 @@
import { Box, Typography } from '@mui/material'
-import { SafeCreationStatus } from './useSafeCreation'
-import LoadingSpinner from '@/components/new-safe/steps/Step4/LoadingSpinner'
+import { SafeCreationStatus } from '@/components/new-safe/create/steps/Step4/useSafeCreation'
+import LoadingSpinner from '@/components/new-safe/create/steps/Step4/LoadingSpinner'
const getStep = (status: SafeCreationStatus) => {
const ERROR_TEXT = 'Please cancel the process or retry the transaction.'
diff --git a/src/components/new-safe/steps/Step4/StatusStep.tsx b/src/components/new-safe/create/steps/Step4/StatusStep.tsx
similarity index 94%
rename from src/components/new-safe/steps/Step4/StatusStep.tsx
rename to src/components/new-safe/create/steps/Step4/StatusStep.tsx
index 7d68272dd2..8a82eec354 100644
--- a/src/components/new-safe/steps/Step4/StatusStep.tsx
+++ b/src/components/new-safe/create/steps/Step4/StatusStep.tsx
@@ -1,6 +1,6 @@
import type { ReactNode } from 'react'
import { Box, Skeleton, StepLabel, SvgIcon } from '@mui/material'
-import css from '@/components/new-safe/steps/Step4/styles.module.css'
+import css from '@/components/new-safe/create/steps/Step4/styles.module.css'
import CircleIcon from '@mui/icons-material/Circle'
import CircleOutlinedIcon from '@mui/icons-material/CircleOutlined'
import Identicon from '@/components/common/Identicon'
diff --git a/src/components/new-safe/steps/Step4/StatusStepper.tsx b/src/components/new-safe/create/steps/Step4/StatusStepper.tsx
similarity index 86%
rename from src/components/new-safe/steps/Step4/StatusStepper.tsx
rename to src/components/new-safe/create/steps/Step4/StatusStepper.tsx
index 81f7b77ac3..9e76107bc0 100644
--- a/src/components/new-safe/steps/Step4/StatusStepper.tsx
+++ b/src/components/new-safe/create/steps/Step4/StatusStepper.tsx
@@ -1,9 +1,9 @@
import { Box, Step, StepConnector, Stepper, Typography } from '@mui/material'
-import css from '@/components/new-safe/steps/Step4/styles.module.css'
+import css from '@/components/new-safe/create/steps/Step4/styles.module.css'
import EthHashInfo from '@/components/common/EthHashInfo'
-import { SafeCreationStatus } from '@/components/new-safe/steps/Step4/useSafeCreation'
-import type { PendingSafeData } from '@/components/new-safe/steps/Step4/index'
-import StatusStep from '@/components/new-safe/steps/Step4/StatusStep'
+import { SafeCreationStatus } from '@/components/new-safe/create/steps/Step4/useSafeCreation'
+import type { PendingSafeData } from '@/components/new-safe/create/steps/Step4/index'
+import StatusStep from '@/components/new-safe/create/steps/Step4/StatusStep'
const StatusStepper = ({ pendingSafe, status }: { pendingSafe: PendingSafeData; status: SafeCreationStatus }) => {
if (!pendingSafe?.safeAddress) return null
diff --git a/src/components/new-safe/steps/Step4/index.tsx b/src/components/new-safe/create/steps/Step4/index.tsx
similarity index 89%
rename from src/components/new-safe/steps/Step4/index.tsx
rename to src/components/new-safe/create/steps/Step4/index.tsx
index aa826347ae..9a2dab05b6 100644
--- a/src/components/new-safe/steps/Step4/index.tsx
+++ b/src/components/new-safe/create/steps/Step4/index.tsx
@@ -5,19 +5,19 @@ import { useRouter } from 'next/router'
import Track from '@/components/common/Track'
import { CREATE_SAFE_EVENTS } from '@/services/analytics/events/createLoadSafe'
import useLocalStorage from '@/services/local-storage/useLocalStorage'
-import StatusMessage from '@/components/new-safe/steps/Step4/StatusMessage'
+import StatusMessage from '@/components/new-safe/create/steps/Step4/StatusMessage'
import useWallet from '@/hooks/wallets/useWallet'
import useIsWrongChain from '@/hooks/useIsWrongChain'
-import type { NewSafeFormData } from '@/components/new-safe/CreateSafe'
+import type { NewSafeFormData } from '@/components/new-safe/create'
import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
-import type { PendingSafeTx } from '@/components/create-safe/types.d'
-import useSafeCreationEffects from '@/components/new-safe/steps/Step4/useSafeCreationEffects'
-import { SafeCreationStatus, useSafeCreation } from '@/components/new-safe/steps/Step4/useSafeCreation'
-import StatusStepper from '@/components/new-safe/steps/Step4/StatusStepper'
+import type { PendingSafeTx } from '@/components/create-safe/types'
+import useSafeCreationEffects from '@/components/new-safe/create/steps/Step4/useSafeCreationEffects'
+import { SafeCreationStatus, useSafeCreation } from '@/components/new-safe/create/steps/Step4/useSafeCreation'
+import StatusStepper from '@/components/new-safe/create/steps/Step4/StatusStepper'
import { trackEvent } from '@/services/analytics'
import useChainId from '@/hooks/useChainId'
-import { getRedirect } from '@/components/new-safe/steps/Step4/logic'
-import layoutCss from '@/components/new-safe/CreateSafe/styles.module.css'
+import { getRedirect } from '@/components/new-safe/create/steps/Step4/logic'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
import { AppRoutes } from '@/config/routes'
import palette from '@/styles/colors'
diff --git a/src/components/new-safe/steps/Step4/logic/index.ts b/src/components/new-safe/create/steps/Step4/logic/index.ts
similarity index 96%
rename from src/components/new-safe/steps/Step4/logic/index.ts
rename to src/components/new-safe/create/steps/Step4/logic/index.ts
index 442976b583..f34cc23bb0 100644
--- a/src/components/new-safe/steps/Step4/logic/index.ts
+++ b/src/components/new-safe/create/steps/Step4/logic/index.ts
@@ -3,13 +3,13 @@ import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { getProxyFactoryContractInstance } from '@/services/contracts/safeContracts'
import type { ConnectedWallet } from '@/services/onboard'
import { BigNumber } from '@ethersproject/bignumber'
-import { SafeCreationStatus } from '@/components/new-safe/steps/Step4/useSafeCreation'
+import { SafeCreationStatus } from '@/components/new-safe/create/steps/Step4/useSafeCreation'
import { didRevert, type EthersError } from '@/utils/ethers-utils'
import { Errors, logError } from '@/services/exceptions'
import { ErrorCode } from '@ethersproject/logger'
import { isWalletRejection } from '@/utils/wallets'
import type { PendingSafeTx } from '@/components/create-safe/types'
-import type { NewSafeFormData } from '@/components/new-safe/CreateSafe'
+import type { NewSafeFormData } from '@/components/new-safe/create'
import type { UrlObject } from 'url'
import chains from '@/config/chains'
import { AppRoutes } from '@/config/routes'
diff --git a/src/components/new-safe/steps/Step4/styles.module.css b/src/components/new-safe/create/steps/Step4/styles.module.css
similarity index 100%
rename from src/components/new-safe/steps/Step4/styles.module.css
rename to src/components/new-safe/create/steps/Step4/styles.module.css
diff --git a/src/components/new-safe/steps/Step4/useSafeCreation.ts b/src/components/new-safe/create/steps/Step4/useSafeCreation.ts
similarity index 96%
rename from src/components/new-safe/steps/Step4/useSafeCreation.ts
rename to src/components/new-safe/create/steps/Step4/useSafeCreation.ts
index 009c3531f1..8d6eeab384 100644
--- a/src/components/new-safe/steps/Step4/useSafeCreation.ts
+++ b/src/components/new-safe/create/steps/Step4/useSafeCreation.ts
@@ -4,7 +4,7 @@ import { useWeb3, useWeb3ReadOnly } from '@/hooks/wallets/web3'
import { useCurrentChain } from '@/hooks/useChains'
import useWallet from '@/hooks/wallets/useWallet'
import type { EthersError } from '@/utils/ethers-utils'
-import type { PendingSafeData } from '@/components/new-safe/steps/Step4/index'
+import type { PendingSafeData } from '@/components/new-safe/create/steps/Step4/index'
import type { PendingSafeTx } from '@/components/create-safe/types'
import {
checkSafeCreationTx,
@@ -12,7 +12,7 @@ import {
handleSafeCreationError,
SAFE_CREATION_ERROR_KEY,
showSafeCreationError,
-} from '@/components/new-safe/steps/Step4/logic'
+} from '@/components/new-safe/create/steps/Step4/logic'
import { useAppDispatch } from '@/store'
import { closeByGroupKey } from '@/store/notificationsSlice'
import { CREATE_SAFE_EVENTS, trackEvent } from '@/services/analytics'
diff --git a/src/components/new-safe/steps/Step4/useSafeCreationEffects.ts b/src/components/new-safe/create/steps/Step4/useSafeCreationEffects.ts
similarity index 92%
rename from src/components/new-safe/steps/Step4/useSafeCreationEffects.ts
rename to src/components/new-safe/create/steps/Step4/useSafeCreationEffects.ts
index 50515a5721..91c32c03ed 100644
--- a/src/components/new-safe/steps/Step4/useSafeCreationEffects.ts
+++ b/src/components/new-safe/create/steps/Step4/useSafeCreationEffects.ts
@@ -1,12 +1,12 @@
import type { Dispatch, SetStateAction } from 'react'
import { useEffect } from 'react'
import { pollSafeInfo } from '@/components/create-safe/logic'
-import { SafeCreationStatus } from '@/components/new-safe/steps/Step4/useSafeCreation'
+import { SafeCreationStatus } from '@/components/new-safe/create/steps/Step4/useSafeCreation'
import { CREATE_SAFE_EVENTS, trackEvent } from '@/services/analytics'
import { updateAddressBook } from '@/components/create-safe/logic/address-book'
import { useAppDispatch } from '@/store'
import useChainId from '@/hooks/useChainId'
-import type { PendingSafeData } from '@/components/new-safe/steps/Step4/index'
+import type { PendingSafeData } from '@/components/new-safe/create/steps/Step4/index'
const useSafeCreationEffects = ({
pendingSafe,
diff --git a/src/components/new-safe/CreateSafe/styles.module.css b/src/components/new-safe/create/styles.module.css
similarity index 100%
rename from src/components/new-safe/CreateSafe/styles.module.css
rename to src/components/new-safe/create/styles.module.css
diff --git a/src/components/new-safe/CreateSafe/useSyncSafeCreationStep.ts b/src/components/new-safe/create/useSyncSafeCreationStep.ts
similarity index 81%
rename from src/components/new-safe/CreateSafe/useSyncSafeCreationStep.ts
rename to src/components/new-safe/create/useSyncSafeCreationStep.ts
index 0ada098a50..8e64022730 100644
--- a/src/components/new-safe/CreateSafe/useSyncSafeCreationStep.ts
+++ b/src/components/new-safe/create/useSyncSafeCreationStep.ts
@@ -1,9 +1,9 @@
import { useEffect } from 'react'
import useLocalStorage from '@/services/local-storage/useLocalStorage'
import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
-import type { PendingSafeData } from '@/components/new-safe/steps/Step4'
-import type { NewSafeFormData } from '@/components/new-safe/CreateSafe/index'
-import { SAFE_PENDING_CREATION_STORAGE_KEY } from '@/components/new-safe/steps/Step4'
+import type { PendingSafeData } from '@/components/new-safe/create/steps/Step4'
+import type { NewSafeFormData } from '@/components/new-safe/create/index'
+import { SAFE_PENDING_CREATION_STORAGE_KEY } from '@/components/new-safe/create/steps/Step4'
import useWallet from '@/hooks/wallets/useWallet'
const useSyncSafeCreationStep = (setStep: StepRenderProps['setStep']) => {
diff --git a/src/components/new-safe/load/index.tsx b/src/components/new-safe/load/index.tsx
new file mode 100644
index 0000000000..52ade6fd2d
--- /dev/null
+++ b/src/components/new-safe/load/index.tsx
@@ -0,0 +1,75 @@
+import React from 'react'
+import { useRouter } from 'next/router'
+
+import { LOAD_SAFE_CATEGORY } from '@/services/analytics'
+import { Container, Grid, Typography } from '@mui/material'
+import { CardStepper } from '@/components/new-safe/CardStepper'
+import type { TxStepperProps } from '@/components/new-safe/CardStepper/useCardStepper'
+import type { NamedAddress } from '@/components/create-safe/types'
+import SetAddressStep from '@/components/new-safe/load/steps/SetAddressStep'
+import { AppRoutes } from '@/config/routes'
+import SafeOwnerStep from '@/components/new-safe/load/steps/SafeOwnerStep'
+import SafeReviewStep from '@/components/new-safe/load/steps/SafeReviewStep'
+
+export type LoadSafeFormData = NamedAddress & {
+ threshold: number
+ owners: NamedAddress[]
+}
+
+export const LoadSafeSteps: TxStepperProps['steps'] = [
+ {
+ title: 'Connect wallet & select network',
+ subtitle: 'Select network on which the Safe was created',
+ render: (_, onSubmit, onBack, setStep) => (
+
+ ),
+ },
+ {
+ title: 'Owners and confirmations',
+ subtitle: 'Optional: Provide a name for each owner.',
+ render: (data, onSubmit, onBack, setStep) => (
+
+ ),
+ },
+ {
+ title: 'Review',
+ subtitle: 'Confirm loading Safe.',
+ render: (data, onSubmit, onBack, setStep) => (
+
+ ),
+ },
+]
+
+export const loadSafeDefaultData = { threshold: -1, owners: [], address: '', name: '' }
+
+const LoadSafe = ({ initialData }: { initialData?: TxStepperProps['initialData'] }) => {
+ const router = useRouter()
+
+ const onClose = () => {
+ router.push(AppRoutes.welcome)
+ }
+
+ const initialSafe = initialData ?? loadSafeDefaultData
+
+ return (
+
+
+
+
+ Load Safe
+
+
+
+
+
+
+
+ )
+}
+
+export default LoadSafe
diff --git a/src/components/new-safe/load/steps/SafeOwnerStep/index.tsx b/src/components/new-safe/load/steps/SafeOwnerStep/index.tsx
new file mode 100644
index 0000000000..68ba7d1cbb
--- /dev/null
+++ b/src/components/new-safe/load/steps/SafeOwnerStep/index.tsx
@@ -0,0 +1,91 @@
+import React, { useEffect } from 'react'
+import { getSafeInfo, type SafeInfo } from '@safe-global/safe-gateway-typescript-sdk'
+import { FormProvider, useFieldArray, useForm } from 'react-hook-form'
+import { Box, Button, Divider } from '@mui/material'
+
+import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
+import type { LoadSafeFormData } from '@/components/new-safe/load'
+import useAsync from '@/hooks/useAsync'
+import useChainId from '@/hooks/useChainId'
+import type { NamedAddress } from '@/components/create-safe/types'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
+import ArrowBackIcon from '@mui/icons-material/ArrowBack'
+import { OwnerRow } from '@/components/new-safe/OwnerRow'
+
+enum Field {
+ owners = 'owners',
+ threshold = 'threshold',
+}
+
+type FormData = {
+ [Field.owners]: NamedAddress[]
+ [Field.threshold]: number
+}
+
+const SafeOwnerStep = ({ data, onSubmit, onBack }: StepRenderProps) => {
+ const chainId = useChainId()
+ const formMethods = useForm({
+ defaultValues: data,
+ mode: 'onChange',
+ })
+ const {
+ handleSubmit,
+ setValue,
+ control,
+ formState: { isValid },
+ getValues,
+ } = formMethods
+
+ const { fields } = useFieldArray({
+ control,
+ name: Field.owners,
+ })
+
+ const [safeInfo] = useAsync(() => {
+ if (data.address) {
+ return getSafeInfo(chainId, data.address)
+ }
+ }, [chainId, data.address])
+
+ useEffect(() => {
+ if (!safeInfo) return
+
+ setValue(Field.threshold, safeInfo.threshold)
+
+ const owners = safeInfo.owners.map((owner, i) => ({
+ address: owner.value,
+ name: getValues(`owners.${i}.name`) || '',
+ }))
+
+ setValue(Field.owners, owners)
+ }, [getValues, safeInfo, setValue])
+
+ const handleBack = () => {
+ onBack(getValues())
+ }
+
+ return (
+
+
+
+ )
+}
+
+export default SafeOwnerStep
diff --git a/src/components/new-safe/load/steps/SafeReviewStep/index.tsx b/src/components/new-safe/load/steps/SafeReviewStep/index.tsx
new file mode 100644
index 0000000000..304d5ebe9a
--- /dev/null
+++ b/src/components/new-safe/load/steps/SafeReviewStep/index.tsx
@@ -0,0 +1,142 @@
+import React from 'react'
+import { Box, Button, Divider, Grid, Typography } from '@mui/material'
+
+import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
+import type { LoadSafeFormData } from '@/components/new-safe/load'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
+import ArrowBackIcon from '@mui/icons-material/ArrowBack'
+import ChainIndicator from '@/components/common/ChainIndicator'
+import css from '@/components/new-safe/create/steps/Step3/styles.module.css'
+import EthHashInfo from '@/components/common/EthHashInfo'
+import { useCurrentChain } from '@/hooks/useChains'
+import { useAppDispatch } from '@/store'
+import { useRouter } from 'next/router'
+import { addOrUpdateSafe } from '@/store/addedSafesSlice'
+import { defaultSafeInfo } from '@/store/safeInfoSlice'
+import { upsertAddressBookEntry } from '@/store/addressBookSlice'
+import { LOAD_SAFE_EVENTS, trackEvent } from '@/services/analytics'
+import { AppRoutes } from '@/config/routes'
+import ReviewRow from '@/components/new-safe/ReviewRow'
+
+const SafeReviewStep = ({ data, onBack }: StepRenderProps) => {
+ const chain = useCurrentChain()
+ const dispatch = useAppDispatch()
+ const router = useRouter()
+ const chainId = chain?.chainId || ''
+
+ const addSafe = () => {
+ const safeName = data.name
+ const safeAddress = data.address
+
+ dispatch(
+ addOrUpdateSafe({
+ safe: {
+ ...defaultSafeInfo,
+ address: { value: safeAddress, name: safeName },
+ threshold: data.threshold,
+ owners: data.owners.map((owner) => ({
+ value: owner.address,
+ name: owner.name || owner.ens,
+ })),
+ chainId,
+ },
+ }),
+ )
+
+ dispatch(
+ upsertAddressBookEntry({
+ chainId,
+ address: safeAddress,
+ name: safeName,
+ }),
+ )
+
+ for (const { address, name, ens } of data.owners) {
+ const entryName = name || ens
+
+ if (!entryName) {
+ continue
+ }
+
+ dispatch(
+ upsertAddressBookEntry({
+ chainId,
+ address,
+ name: entryName,
+ }),
+ )
+ }
+
+ trackEvent({
+ ...LOAD_SAFE_EVENTS.OWNERS,
+ label: data.owners.length,
+ })
+
+ trackEvent({
+ ...LOAD_SAFE_EVENTS.THRESHOLD,
+ label: data.threshold,
+ })
+
+ trackEvent(LOAD_SAFE_EVENTS.GO_TO_SAFE)
+
+ router.push({
+ pathname: AppRoutes.home,
+ query: { safe: `${chain?.shortName}:${safeAddress}` },
+ })
+ }
+
+ const handleBack = () => {
+ onBack(data)
+ }
+
+ return (
+ <>
+
+
+ } />
+ {data.name}} />
+
+ {data.owners.map((owner, index) => (
+
+ ))}
+
+ }
+ />
+
+ {data.threshold} out of {data.owners.length} owner(s)
+
+ }
+ />
+
+
+
+
+
+ }>
+ Back
+
+
+
+
+ >
+ )
+}
+
+export default SafeReviewStep
diff --git a/src/components/new-safe/load/steps/SetAddressStep/index.tsx b/src/components/new-safe/load/steps/SetAddressStep/index.tsx
new file mode 100644
index 0000000000..85952f8333
--- /dev/null
+++ b/src/components/new-safe/load/steps/SetAddressStep/index.tsx
@@ -0,0 +1,161 @@
+import type { StepRenderProps } from '@/components/new-safe/CardStepper/useCardStepper'
+import type { LoadSafeFormData } from '@/components/new-safe/load'
+import { FormProvider, useForm } from 'react-hook-form'
+import {
+ Box,
+ Button,
+ CircularProgress,
+ Divider,
+ Grid,
+ InputAdornment,
+ SvgIcon,
+ Tooltip,
+ Typography,
+} from '@mui/material'
+import layoutCss from '@/components/new-safe/create/styles.module.css'
+import NameInput from '@/components/common/NameInput'
+import InfoIcon from '@/public/images/notifications/info.svg'
+import css from '@/components/new-safe/create/steps/Step1/styles.module.css'
+import NetworkSelector from '@/components/common/NetworkSelector'
+import { useMnemonicSafeName } from '@/hooks/useMnemonicName'
+import { useAddressResolver } from '@/hooks/useAddressResolver'
+import ArrowBackIcon from '@mui/icons-material/ArrowBack'
+import AddressInput from '@/components/common/AddressInput'
+import React from 'react'
+import { getSafeInfo } from '@safe-global/safe-gateway-typescript-sdk'
+import useChainId from '@/hooks/useChainId'
+import { useAppSelector } from '@/store'
+import { selectAddedSafes } from '@/store/addedSafesSlice'
+import { LOAD_SAFE_EVENTS, trackEvent } from '@/services/analytics'
+import ExternalLink from '@/components/common/ExternalLink'
+
+enum Field {
+ name = 'name',
+ address = 'address',
+}
+
+type FormData = {
+ [Field.name]: string
+ [Field.address]: string
+}
+
+const SetAddressStep = ({ data, onSubmit, onBack }: StepRenderProps) => {
+ const currentChainId = useChainId()
+ const addedSafes = useAppSelector((state) => selectAddedSafes(state, currentChainId))
+ const formMethods = useForm({
+ mode: 'all',
+ defaultValues: {
+ [Field.name]: data.name,
+ [Field.address]: data.address,
+ },
+ })
+
+ const {
+ handleSubmit,
+ formState: { errors, isValid },
+ watch,
+ getValues,
+ } = formMethods
+
+ const safeAddress = watch(Field.address)
+
+ const randomName = useMnemonicSafeName()
+ const { ens, name, resolving } = useAddressResolver(safeAddress)
+
+ // Address book, ENS, mnemonic
+ const fallbackName = name || ens || randomName
+
+ const validateSafeAddress = async (address: string) => {
+ if (addedSafes && Object.keys(addedSafes).includes(address)) {
+ return 'Safe is already added'
+ }
+
+ try {
+ await getSafeInfo(currentChainId, address)
+ } catch (error) {
+ return 'Address given is not a valid Safe address'
+ }
+ }
+
+ const onFormSubmit = handleSubmit((data: FormData) => {
+ onSubmit({
+ ...data,
+ [Field.name]: data[Field.name] || fallbackName,
+ })
+
+ if (data[Field.name]) {
+ trackEvent(LOAD_SAFE_EVENTS.NAME_SAFE)
+ }
+ })
+
+ const handleBack = () => {
+ const formData = getValues()
+ onBack({
+ ...formData,
+ [Field.name]: formData.name || fallbackName,
+ })
+ }
+
+ return (
+
+
+
+ )
+}
+
+export default SetAddressStep
diff --git a/src/components/safe-apps/SafeAppLandingPage/AppActions.tsx b/src/components/safe-apps/SafeAppLandingPage/AppActions.tsx
index 1808aced5b..81c88dda63 100644
--- a/src/components/safe-apps/SafeAppLandingPage/AppActions.tsx
+++ b/src/components/safe-apps/SafeAppLandingPage/AppActions.tsx
@@ -71,7 +71,7 @@ const AppActions = ({ wallet, onConnectWallet, chain, appUrl, app }: Props): Rea
case shouldCreateSafe:
const redirect = `${AppRoutes.apps}?appUrl=${appUrl}`
const createSafeHrefWithRedirect: UrlObject = {
- pathname: AppRoutes.open,
+ pathname: AppRoutes.newSafe.create,
query: { safeViewRedirectURL: redirect, chain: chain.shortName },
}
button = (
diff --git a/src/components/sidebar/SafeListItem/index.tsx b/src/components/sidebar/SafeListItem/index.tsx
index 0a932a9189..a87aea66b0 100644
--- a/src/components/sidebar/SafeListItem/index.tsx
+++ b/src/components/sidebar/SafeListItem/index.tsx
@@ -64,7 +64,7 @@ const SafeListItem = ({
address={address}
onClick={closeDrawer}
href={{
- pathname: AppRoutes.load,
+ pathname: AppRoutes.newSafe.load,
query: { chain: shortName, address },
}}
/>
diff --git a/src/components/welcome/index.tsx b/src/components/welcome/index.tsx
index 99160f9e6c..01c8732874 100644
--- a/src/components/welcome/index.tsx
+++ b/src/components/welcome/index.tsx
@@ -29,7 +29,7 @@ const NewSafe = () => {
for creating your new Safe.
@@ -44,7 +44,7 @@ const NewSafe = () => {
address.
diff --git a/src/config/routes.ts b/src/config/routes.ts
index 2e82d827c8..6fd0bfd99d 100644
--- a/src/config/routes.ts
+++ b/src/config/routes.ts
@@ -1,8 +1,6 @@
export const AppRoutes = {
'404': '/404',
welcome: '/welcome',
- open: '/open',
- load: '/load',
index: '/',
import: '/import',
home: '/home',
@@ -14,6 +12,7 @@ export const AppRoutes = {
},
newSafe: {
create: '/new-safe/create',
+ load: '/new-safe/load',
},
settings: {
spendingLimits: '/settings/spending-limits',
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 2a52c4c6fa..ac98f28c18 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,16 +1,18 @@
-import { useLayoutEffect } from 'react'
+import { useEffect, useLayoutEffect } from 'react'
import type { NextPage } from 'next'
import { useRouter } from 'next/router'
import useLastSafe from '@/hooks/useLastSafe'
import { AppRoutes } from '@/config/routes'
+const useIsomorphicEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect
+
const IndexPage: NextPage = () => {
const router = useRouter()
const { safe, chain } = router.query
const lastSafe = useLastSafe()
const safeAddress = safe || lastSafe
- useLayoutEffect(() => {
+ useIsomorphicEffect(() => {
router.replace(
safeAddress
? `${AppRoutes.home}?safe=${safeAddress}`
diff --git a/src/pages/new-safe/create.tsx b/src/pages/new-safe/create.tsx
index e158c36424..5327d3c5b8 100644
--- a/src/pages/new-safe/create.tsx
+++ b/src/pages/new-safe/create.tsx
@@ -1,7 +1,7 @@
import Head from 'next/head'
import type { NextPage } from 'next'
-import CreateSafe from '@/components/new-safe/CreateSafe'
+import CreateSafe from '@/components/new-safe/create'
const Open: NextPage = () => {
return (
diff --git a/src/pages/load.tsx b/src/pages/new-safe/load.tsx
similarity index 65%
rename from src/pages/load.tsx
rename to src/pages/new-safe/load.tsx
index 4cd8af13dd..882f2950a0 100644
--- a/src/pages/load.tsx
+++ b/src/pages/new-safe/load.tsx
@@ -1,7 +1,7 @@
import type { NextPage } from 'next'
import Head from 'next/head'
import { useRouter } from 'next/router'
-import LoadSafe from '@/components/load-safe'
+import LoadSafe, { loadSafeDefaultData } from '@/components/new-safe/load'
const Load: NextPage = () => {
const router = useRouter()
@@ -15,9 +15,9 @@ const Load: NextPage = () => {
{safeAddress ? (
-
+
) : (
-
+
)}
)
diff --git a/src/pages/open.tsx b/src/pages/open.tsx
deleted file mode 100644
index 5ca00b96ec..0000000000
--- a/src/pages/open.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import type { NextPage } from 'next'
-import Head from 'next/head'
-import CreateSafe from '@/components/create-safe'
-import { useRouter } from 'next/router'
-import useABTesting from '@/services/tracking/useABTesting'
-import { AbTest } from '@/services/tracking/abTesting'
-import { useLayoutEffect } from 'react'
-import { AppRoutes } from '@/config/routes'
-
-const Open: NextPage = () => {
- const shouldUseNewCreation = useABTesting(AbTest.SAFE_CREATION)
- const router = useRouter()
-
- useLayoutEffect(() => {
- if (shouldUseNewCreation) {
- router.replace(AppRoutes.newSafe.create)
- }
- }, [router, shouldUseNewCreation])
-
- if (shouldUseNewCreation) {
- return <>>
- }
-
- return (
-
-
- Safe – Create Safe
-
-
-
-
- )
-}
-
-export default Open