Feature #739: Deployment screen improvements (#908)

* Dep bump

* add deps to useEffect hook

* Revert "Dep bump"

This reverts commit f22795296cd7989ecda594ffef4478c2f5d92911.

* fix / redirect

* Fix currency fetch 400 error

* extract tab labels to components

* fix currency dropdown not showing, rename DropdownCurrency component to CurrencyDropdown

* Fix loader component type

* move steps to a separate file

* make confirmation banner green

* track safe creation in analytics

* add back button

* remove width style from backbutton

* remove width style from backbutton (prev was just commented)

* remove components-v2 and use safe-react-components

* fix duplicated import

* bring back addressinfo component because it was not included in safe-react-components

* Fix broken import (CurrencyDropdown component was renamed)

* add CustomIconText component to fix transaction tab crash

* bring back ListLayoutComponent
This commit is contained in:
Mikhail Mikheev 2020-05-19 15:55:35 +04:00 committed by GitHub
parent cfffd00d2b
commit 6377c80e4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 841 additions and 1910 deletions

View File

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="21" viewBox="0 0 13 21">
<path fill="#B2B5B2" fill-rule="evenodd" d="M8.7 11.266V0H4.27v11.266H0l6.484 9.172 6.493-9.172z"/>
</svg>

Before

Width:  |  Height:  |  Size: 195 B

View File

@ -1,31 +0,0 @@
// @flow
import React from 'react'
import styled from 'styled-components'
import ArrowDown from './arrow-down.svg'
import Hairline from '~/components/layout/Hairline'
import { md, sm } from '~/theme/variables'
const Wrapper = styled.div`
display: flex;
align-items: center;
margin: ${md} 0;
img {
margin: 0 ${sm};
}
`
type Props = {
withArrow: boolean,
}
const DividerLine = ({ withArrow }: Props) => (
<Wrapper>
{withArrow && <img alt="Arrow Down" src={ArrowDown} />}
<Hairline />
</Wrapper>
)
export default DividerLine

View File

@ -1,21 +0,0 @@
// @flow
import React from 'react'
import styled from 'styled-components'
import { border } from '~/theme/variables'
type Props = {
children: React.Node,
}
const Box = styled.p`
padding: 10px;
word-wrap: break-word;
border: solid 2px ${border};
`
const TextBox = ({ children }: Props) => {
return <Box>{children}</Box>
}
export default TextBox

View File

@ -1,4 +0,0 @@
// @flow
export { default as DividerLine } from './DividerLine'
export { default as TextBox } from './TextBox'
export { default as IconText } from './IconText'

View File

@ -1,24 +0,0 @@
// @flow
import CircularProgress from '@material-ui/core/CircularProgress'
import React from 'react'
import styled from 'styled-components'
const Wrapper = styled.div`
display: flex;
height: 100%;
width: 100%;
justify-content: ${({ centered }) => (centered ? 'center' : 'start')};
align-items: center;
`
type Props = {
size?: number,
centered: boolean,
}
const Loader = ({ centered = true, size }: Props) => (
<Wrapper centered={centered}>
<CircularProgress size={size || 60} />
</Wrapper>
)
export default Loader

View File

@ -1,2 +0,0 @@
// @flow
export { default as Loader } from './Loader'

View File

@ -1,8 +0,0 @@
// @flow
export * from './dataDisplay'
export * from './feedback'
export * from './layouts'
export * from './navigation'
export * from './safeUtils'
export * from './surfaces'
export * from './utils'

View File

@ -1,2 +0,0 @@
// @flow
export { default as ListContentLayout } from './ListContentLayout'

View File

@ -1,48 +0,0 @@
// @flow
import React from 'react'
import styled from 'styled-components'
import { IconText } from '~/components-v2'
import CheckIcon from '~/components/layout/PageFrame/assets/check.svg'
import {
background as backgroundColor,
secondaryText as disabledColor,
error as errorColor,
secondary,
} from '~/theme/variables'
const Circle = styled.div`
background-color: ${({ disabled, error }) => {
if (error) {
return errorColor
}
if (disabled) {
return disabledColor
}
return secondary
}};
color: ${backgroundColor};
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 5px;
`
type Props = {
dotIndex: number,
currentIndex: number,
error?: boolean,
}
const DotStep = ({ currentIndex, dotIndex, error }: Props) => {
return (
<Circle disabled={dotIndex > currentIndex} error={error}>
{dotIndex < currentIndex ? <IconText iconUrl={CheckIcon} /> : dotIndex + 1}
</Circle>
)
}
export default DotStep

View File

@ -1,69 +0,0 @@
// @flow
import StepMUI from '@material-ui/core/Step'
import StepLabelMUI from '@material-ui/core/StepLabel'
import StepperMUI from '@material-ui/core/Stepper'
import React from 'react'
import styled from 'styled-components'
import DotStep from './DotStep'
import { secondaryText as disabled, error as errorColor, primary, secondary } from '~/theme/variables'
const StyledStepper = styled(StepperMUI)`
background-color: transparent;
`
const StyledStepLabel = styled.p`
&& {
color: ${({ activeStepIndex, error, index }) => {
if (error) {
return errorColor
}
if (index === activeStepIndex) {
return secondary
}
if (index < activeStepIndex) {
return disabled
}
return primary
}};
}
`
type Props = {
steps: Array<{ id: string | number, label: string }>,
activeStepIndex: number,
error?: boolean,
orientation: 'vertical' | 'horizontal',
}
const Stepper = ({ activeStepIndex, error, orientation, steps }: Props) => {
return (
<StyledStepper activeStep={activeStepIndex} orientation={orientation}>
{steps.map((s, index) => {
return (
<StepMUI key={s.id}>
<StepLabelMUI
icon={
<DotStep currentIndex={activeStepIndex} dotIndex={index} error={index === activeStepIndex && error} />
}
>
<StyledStepLabel
activeStepIndex={activeStepIndex}
error={index === activeStepIndex && error}
index={index}
>
{s.label}
</StyledStepLabel>
</StepLabelMUI>
</StepMUI>
)
})}
</StyledStepper>
)
}
export default Stepper

View File

@ -1,2 +0,0 @@
// @flow
export { default as Stepper } from './Stepper'

View File

@ -1,2 +0,0 @@
// @flow
export { default as AddressInfo } from './AddressInfo'

View File

@ -1,48 +0,0 @@
// @flow
import CollapseMUI from '@material-ui/core/Collapse'
import IconButton from '@material-ui/core/IconButton'
import ExpandLess from '@material-ui/icons/ExpandLess'
import ExpandMore from '@material-ui/icons/ExpandMore'
import React from 'react'
import styled from 'styled-components'
const Wrapper = styled.div``
const Header = styled.div`
display: flex;
align-items: center;
`
const Title = styled.div``
type Props = {
title: string,
children: React.Node,
description: React.Node,
}
const Collapse = ({ children, description, title }: Props) => {
const [open, setOpen] = React.useState(false)
const handleClick = () => {
setOpen(!open)
}
return (
<Wrapper>
<Title>{title}</Title>
<Header>
<IconButton disableRipple onClick={handleClick} size="small">
{open ? <ExpandLess /> : <ExpandMore />}
</IconButton>
{description}
</Header>
<CollapseMUI in={open} timeout="auto" unmountOnExit>
{children}
</CollapseMUI>
</Wrapper>
)
}
export default Collapse

View File

@ -1,2 +0,0 @@
// @flow
export { default as Collapse } from './Collapse'

View File

@ -1,2 +0,0 @@
// @flow
export * from './modals'

View File

@ -1,73 +0,0 @@
// @flow
import IconButton from '@material-ui/core/IconButton'
import { createStyles, makeStyles } from '@material-ui/core/styles'
import Close from '@material-ui/icons/Close'
import React, { type Node } from 'react'
import styled from 'styled-components'
import Modal from '~/components/Modal'
import Hairline from '~/components/layout/Hairline'
const TitleSection = styled.div`
display: flex;
justify-content: space-between;
margin: 10px 20px;
`
const BodySection = styled.div`
padding: 10px 20px;
max-height: 460px;
overflow-y: auto;
`
const FooterSection = styled.div`
margin: 10px 20px;
`
const StyledClose = styled(Close)`
&& {
height: 35px;
width: 35px;
}
`
const useStyles = makeStyles(() =>
createStyles({
paper: {
height: 'auto',
position: 'static',
},
}),
)
type Props = {
title: string,
body: Node,
footer: Node,
onClose: () => void,
}
const GenericModal = ({ body, footer, onClose, title }: Props) => {
const classes = useStyles()
return (
<Modal description="GenericModal" handleClose={onClose} open paperClassName={classes.paper} title="GenericModal">
<TitleSection>
{title}
<IconButton disableRipple onClick={onClose}>
<StyledClose />
</IconButton>
</TitleSection>
<Hairline />
<BodySection>{body}</BodySection>
{footer && (
<>
<Hairline />
<FooterSection>{footer}</FooterSection>
</>
)}
</Modal>
)
}
export default GenericModal

View File

@ -1,3 +0,0 @@
// @flow
export { default as GenericModal } from './GenericModal'
export * from './utils'

View File

@ -1,60 +0,0 @@
// @flow
import React from 'react'
import styled from 'styled-components'
import Button from '~/components/layout/Button'
import Paragraph from '~/components/layout/Paragraph'
import { lg } from '~/theme/variables'
const StyledParagraph = styled(Paragraph)`
&& {
font-size: ${lg};
}
`
const IconImg = styled.img`
width: 20px;
margin-right: 10px;
`
const TitleWrapper = styled.div`
display: flex;
align-items: center;
`
export const ModalTitle = ({ iconUrl, title }: { title: string, iconUrl: string }) => {
return (
<TitleWrapper>
{iconUrl && <IconImg alt={title} src={iconUrl} />}
<StyledParagraph noMargin weight="bolder">
{title}
</StyledParagraph>
</TitleWrapper>
)
}
const FooterWrapper = styled.div`
display: flex;
justify-content: space-around;
`
export const ModalFooterConfirmation = ({
cancelText,
handleCancel,
handleOk,
okText,
}: {
okText: string,
cancelText: string,
handleOk: () => void,
handleCancel: () => void,
}) => {
return (
<FooterWrapper>
<Button minWidth={130} onClick={handleCancel}>
{cancelText}
</Button>
<Button color="primary" minWidth={130} onClick={handleOk} variant="contained">
{okText}
</Button>
</FooterWrapper>
)
}

View File

@ -38,9 +38,9 @@ const StyledBlock = styled(Block)`
border-radius: 3px;
`
type Props = {
safeName: string,
safeName?: string,
safeAddress: string,
ethBalance: string,
ethBalance?: string,
}
const AddressInfo = ({ ethBalance, safeAddress, safeName }: Props) => {

View File

@ -15,11 +15,11 @@ const Text = styled.span`
height: 17px;
`
const IconText = ({ iconUrl, text }: { iconUrl: string, text?: string }) => (
const CustomIconText = ({ iconUrl, text }: { iconUrl: string, text?: string }) => (
<Wrapper>
<Icon alt={text} src={iconUrl} />
{text && <Text>{text}</Text>}
</Wrapper>
)
export default IconText
export default CustomIconText

View File

@ -6,7 +6,6 @@ export const Wrapper = styled.div`
grid-template-columns: 245px auto;
grid-template-rows: 514px;
min-height: 525px;
.background {
box-shadow: 1px 2px 10px 0 rgba(212, 212, 211, 0.59);
background-color: white;

View File

@ -34,23 +34,21 @@ type Props = {
classes: Object,
}
const List = ({ activeItem, classes, items, onItemClick }: Props) => {
return (
<Wrapper>
{items.map((i) => (
<Item
className={cn(classes.menuOption, activeItem === i.id && classes.active)}
key={i.id}
onClick={() => onItemClick(i.id)}
>
<div className="container">
{i.iconUrl && <IconImg alt={i.name} src={i.iconUrl} />}
<span>{i.name}</span>
</div>
</Item>
))}
</Wrapper>
)
}
const List = ({ activeItem, classes, items, onItemClick }: Props) => (
<Wrapper>
{items.map((i) => (
<Item
className={cn(classes.menuOption, activeItem === i.id && classes.active)}
key={i.id}
onClick={() => onItemClick(i.id)}
>
<div className="container">
{i.iconUrl && <IconImg alt={i.name} src={i.iconUrl} />}
<span>{i.name}</span>
</div>
</Item>
))}
</Wrapper>
)
export default withStyles(styles)(List)

View File

@ -5,8 +5,8 @@ import { getExchangeRatesUrl } from '~/config'
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
const fetchCurrenciesRates = async (
baseCurrency: AVAILABLE_CURRENCIES,
targetCurrencyValue: AVAILABLE_CURRENCIES,
baseCurrency: $Keys<typeof AVAILABLE_CURRENCIES>,
targetCurrencyValue: $Keys<typeof AVAILABLE_CURRENCIES>,
): Promise<number> => {
let rate = 0
const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}`

View File

@ -1,5 +1,5 @@
// @flow
import { Dispatch as ReduxDispatch } from 'redux'
import { type Dispatch as ReduxDispatch } from 'redux'
import fetchCurrenciesRates from '~/logic/currencyValues/api/fetchCurrenciesRates'
import { setCurrencyRate } from '~/logic/currencyValues/store/actions/setCurrencyRate'

View File

@ -3,13 +3,11 @@ import { List } from 'immutable'
import { batch } from 'react-redux'
import type { Dispatch as ReduxDispatch } from 'redux'
import fetchCurrencyRate from '~/logic/currencyValues/store/actions/fetchCurrencyRate'
import { setCurrencyBalances } from '~/logic/currencyValues/store/actions/setCurrencyBalances'
import { setCurrencyRate } from '~/logic/currencyValues/store/actions/setCurrencyRate'
import { setSelectedCurrency } from '~/logic/currencyValues/store/actions/setSelectedCurrency'
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
import { loadCurrencyValues } from '~/logic/currencyValues/store/utils/currencyValuesStorage'
import fetchSafeTokens from '~/logic/tokens/store/actions/fetchSafeTokens'
import type { GlobalState } from '~/store'
export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
@ -27,12 +25,11 @@ export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: Red
Object.entries(storedCurrencies).forEach((kv) => {
const safeAddr = kv[0]
const value = kv[1]
const { currencyRate, selectedCurrency } = value
batch(() => {
dispatch(setSelectedCurrency(safeAddr, selectedCurrency))
dispatch(setSelectedCurrency(safeAddr, selectedCurrency || AVAILABLE_CURRENCIES.USD))
dispatch(setCurrencyRate(safeAddr, currencyRate))
dispatch(fetchCurrencyRate(safeAddr, selectedCurrency))
dispatch(fetchSafeTokens(safeAddress))
})
})
} catch (err) {

View File

@ -29,10 +29,10 @@ const Routes = ({ location }: RoutesProps) => {
const { trackPage } = useAnalytics()
useEffect(() => {
if (location.pathname !== '/') {
if (isInitialLoad && location.pathname !== '/') {
setInitialLoad(false)
}
}, [])
}, [location.pathname, isInitialLoad])
useEffect(() => {
const page = location.pathname + location.search

View File

@ -1,6 +1,8 @@
// @flow
import { Loader } from '@gnosis.pm/safe-react-components'
import queryString from 'query-string'
import React, { useEffect, useState } from 'react'
import ReactGA from 'react-ga'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
@ -10,7 +12,6 @@ import Layout from '../components/Layout'
import actions, { type Actions } from './actions'
import selector from './selector'
import { Loader } from '~/components-v2'
import Page from '~/components/layout/Page'
import { getSafeDeploymentTransaction } from '~/logic/contracts/safeContracts'
import { checkReceiptStatus } from '~/logic/wallets/ethTransactions'
@ -120,7 +121,7 @@ const Open = ({ addSafe, network, provider, userAccount }: Props) => {
threshold,
})
}
})
}, [])
// check if there is a safe being created
useEffect(() => {
@ -163,6 +164,12 @@ const Open = ({ addSafe, network, provider, userAccount }: Props) => {
const safeProps = await getSafeProps(safeAddress, name, ownersNames, ownerAddresses)
addSafe(safeProps)
ReactGA.event({
category: 'User',
action: 'Created a safe',
value: safeAddress,
})
removeFromStorage(SAFE_PENDING_CREATION_STORAGE_KEY)
const url = {
pathname: `${SAFELIST_ADDRESS}/${safeProps.address}/balances`,
@ -191,7 +198,7 @@ const Open = ({ addSafe, network, provider, userAccount }: Props) => {
}
if (loading || showProgress === undefined) {
return <Loader />
return <Loader size="md" />
}
return (

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,56 @@
// @flow
import React from 'react'
import styled from 'styled-components'
import Button from '~/components/layout/Button'
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
import { connected } from '~/theme/variables'
const EtherScanLink = styled.a`
color: ${connected};
`
const ButtonWithMargin = styled(Button)`
margin-right: 16px;
`
export const GenericFooter = ({ safeCreationTxHash }: { safeCreationTxHash: string }) => (
<span>
<p>This process should take a couple of minutes.</p>
<p>
Follow the progress on{' '}
<EtherScanLink
aria-label="Show details on Etherscan"
href={getEtherScanLink('tx', safeCreationTxHash)}
rel="noopener noreferrer"
target="_blank"
>
Etherscan.io
</EtherScanLink>
.
</p>
</span>
)
export const ContinueFooter = ({
continueButtonDisabled,
onContinue,
}: {
continueButtonDisabled: boolean,
onContinue: Function,
}) => (
<Button color="primary" disabled={continueButtonDisabled} onClick={onContinue} variant="contained">
Continue
</Button>
)
export const ErrorFooter = ({ onCancel, onRetry }: { onCancel: Function, onRetry: Function }) => (
<>
<ButtonWithMargin onClick={onCancel} variant="contained">
Cancel
</ButtonWithMargin>
<Button color="primary" onClick={onRetry} variant="contained">
Retry
</Button>
</>
)

View File

@ -1,18 +1,21 @@
// @flow
import { Loader, Stepper } from '@gnosis.pm/safe-react-components'
import React, { useEffect, useState } from 'react'
import styled from 'styled-components'
import { Loader, Stepper } from '~/components-v2'
import LoaderDots from '~/components-v2/feedback/Loader-dots/assets/loader-dots.svg'
import { ErrorFooter } from './components/Footer'
import { isConfirmationStep, steps } from './steps'
import Button from '~/components/layout/Button'
import Heading from '~/components/layout/Heading'
import Img from '~/components/layout/Img'
import Paragraph from '~/components/layout/Paragraph'
import { initContracts } from '~/logic/contracts/safeContracts'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getEtherScanLink, getWeb3 } from '~/logic/wallets/getWeb3'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { background, connected } from '~/theme/variables'
const loaderDotsSvg = require('./assets/loader-dots.svg')
const successSvg = require('./assets/success.svg')
const vaultErrorSvg = require('./assets/vault-error.svg')
const vaultSvg = require('./assets/vault.svg')
@ -47,21 +50,18 @@ const Body = styled.div`
display: grid;
grid-template-rows: 100px 50px 70px 60px 100px;
`
const EtherScanLink = styled.a`
color: ${connected};
`
const CardTitle = styled.div`
font-size: 20px;
`
const FullParagraph = styled(Paragraph)`
background-color: ${background};
background-color: ${(p) => (p.inverseColors ? connected : background)};
color: ${(p) => (p.inverseColors ? background : connected)};
padding: 24px;
font-size: 16px;
margin-bottom: 16px;
`
const ButtonMargin = styled(Button)`
margin-right: 16px;
transition: color 0.3s ease-in-out, background-color 0.3s ease-in-out;
`
const BodyImage = styled.div`
@ -88,6 +88,11 @@ const BodyFooter = styled.div`
align-items: flex-end;
`
const BackButton = styled(Button)`
grid-column: 2;
margin: 20px auto 0;
`
type Props = {
provider: string,
creationTxHash: Promise<any>,
@ -108,78 +113,13 @@ const SafeDeployment = ({ creationTxHash, onCancel, onRetry, onSuccess, provider
const [waitingSafeDeployed, setWaitingSafeDeployed] = useState(false)
const [continueButtonDisabled, setContinueButtonDisabled] = useState(false)
const genericFooter = (
<span>
<p>This process should take a couple of minutes.</p>
<p>
Follow the progress on{' '}
<EtherScanLink
aria-label="Show details on Etherscan"
href={getEtherScanLink('tx', safeCreationTxHash)}
rel="noopener noreferrer"
target="_blank"
>
Etherscan.io
</EtherScanLink>
.
</p>
</span>
)
const confirmationStep = isConfirmationStep(stepIndex)
const navigateToSafe = () => {
setContinueButtonDisabled(true)
onSuccess(createdSafeAddress)
}
const steps = [
{
id: '1',
label: 'Waiting for transaction confirmation',
description: undefined,
instruction: 'Please confirm the Safe creation in your wallet',
footer: null,
},
{
id: '2',
label: 'Transaction submitted',
description: undefined,
instruction: 'Please do not leave the page',
footer: genericFooter,
},
{
id: '3',
label: 'Validating transaction',
description: undefined,
instruction: 'Please do not leave the page',
footer: genericFooter,
},
{
id: '4',
label: 'Deploying smart contract',
description: undefined,
instruction: 'Please do not leave the page',
footer: genericFooter,
},
{
id: '5',
label: 'Generating your Safe',
description: undefined,
instruction: 'Please do not leave the page',
footer: genericFooter,
},
{
id: '6',
label: 'Success',
description: 'Your Safe was created successfully',
instruction: 'Click below to get started',
footer: (
<Button color="primary" disabled={continueButtonDisabled} onClick={navigateToSafe} variant="contained">
Continue
</Button>
),
},
]
const onError = (error) => {
setIntervalStarted(false)
setWaitingSafeDeployed(false)
@ -354,6 +294,13 @@ const SafeDeployment = ({ creationTxHash, onCancel, onRetry, onSuccess, provider
return <Loader />
}
let FooterComponent = null
if (error) {
FooterComponent = ErrorFooter
} else if (steps[stepIndex].footerComponent) {
FooterComponent = steps[stepIndex].footerComponent
}
return (
<Wrapper>
<Title tag="h2">Safe creation process</Title>
@ -369,29 +316,30 @@ const SafeDeployment = ({ creationTxHash, onCancel, onRetry, onSuccess, provider
<CardTitle>{steps[stepIndex].description || steps[stepIndex].label}</CardTitle>
</BodyDescription>
<BodyLoader>{!error && stepIndex <= 4 && <Img alt="LoaderDots" src={LoaderDots} />}</BodyLoader>
<BodyLoader>{!error && stepIndex <= 4 && <Img alt="Loader dots" src={loaderDotsSvg} />}</BodyLoader>
<BodyInstruction>
<FullParagraph color="primary" noMargin size="md">
<FullParagraph color="primary" inverseColors={confirmationStep} noMargin size="md">
{error ? 'You can Cancel or Retry the Safe creation process.' : steps[stepIndex].instruction}
</FullParagraph>
</BodyInstruction>
<BodyFooter>
{error ? (
<>
<ButtonMargin onClick={onCancel} variant="contained">
Cancel
</ButtonMargin>
<Button color="primary" onClick={onRetryTx} variant="contained">
Retry
</Button>
</>
) : (
steps[stepIndex].footer
)}
{FooterComponent ? (
<FooterComponent
continueButtonDisabled={continueButtonDisabled}
onCancel={onCancel}
onClick={onRetryTx}
onContinue={navigateToSafe}
onRetry={onRetryTx}
safeCreationTxHash={safeCreationTxHash}
/>
) : null}
</BodyFooter>
</Body>
<BackButton color="primary" minWidth={140} onClick={onCancel}>
Back
</BackButton>
</Wrapper>
)
}

View File

@ -0,0 +1,49 @@
// @flow
import { ContinueFooter, GenericFooter } from './components/Footer'
export const isConfirmationStep = (stepIndex?: number) => stepIndex === 0
export const steps = [
{
id: '1',
label: 'Waiting for transaction confirmation',
description: undefined,
instruction: 'Please confirm the Safe creation in your wallet',
footerComponent: null,
},
{
id: '2',
label: 'Transaction submitted',
description: undefined,
instruction: 'Please do not leave the page',
footerComponent: GenericFooter,
},
{
id: '3',
label: 'Validating transaction',
description: undefined,
instruction: 'Please do not leave the page',
footerComponent: GenericFooter,
},
{
id: '4',
label: 'Deploying smart contract',
description: undefined,
instruction: 'Please do not leave the page',
footerComponent: GenericFooter,
},
{
id: '5',
label: 'Generating your Safe',
description: undefined,
instruction: 'Please do not leave the page',
footerComponent: GenericFooter,
},
{
id: '6',
label: 'Success',
description: 'Your Safe was created successfully',
instruction: 'Click below to get started',
footerComponent: ContinueFooter,
},
]

View File

@ -1,10 +1,19 @@
// @flow
import { Icon, ModalFooterConfirmation, Text, Title } from '@gnosis.pm/safe-react-components'
import {
Collapse,
DividerLine,
Icon,
ModalFooterConfirmation,
ModalTitle,
Text,
TextBox,
Title,
} from '@gnosis.pm/safe-react-components'
import { BigNumber } from 'bignumber.js'
import React from 'react'
import styled from 'styled-components'
import { AddressInfo, Collapse, DividerLine, ModalTitle, TextBox } from '~/components-v2'
import AddressInfo from '~/components/AddressInfo'
import { mustBeEthereumAddress } from '~/components/forms/validator'
import Bold from '~/components/layout/Bold'
import Heading from '~/components/layout/Heading'

View File

@ -1,5 +1,5 @@
// @flow
import { Card, FixedDialog, FixedIcon, IconText, Menu, Text, Title } from '@gnosis.pm/safe-react-components'
import { Card, FixedDialog, FixedIcon, IconText, Loader, Menu, Text, Title } from '@gnosis.pm/safe-react-components'
import { withSnackbar } from 'notistack'
import React, { useCallback, useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
@ -11,7 +11,7 @@ import confirmTransactions from './confirmTransactions'
import sendTransactions from './sendTransactions'
import { getAppInfoFromUrl, staticAppsList } from './utils'
import { ListContentLayout as LCL, Loader } from '~/components-v2'
import LCL from '~/components/ListContentLayout'
import { networkSelector } from '~/logic/wallets/store/selectors'
import { SAFELIST_ADDRESS } from '~/routes/routes'
import { grantedSelector } from '~/routes/safe/container/selector'

View File

@ -2,7 +2,7 @@
import React from 'react'
import { useSelector } from 'react-redux'
import { AddressInfo } from '~/components-v2'
import AddressInfo from '~/components/AddressInfo'
import { safeSelector } from '~/routes/safe/store/selectors'
const SafeInfo = () => {

View File

@ -14,8 +14,8 @@ import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
import EtherscanService from '~/logic/contractInteraction/sources/EtherscanService'
import { NO_CONTRACT } from '~/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils'
import CheckIcon from '~/routes/safe/components/DropdownCurrency/img/check.svg'
import { useDropdownStyles } from '~/routes/safe/components/DropdownCurrency/style'
import CheckIcon from '~/routes/safe/components/CurrencyDropdown/img/check.svg'
import { useDropdownStyles } from '~/routes/safe/components/CurrencyDropdown/style'
import { DropdownListTheme } from '~/theme/mui'
const MENU_WIDTH = '452px'

View File

@ -6,7 +6,7 @@ import { useDispatch, useSelector } from 'react-redux'
import { styles } from './style'
import AddressInfo from '~/components-v2/safeUtils/AddressInfo'
import AddressInfo from '~/components/AddressInfo'
import Block from '~/components/layout/Block'
import Button from '~/components/layout/Button'
import Col from '~/components/layout/Col'

View File

@ -15,7 +15,7 @@ import Link from '~/components/layout/Link'
import Row from '~/components/layout/Row'
import { SAFELIST_ADDRESS } from '~/routes/routes'
import SendModal from '~/routes/safe/components/Balances/SendModal'
import DropdownCurrency from '~/routes/safe/components/DropdownCurrency'
import CurrencyDropdown from '~/routes/safe/components/CurrencyDropdown'
import { useFetchTokens } from '~/routes/safe/container/Hooks/useFetchTokens'
import { safeFeaturesEnabledSelector, safeParamAddressFromStateSelector } from '~/routes/safe/store/selectors'
import { history } from '~/store'
@ -170,7 +170,7 @@ const Balances = (props: Props) => {
))}
</Col>
<Col className={tokenControls} end="sm" sm={6} xs={12}>
{showCoins && <DropdownCurrency />}
{showCoins && <CurrencyDropdown />}
<ButtonLink
className={manageTokensButton}
onClick={erc721Enabled && showCollectibles ? () => onShow('ManageCollectibleModal') : () => onShow('Token')}

View File

Before

Width:  |  Height:  |  Size: 188 B

After

Width:  |  Height:  |  Size: 188 B

View File

@ -16,11 +16,11 @@ import CheckIcon from './img/check.svg'
import { setSelectedCurrency } from '~/logic/currencyValues/store/actions/setSelectedCurrency'
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
import { currentCurrencySelector } from '~/logic/currencyValues/store/selectors'
import { useDropdownStyles } from '~/routes/safe/components/DropdownCurrency/style'
import { useDropdownStyles } from '~/routes/safe/components/CurrencyDropdown/style'
import { safeParamAddressFromStateSelector } from '~/routes/safe/store/selectors'
import { DropdownListTheme } from '~/theme/mui'
const DropdownCurrency = () => {
const CurrencyDropdown = () => {
const currenciesList = Object.values(AVAILABLE_CURRENCIES)
const safeAddress = useSelector(safeParamAddressFromStateSelector)
const dispatch = useDispatch()
@ -122,4 +122,4 @@ const DropdownCurrency = () => {
)
}
export default DropdownCurrency
export default CurrencyDropdown

View File

@ -26,6 +26,34 @@ type Props = {
location: Object,
}
const BalancesLabel = (
<>
<BalancesIcon />
Assets
</>
)
const AddressBookLabel = (
<>
<AddressBookIcon />
Address Book
</>
)
const AppsLabel = (
<>
<AppsIcon />
Apps
</>
)
const TransactionsLabel = (
<>
<TransactionsIcon />
Transactions
</>
)
const TabsComponent = (props: Props) => {
const { classes, location, match } = props
@ -47,33 +75,6 @@ const TabsComponent = (props: Props) => {
return pathname
}
const labelBalances = (
<>
<BalancesIcon />
Assets
</>
)
const labelAddressBook = (
<>
<AddressBookIcon />
Address Book
</>
)
const labelApps = (
<>
<AppsIcon />
Apps
</>
)
const labelTransactions = (
<>
<TransactionsIcon />
Transactions
</>
)
return (
<Tabs
indicatorColor="secondary"
@ -88,7 +89,7 @@ const TabsComponent = (props: Props) => {
wrapper: classes.tabWrapper,
}}
data-testid={BALANCES_TAB_BTN_TEST_ID}
label={labelBalances}
label={BalancesLabel}
value={`${match.url}/balances`}
/>
<Tab
@ -97,7 +98,7 @@ const TabsComponent = (props: Props) => {
wrapper: classes.tabWrapper,
}}
data-testid={TRANSACTIONS_TAB_BTN_TEST_ID}
label={labelTransactions}
label={TransactionsLabel}
value={`${match.url}/transactions`}
/>
{process.env.REACT_APP_APPS_DISABLED !== 'true' && (
@ -107,7 +108,7 @@ const TabsComponent = (props: Props) => {
wrapper: classes.tabWrapper,
}}
data-testid={TRANSACTIONS_TAB_BTN_TEST_ID}
label={labelApps}
label={AppsLabel}
value={`${match.url}/apps`}
/>
)}
@ -117,7 +118,7 @@ const TabsComponent = (props: Props) => {
wrapper: classes.tabWrapper,
}}
data-testid={ADDRESS_BOOK_TAB_BTN_TEST_ID}
label={labelAddressBook}
label={AddressBookLabel}
value={`${match.url}/address-book`}
/>
<Tab

View File

@ -1,4 +1,5 @@
// @flow
import { GenericModal } from '@gnosis.pm/safe-react-components'
import { makeStyles } from '@material-ui/core/styles'
import React, { useState } from 'react'
import { useSelector } from 'react-redux'
@ -8,7 +9,6 @@ import Receive from '../Balances/Receive'
import { styles } from './style'
import { GenericModal } from '~/components-v2'
import Modal from '~/components/Modal'
import NoSafe from '~/components/NoSafe'
import Hairline from '~/components/layout/Hairline'
@ -33,7 +33,6 @@ const TxsTable = React.lazy(() => import('~/routes/safe/components/Transactions/
const AddressBookTable = React.lazy(() => import('~/routes/safe/components/AddressBook'))
type Props = {
classes: Object,
sendFunds: Object,
showReceive: boolean,
onShow: Function,

View File

@ -1,4 +1,5 @@
// @flow
import { IconText, Loader } from '@gnosis.pm/safe-react-components'
import React, { useEffect, useState } from 'react'
import CustomTxIcon from './assets/custom.svg'
@ -6,7 +7,7 @@ import IncomingTxIcon from './assets/incoming.svg'
import OutgoingTxIcon from './assets/outgoing.svg'
import SettingsTxIcon from './assets/settings.svg'
import { IconText, Loader } from '~/components-v2'
import CustomIconText from '~/components/CustomIconText'
import { getAppInfoFromOrigin, getAppInfoFromUrl } from '~/routes/safe/components/Apps/utils'
import { type TransactionType } from '~/routes/safe/store/models/transaction'
@ -56,9 +57,9 @@ const TxType = ({ origin, txType }: { txType: TransactionType, origin: string |
}, [origin, txType])
if (forceCustom || !origin) {
return <IconText iconUrl={typeToIcon[txType]} text={typeToLabel[txType]} />
return <CustomIconText iconUrl={typeToIcon[txType]} text={typeToLabel[txType]} />
}
return loading ? <Loader centered={false} size={20} /> : <IconText iconUrl={appInfo.iconUrl} text={appInfo.name} />
return loading ? <Loader size="md" /> : <IconText iconUrl={appInfo.iconUrl} text={appInfo.name} />
}
export default TxType

1933
yarn.lock

File diff suppressed because it is too large Load Diff