Skip to content

Commit

Permalink
Review step redesign (#993)
Browse files Browse the repository at this point in the history
* feat: new create safe review step

* calculate total gas fee

* fill the form values

* refactor review rows

* fix: implement Figma designs

* fix: background-color on network fee

* avoid infinite rerendering

* integrate review step in new Stepper

* style: visual tweaks
  • Loading branch information
DiogoSoaress authored Oct 28, 2022
1 parent 0b379c7 commit 7ac11b1
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 24 deletions.
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);
}

0 comments on commit 7ac11b1

Please sign in to comment.