* Add types for SafeProps Adds getSafePropsValuesFromQueryParams implementation Replaces window.location with useLocation hook * Replaces SafeProps with import in Layout.tsx Adds downlevelIteration to tsconfig.json to allow array.entries() * Type createSafe() * SafeDeployment Types * Type Paragraph and refactor to functional component * Fix validateQueryParams and types Co-authored-by: nicolas <nicosampler@users.noreply.github.com> Co-authored-by: Daniel Sanchez <daniel.sanchez@gnosis.pm>
This commit is contained in:
parent
d47bd1fe98
commit
0ea73c4eda
|
@ -1,23 +1,34 @@
|
|||
import classNames from 'classnames/bind'
|
||||
import * as React from 'react'
|
||||
import React, { MouseEventHandler, CSSProperties, ReactElement, ReactNode } from 'react'
|
||||
|
||||
import styles from './index.module.scss'
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
||||
class Paragraph extends React.PureComponent<any> {
|
||||
render() {
|
||||
const { align, children, className, color, dot, noMargin, size, transform, weight, ...props } = this.props
|
||||
interface Props {
|
||||
align?: string
|
||||
children: ReactNode
|
||||
className?: string
|
||||
color?: string
|
||||
dot?: string
|
||||
noMargin?: boolean
|
||||
size?: string
|
||||
transform?: string
|
||||
weight?: string
|
||||
onClick?: MouseEventHandler<HTMLParagraphElement>
|
||||
style?: CSSProperties
|
||||
}
|
||||
|
||||
return (
|
||||
<p
|
||||
className={cx(styles.paragraph, className, weight, { noMargin, dot }, size, color, transform, align)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
const Paragraph = (props: Props): ReactElement => {
|
||||
const { align, children, className, color, dot, noMargin, size, transform, weight, ...restProps } = props
|
||||
return (
|
||||
<p
|
||||
className={cx(styles.paragraph, className, weight, { noMargin, dot }, size, color, transform, align)}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
export default Paragraph
|
||||
|
|
|
@ -24,19 +24,13 @@ import { networkSelector, providerNameSelector, userAccountSelector } from 'src/
|
|||
import { useSelector } from 'react-redux'
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { getNameFromAddressBook } from 'src/logic/addressBook/utils'
|
||||
import { SafeProps } from 'src/routes/open/container/Open'
|
||||
|
||||
const { useEffect } = React
|
||||
|
||||
const getSteps = () => ['Name', 'Owners and confirmations', 'Review']
|
||||
|
||||
type SafeProps = {
|
||||
name: string
|
||||
ownerAddresses: any
|
||||
ownerNames: string
|
||||
threshold: string
|
||||
}
|
||||
|
||||
type InitialValuesForm = {
|
||||
export type InitialValuesForm = {
|
||||
owner0Address?: string
|
||||
owner0Name?: string
|
||||
confirmations: string
|
||||
|
|
|
@ -3,8 +3,8 @@ import queryString from 'query-string'
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import ReactGA from 'react-ga'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import Opening from 'src/routes/opening'
|
||||
import { Layout } from 'src/routes/open/components/Layout'
|
||||
import { SafeDeployment } from 'src/routes/opening'
|
||||
import { InitialValuesForm, Layout } from 'src/routes/open/components/Layout'
|
||||
import Page from 'src/components/layout/Page'
|
||||
import { getSafeDeploymentTransaction } from 'src/logic/contracts/safeContracts'
|
||||
import { checkReceiptStatus } from 'src/logic/wallets/ethTransactions'
|
||||
|
@ -24,21 +24,51 @@ import { userAccountSelector } from 'src/logic/wallets/store/selectors'
|
|||
import { SafeRecordProps } from 'src/logic/safe/store/models/safe'
|
||||
import { addOrUpdateSafe } from 'src/logic/safe/store/actions/addOrUpdateSafe'
|
||||
import { PromiEvent, TransactionReceipt } from 'web3-core'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
|
||||
const SAFE_PENDING_CREATION_STORAGE_KEY = 'SAFE_PENDING_CREATION_STORAGE_KEY'
|
||||
|
||||
const validateQueryParams = (ownerAddresses, ownerNames, threshold, safeName) => {
|
||||
interface SafeCreationQueryParams {
|
||||
ownerAddresses: string | string[] | null
|
||||
ownerNames: string | string[] | null
|
||||
threshold: number | null
|
||||
safeName: string | null
|
||||
}
|
||||
|
||||
export interface SafeProps {
|
||||
name: string
|
||||
ownerAddresses: string[]
|
||||
ownerNames: string[]
|
||||
threshold: string
|
||||
}
|
||||
|
||||
const validateQueryParams = (queryParams: SafeCreationQueryParams): boolean => {
|
||||
const { ownerAddresses, ownerNames, threshold, safeName } = queryParams
|
||||
|
||||
if (!ownerAddresses || !ownerNames || !threshold || !safeName) {
|
||||
return false
|
||||
}
|
||||
if (!ownerAddresses.length || ownerNames.length === 0) {
|
||||
|
||||
if (Number.isNaN(threshold)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (Number.isNaN(Number(threshold))) {
|
||||
return false
|
||||
return threshold > 0 && threshold <= ownerAddresses.length
|
||||
}
|
||||
|
||||
const getSafePropsValuesFromQueryParams = (queryParams: SafeCreationQueryParams): SafeProps | undefined => {
|
||||
if (!validateQueryParams(queryParams)) {
|
||||
return
|
||||
}
|
||||
|
||||
const { threshold, safeName, ownerAddresses, ownerNames } = queryParams
|
||||
|
||||
return {
|
||||
name: safeName as string,
|
||||
threshold: (threshold as number).toString(),
|
||||
ownerAddresses: Array.isArray(ownerAddresses) ? ownerAddresses : [ownerAddresses as string],
|
||||
ownerNames: Array.isArray(ownerNames) ? ownerNames : [ownerNames as string],
|
||||
}
|
||||
return threshold <= ownerAddresses.length
|
||||
}
|
||||
|
||||
export const getSafeProps = async (
|
||||
|
@ -54,7 +84,7 @@ export const getSafeProps = async (
|
|||
return safeProps
|
||||
}
|
||||
|
||||
export const createSafe = (values, userAccount) => {
|
||||
export const createSafe = (values: InitialValuesForm, userAccount: string): PromiEvent<TransactionReceipt> => {
|
||||
const confirmations = getThresholdFrom(values)
|
||||
const name = getSafeNameFrom(values)
|
||||
const ownersNames = getNamesFrom(values)
|
||||
|
@ -86,24 +116,26 @@ const Open = (): React.ReactElement => {
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [showProgress, setShowProgress] = useState(false)
|
||||
const [creationTxPromise, setCreationTxPromise] = useState<PromiEvent<TransactionReceipt>>()
|
||||
const [safeCreationPendingInfo, setSafeCreationPendingInfo] = useState<any>()
|
||||
const [safePropsFromUrl, setSafePropsFromUrl] = useState()
|
||||
const [safeCreationPendingInfo, setSafeCreationPendingInfo] = useState<{ txHash?: string } | undefined>()
|
||||
const [safePropsFromUrl, setSafePropsFromUrl] = useState<SafeProps | undefined>()
|
||||
const userAccount = useSelector(userAccountSelector)
|
||||
const dispatch = useDispatch()
|
||||
const location = useLocation()
|
||||
|
||||
useEffect(() => {
|
||||
// #122: Allow to migrate an old Multisig by passing the parameters to the URL.
|
||||
const query = queryString.parse(window.location.search, { arrayFormat: 'comma' })
|
||||
const query = queryString.parse(location.search, { arrayFormat: 'comma' })
|
||||
const { name, owneraddresses, ownernames, threshold } = query
|
||||
if (validateQueryParams(owneraddresses, ownernames, threshold, name)) {
|
||||
setSafePropsFromUrl({
|
||||
name,
|
||||
ownerAddresses: owneraddresses,
|
||||
ownerNames: ownernames,
|
||||
threshold,
|
||||
} as any)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const safeProps = getSafePropsValuesFromQueryParams({
|
||||
ownerAddresses: owneraddresses,
|
||||
ownerNames: ownernames,
|
||||
threshold: Number(threshold),
|
||||
safeName: name as string | null,
|
||||
})
|
||||
|
||||
setSafePropsFromUrl(safeProps)
|
||||
}, [location])
|
||||
|
||||
// check if there is a safe being created
|
||||
useEffect(() => {
|
||||
|
@ -121,7 +153,7 @@ const Open = (): React.ReactElement => {
|
|||
load()
|
||||
}, [])
|
||||
|
||||
const createSafeProxy = async (formValues?: any) => {
|
||||
const createSafeProxy = async (formValues?: InitialValuesForm) => {
|
||||
let values = formValues
|
||||
|
||||
// save form values, used when the user rejects the TX and wants to retry
|
||||
|
@ -132,7 +164,7 @@ const Open = (): React.ReactElement => {
|
|||
values = await loadFromStorage(SAFE_PENDING_CREATION_STORAGE_KEY)
|
||||
}
|
||||
|
||||
const promiEvent = createSafe(values, userAccount)
|
||||
const promiEvent = createSafe(values as InitialValuesForm, userAccount)
|
||||
setCreationTxPromise(promiEvent)
|
||||
setShowProgress(true)
|
||||
}
|
||||
|
@ -186,7 +218,7 @@ const Open = (): React.ReactElement => {
|
|||
return (
|
||||
<Page>
|
||||
{showProgress ? (
|
||||
<Opening
|
||||
<SafeDeployment
|
||||
creationTxHash={safeCreationPendingInfo?.txHash}
|
||||
onCancel={onCancel}
|
||||
onRetry={onRetry}
|
||||
|
|
|
@ -20,6 +20,7 @@ import LoaderDotsSvg from './assets/loader-dots.svg'
|
|||
import SuccessSvg from './assets/success.svg'
|
||||
import VaultErrorSvg from './assets/vault-error.svg'
|
||||
import VaultSvg from './assets/vault.svg'
|
||||
import { PromiEvent, TransactionReceipt } from 'web3-core'
|
||||
|
||||
const Wrapper = styled.div`
|
||||
display: grid;
|
||||
|
@ -56,13 +57,17 @@ const Body = styled.div`
|
|||
const CardTitle = styled.div`
|
||||
font-size: 20px;
|
||||
`
|
||||
const FullParagraph = styled(Paragraph)`
|
||||
background-color: ${(p) => (p.inverseColors ? connected : background)};
|
||||
color: ${(p) => (p.inverseColors ? background : connected)};
|
||||
|
||||
interface FullParagraphProps {
|
||||
inversecolors: string
|
||||
}
|
||||
|
||||
const FullParagraph = styled(Paragraph)<FullParagraphProps>`
|
||||
background-color: ${(p) => (p.inversecolors ? connected : background)};
|
||||
color: ${(p) => (p.inversecolors ? background : connected)};
|
||||
padding: 24px;
|
||||
font-size: 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
transition: color 0.3s ease-in-out, background-color 0.3s ease-in-out;
|
||||
`
|
||||
|
||||
|
@ -95,16 +100,21 @@ const BackButton = styled(Button)`
|
|||
margin: 20px auto 0;
|
||||
`
|
||||
|
||||
// type Props = {
|
||||
// provider: string
|
||||
// creationTxHash: Promise<any>
|
||||
// submittedPromise: Promise<any>
|
||||
// onRetry: () => void
|
||||
// onSuccess: () => void
|
||||
// onCancel: () => void
|
||||
// }
|
||||
type Props = {
|
||||
creationTxHash?: string
|
||||
submittedPromise?: PromiEvent<TransactionReceipt>
|
||||
onRetry: () => void
|
||||
onSuccess: (createdSafeAddress: string) => void
|
||||
onCancel: () => void
|
||||
}
|
||||
|
||||
const SafeDeployment = ({ creationTxHash, onCancel, onRetry, onSuccess, submittedPromise }): React.ReactElement => {
|
||||
export const SafeDeployment = ({
|
||||
creationTxHash,
|
||||
onCancel,
|
||||
onRetry,
|
||||
onSuccess,
|
||||
submittedPromise,
|
||||
}: Props): React.ReactElement => {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [stepIndex, setStepIndex] = useState(0)
|
||||
const [safeCreationTxHash, setSafeCreationTxHash] = useState('')
|
||||
|
@ -326,7 +336,7 @@ const SafeDeployment = ({ creationTxHash, onCancel, onRetry, onSuccess, submitte
|
|||
<BodyLoader>{!error && stepIndex <= 4 && <Img alt="Loader dots" src={LoaderDotsSvg} />}</BodyLoader>
|
||||
|
||||
<BodyInstruction>
|
||||
<FullParagraph color="primary" inverseColors={confirmationStep} noMargin size="md">
|
||||
<FullParagraph color="primary" inversecolors={confirmationStep.toString()} noMargin size="md">
|
||||
{error ? 'You can Cancel or Retry the Safe creation process.' : steps[stepIndex].instruction}
|
||||
</FullParagraph>
|
||||
</BodyInstruction>
|
||||
|
@ -350,5 +360,3 @@ const SafeDeployment = ({ creationTxHash, onCancel, onRetry, onSuccess, submitte
|
|||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default SafeDeployment
|
||||
|
|
|
@ -82,6 +82,7 @@ export const aMinedSafe = async (
|
|||
[FIELD_NAME]: name,
|
||||
[FIELD_CONFIRMATIONS]: `${threshold}`,
|
||||
[FIELD_OWNERS]: `${owners}`,
|
||||
safeCreationSalt: 0
|
||||
}
|
||||
|
||||
for (let i = 0; i < owners; i += 1) {
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react",
|
||||
"noFallthroughCasesInSwitch": true
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"downlevelIteration": true
|
||||
},
|
||||
"paths": {
|
||||
"src/*": [
|
||||
|
|
Loading…
Reference in New Issue