Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review step redesign #993

Merged
merged 10 commits into from
Oct 28, 2022
6 changes: 6 additions & 0 deletions src/components/new-safe/CreateSafe/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Card, CardContent, Typography } from '@mui/material'
import { useRouter } from 'next/router'
import { AppRoutes } from '@/config/routes'
import { CREATE_SAFE_CATEGORY } from '@/services/analytics'
import CreateSafeStep3 from '@/components/new-safe/steps/Step3'

export type NewSafeFormData = {
name: string
Expand All @@ -33,6 +34,11 @@ export const CreateSafeSteps: TxStepperProps<NewSafeFormData>['steps'] = [
'Here you can add owners to your Safe and determine how many owners need to confirm before making a successful transaction',
render: (data, onSubmit, onBack) => <CreateSafeStep2 onSubmit={onSubmit} onBack={onBack} data={data} />,
},
{
title: 'Review',
subtitle: `You're about to create a new Safe and will have to confirm a transaction with your currently connected wallet.`,
render: (data, onSubmit, onBack) => <CreateSafeStep3 onSubmit={onSubmit} onBack={onBack} data={data} />,
},
]

const CreateSafe = () => {
Expand Down
44 changes: 21 additions & 23 deletions src/components/new-safe/StepCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,32 @@ const StepCard = ({
subheader,
content,
actions,
step = 1,
}: {
title: string
subheader: string
content: ReactElement
actions: ReactElement
}): ReactElement => {
// TODO: `step` and `LinearProgress` will be set via stepper hook
const step = 1

return (
<Card className={css.card}>
<LinearProgress />
<CardHeader
title={title}
subheader={subheader}
titleTypographyProps={{ variant: 'h4' }}
subheaderTypographyProps={{ variant: 'body2' }}
avatar={
<Avatar className={css.step}>
<Typography variant="body2">{step}</Typography>
</Avatar>
}
className={css.header}
/>
<CardContent className={css.content}>{content}</CardContent>
<CardActions className={css.actions}>{actions}</CardActions>
</Card>
)
}
step?: number
}): ReactElement => (
<Card className={css.card}>
<LinearProgress />
<CardHeader
title={title}
subheader={subheader}
titleTypographyProps={{ variant: 'h4' }}
subheaderTypographyProps={{ variant: 'body2' }}
avatar={
<Avatar className={css.step}>
<Typography variant="body2">{step}</Typography>
</Avatar>
}
className={css.header}
/>
<CardContent className={css.content}>{content}</CardContent>
<CardActions className={css.actions}>{actions}</CardActions>
</Card>
)

export default StepCard
1 change: 0 additions & 1 deletion src/components/new-safe/steps/Step2/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ const CreateSafeStep2 = ({
const { register, handleSubmit, control, watch } = formMethods

const allFormData = watch()
const currentThreshold = watch(CreateSafeStep2Fields.threshold)

const { fields: ownerFields, append: appendOwner, remove: removeOwner } = useFieldArray({ control, name: 'owners' })

Expand Down
162 changes: 162 additions & 0 deletions src/components/new-safe/steps/Step3/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { useMemo, type ReactElement } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { Button, Grid, Typography, Divider, Box } from '@mui/material'
import ChainIndicator from '@/components/common/ChainIndicator'
import EthHashInfo from '@/components/common/EthHashInfo'
import type { NamedAddress } from '@/components/create-safe/types'
import { useCurrentChain } from '@/hooks/useChains'
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'

enum CreateSafeStep3Fields {
name = 'name',
owners = 'owners',
threshold = 'threshold',
}

type CreateSafeStep3Form = {
name: string
owners: NamedAddress[]
threshold: number
networkFee: string
}

const STEP_3_FORM_ID = 'create-safe-step-3-form'

const ReviewRow = ({ name, value }: { name: string; value: ReactElement }) => {
return (
<>
<Grid item xs={3}>
<Typography variant="body2">{name}</Typography>
</Grid>
<Grid item xs={9}>
{value}
</Grid>
</>
)
}

const CreateSafeStep3 = ({
onSubmit,
onBack,
data,
}: Pick<StepRenderProps<NewSafeFormData>, 'onSubmit' | 'data' | 'onBack'>): ReactElement => {
const chain = useCurrentChain()
const { maxFeePerGas, maxPriorityFeePerGas } = useGasPrice()
const saltNonce = useMemo(() => Date.now(), [])

const safeParams = useMemo(() => {
return {
owners: data.owners.map((owner) => owner.address),
threshold: data.threshold,
saltNonce,
}
}, [data.owners, data.threshold, saltNonce])

const { gasLimit } = useEstimateSafeCreationGas(safeParams)

const totalFee =
gasLimit && maxFeePerGas && maxPriorityFeePerGas
? formatVisualAmount(maxFeePerGas.add(maxPriorityFeePerGas).mul(gasLimit), chain?.nativeCurrency.decimals)
: '> 0.001'

const formMethods = useForm<CreateSafeStep3Form>({
mode: 'all',
defaultValues: {
[CreateSafeStep3Fields.name]: data.name,
[CreateSafeStep3Fields.owners]: data.owners,
[CreateSafeStep3Fields.threshold]: data.threshold,
},
})

const { handleSubmit, getValues } = formMethods

const allFormData = getValues()

const handleBack = () => {
onBack(allFormData)
}

return (
<form onSubmit={handleSubmit(onSubmit)} id={STEP_3_FORM_ID}>
<FormProvider {...formMethods}>
<Grid container spacing={3}>
<Grid item>
<Grid container spacing={3}>
<ReviewRow name="Network" value={<ChainIndicator chainId={chain?.chainId} inline />} />
<ReviewRow name="Name" value={<Typography>{data.name}</Typography>} />
<ReviewRow
name="Owners"
value={
<Box className={css.ownersArray}>
{data.owners.map((owner, index) => (
<EthHashInfo
address={owner.address}
name={owner.name || owner.ens}
shortAddress={false}
showPrefix={false}
showName
key={index}
/>
))}
</Box>
}
/>
<ReviewRow
name="Threshold"
value={
<Typography>
{data.threshold} out of {data.owners.length} owner(s)
</Typography>
}
/>
</Grid>
</Grid>

<Grid item xs={12}>
<Divider sx={{ ml: '-52px', mr: '-52px', mb: 4, mt: 3 }} />
<Grid item xs={12}>
<Grid container spacing={3}>
<ReviewRow
name="Est. network fee"
value={
<Box p={1} sx={{ backgroundColor: 'secondary.background', width: 'fit-content' }}>
<Typography variant="body1">
<b>
&asymp; {totalFee} {chain?.nativeCurrency.symbol}
</b>
</Typography>
</Box>
}
/>
<Grid xs={3} />
<Grid xs={9} pt={1} pl={3}>
<Typography color="text.secondary">
You will have to confirm a transaction with your currently connected wallet.
</Typography>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Divider sx={{ ml: '-52px', mr: '-52px', mb: 4, mt: 3, alignSelf: 'normal' }} />
<Box display="flex" flexDirection="row" gap={3}>
<Button variant="outlined" onClick={handleBack}>
Back
</Button>
<Button type="submit" variant="contained">
Continue
</Button>
</Box>
</Grid>
</Grid>
</FormProvider>
</form>
)
}

export default CreateSafeStep3
5 changes: 5 additions & 0 deletions src/components/new-safe/steps/Step3/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.ownersArray {
display: flex;
flex-direction: column;
gap: var(--space-2);
}