Skip to content

Commit

Permalink
[Create Safe] add overview and CreateSafeInfo widget (#1002)
Browse files Browse the repository at this point in the history
* add overview and CreateSafeInfo widget

- displays safe name and connected wallet during owner setup
- displays hints for each step + dynamic hints during owner and threshold setup
- state is pulled up into the CreateSafe component and update functions passed into the owner step

* step static tips are collapsed by default

* navigate tips logic

* reverse expanded logic

* restyle InfoWidget

* remove the add mobile owner row

* remove flickering when opening the accordion

* fix keys

* add hover style to the Accordion expand icon

* Accordion summary bold when expanded

* style: PR comments

* fix empty form data name

* simplify map key

* link to Safe setup article

* change allOwners logic

* mv sx to css modules

* add current chain in Overview widget

Co-authored-by: Diogo Soares <diogo.lsoares@gmail.com>
  • Loading branch information
schmanu and DiogoSoaress authored Nov 3, 2022
1 parent 9be5b07 commit 6b05e27
Show file tree
Hide file tree
Showing 9 changed files with 339 additions and 176 deletions.
106 changes: 45 additions & 61 deletions src/components/create-safe/InfoWidget/index.tsx
Original file line number Diff line number Diff line change
@@ -1,84 +1,68 @@
import { Box, Button, Card, CardActions, CardContent, CardHeader, SvgIcon, Typography } from '@mui/material'
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'
import { useState } from 'react'
import {
Accordion,
AccordionDetails,
AccordionSummary,
Box,
Card,
CardContent,
CardHeader,
IconButton,
SvgIcon,
Typography,
} from '@mui/material'
import type { AlertColor } from '@mui/material'
import type { ReactElement } from 'react'

import LightbulbIcon from '@/public/images/common/lightbulb.svg'

import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import css from './styles.module.css'

type Props = {
type InfoWidgetProps = {
title: string
steps: { title: string; text: string }[]
steps: { title: string; text: string | ReactElement }[]
variant: AlertColor
startExpanded?: boolean
}

const InfoWidget = ({ title, steps, variant }: Props): ReactElement | null => {
const [activeStep, setActiveStep] = useState(0)
const [dismissed, setDismissed] = useState(false)

const isFirst = activeStep === 0
const isLast = activeStep === steps.length - 1

const isMultiStep = steps.length > 1

const onPrev = () => {
if (!isFirst) {
setActiveStep((prev) => prev - 1)
}
}

const onNext = () => {
if (isLast) {
setDismissed(true)
} else {
setActiveStep((prev) => prev + 1)
}
}

if (dismissed) {
const InfoWidget = ({ title, steps, variant, startExpanded = false }: InfoWidgetProps): ReactElement | null => {
if (steps.length === 0) {
return null
}

return (
<Card sx={{ backgroundColor: ({ palette }) => palette[variant]?.background }}>
<CardHeader
className={css.header}
className={css.cardHeader}
title={
<Box className={css.headerWrapper}>
<Typography
variant="caption"
className={css.title}
sx={{
backgroundColor: ({ palette }) => palette[variant]?.main,
}}
>
<SvgIcon component={LightbulbIcon} inheritViewBox fontSize="inherit" className={css.lightbulb} />
{title}
<Box className={css.title} sx={{ backgroundColor: ({ palette }) => palette[variant]?.main }}>
<SvgIcon component={LightbulbIcon} inheritViewBox className={css.titleIcon} />
<Typography variant="caption">
<b>{title}</b>
</Typography>
{isMultiStep && (
<Typography variant="caption" className={css.count}>
{activeStep + 1} of {steps.length}
</Typography>
)}
</Box>
}
/>
<CardContent>
<Typography variant="h5">{steps[activeStep].title}</Typography>
<Typography variant="body2">{steps[activeStep].text}</Typography>
</CardContent>
<CardActions className={css.actions}>
{isMultiStep && !isFirst && (
<Button variant="contained" size="small" onClick={onPrev} startIcon={<ChevronLeftIcon />}>
Previous
</Button>
)}
<Button variant="outlined" size="small" onClick={onNext}>
Got it
</Button>
</CardActions>
<Box className={css.tipsList}>
<CardContent>
{steps.map(({ title, text }) => {
return (
<Accordion key={title} className={css.tipAccordion} defaultExpanded={startExpanded}>
<AccordionSummary
expandIcon={
<IconButton sx={{ '&:hover': { background: ({ palette }) => palette[variant]?.light } }}>
<ExpandMoreIcon sx={{ color: ({ palette }) => palette[variant]?.main }} />
</IconButton>
}
>
{title}
</AccordionSummary>
<AccordionDetails>
<Typography variant="body2">{text}</Typography>
</AccordionDetails>
</Accordion>
)
})}
</CardContent>
</Box>
</Card>
)
}
Expand Down
40 changes: 24 additions & 16 deletions src/components/create-safe/InfoWidget/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
.header {
.cardHeader {
padding-bottom: 0px;
}

.headerWrapper {
display: flex;
justify-content: space-between;
align-items: center;
}

.title {
font-weight: 700;
padding: calc(var(--space-1) / 2) var(--space-1);
width:fit-content;
padding: 4px var(--space-1);
border-radius: 6px;
display: flex;
align-items: center;
gap: 4px;
}

.lightbulb {
margin-right: calc(var(--space-1) / 2);
.titleIcon {
font-size: 12px;
}

.count {
color: var(--color-text-secondary);
.tipsList :global .MuiCardContent-root {
padding: 0;
}

.actions {
display: flex;
justify-content: flex-end;
.tipAccordion {
background-color: inherit;
border: none;
}

.tipAccordion :global .MuiAccordionSummary-root:hover {
background: inherit;
}

.tipAccordion :global .Mui-expanded.MuiAccordionSummary-root {
background: inherit;
font-weight: bold;
}

.tipAccordion :global .MuiAccordionDetails-root {
padding-top: 0;
}
7 changes: 6 additions & 1 deletion src/components/new-safe/CardStepper/useCardStepper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ReactElement } from 'react'
import type { ReactElement, SetStateAction } from 'react'
import { useState } from 'react'
import { trackEvent, MODALS_CATEGORY } from '@/services/analytics'

Expand All @@ -25,6 +25,7 @@ export type TxStepperProps<TData> = {
initialData: TData
initialStep?: number
eventCategory?: string
setWidgetStep?: (step: number | SetStateAction<number>) => void
onClose: () => void
}

Expand All @@ -34,17 +35,20 @@ export const useCardStepper = <TData>({
initialStep,
eventCategory = MODALS_CATEGORY,
onClose,
setWidgetStep,
}: TxStepperProps<TData>) => {
const [activeStep, setActiveStep] = useState<number>(initialStep || 0)
const [stepData, setStepData] = useState(initialData)

const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1)
setWidgetStep && setWidgetStep((prevActiveStep) => prevActiveStep + 1)
trackEvent({ category: eventCategory, action: lastStep ? 'Submit' : 'Next' })
}

const handleBack = (data?: Partial<TData>) => {
setActiveStep((prevActiveStep) => prevActiveStep - 1)
setWidgetStep && setWidgetStep((prevActiveStep) => prevActiveStep - 1)
trackEvent({ category: eventCategory, action: firstStep ? 'Cancel' : 'Back' })

if (data) {
Expand All @@ -54,6 +58,7 @@ export const useCardStepper = <TData>({

const setStep = (step: number) => {
setActiveStep(step)
setWidgetStep && setWidgetStep(step)
}

const firstStep = activeStep === 0
Expand Down
Loading

0 comments on commit 6b05e27

Please sign in to comment.