mirror of
https://github.com/status-im/safe-react.git
synced 2025-01-11 02:25:40 +00:00
* 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:
parent
cfffd00d2b
commit
6377c80e4f
@ -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 |
@ -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
|
@ -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
|
@ -1,4 +0,0 @@
|
||||
// @flow
|
||||
export { default as DividerLine } from './DividerLine'
|
||||
export { default as TextBox } from './TextBox'
|
||||
export { default as IconText } from './IconText'
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
// @flow
|
||||
export { default as Loader } from './Loader'
|
@ -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'
|
@ -1,2 +0,0 @@
|
||||
// @flow
|
||||
export { default as ListContentLayout } from './ListContentLayout'
|
@ -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
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
// @flow
|
||||
export { default as Stepper } from './Stepper'
|
@ -1,2 +0,0 @@
|
||||
// @flow
|
||||
export { default as AddressInfo } from './AddressInfo'
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
// @flow
|
||||
export { default as Collapse } from './Collapse'
|
@ -1,2 +0,0 @@
|
||||
// @flow
|
||||
export * from './modals'
|
@ -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
|
@ -1,3 +0,0 @@
|
||||
// @flow
|
||||
export { default as GenericModal } from './GenericModal'
|
||||
export * from './utils'
|
@ -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>
|
||||
)
|
||||
}
|
@ -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) => {
|
@ -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
|
@ -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;
|
@ -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)
|
@ -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}`
|
||||
|
@ -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'
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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 (
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
56
src/routes/opening/components/Footer.jsx
Normal file
56
src/routes/opening/components/Footer.jsx
Normal 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>
|
||||
</>
|
||||
)
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
49
src/routes/opening/steps.js
Normal file
49
src/routes/opening/steps.js
Normal 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,
|
||||
},
|
||||
]
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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 = () => {
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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')}
|
||||
|
Before Width: | Height: | Size: 188 B After Width: | Height: | Size: 188 B |
@ -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
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user