(Fix) Enforce linting and formatting (#564)

* (remove) unused / old packages / linting script

* (add) eslint / prettier packages and plugins

* (fix) eslint / prettier config

* (add) prettier / eslint scripts

* (fix) linting and formatting problems

* (remove) unused files

* (fix) linting problem that needed to be addressed manually

* (add) pre commit hooks

* (fix) lint-staged config

* (fix) config

* (fix) config

* (check) if pre config formatting works

* Add nvmrc and update yarn.lock

* Update `yarn.lock`

* Make jsx-a11y/no-autofocus report as warn

* Apply lint:fix to project

Co-authored-by: Fernando <fernando.greco@gmail.com>
This commit is contained in:
Gabriel Rodríguez Alsina 2020-02-17 19:20:43 -03:00 committed by GitHub
parent dff0f0bd4d
commit 6df5e72135
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
231 changed files with 2108 additions and 2960 deletions

View File

@ -1,7 +1,15 @@
node_modules
!.eslintrc.js
build_webpack
config
contracts
flow-typed
flow-typed/npm
config
scripts
migrations
node_modules
public
scripts
src/assets
src/config
test
*.spec*
*.test*

133
.eslintrc
View File

@ -1,82 +1,57 @@
{
"settings": {
"react": {
"flowVersion": "0.112.0",
"pragma": "React",
"version": "16.12.0"
},
"import/extensions": [".js", ".jsx"]
},
"parser": "babel-eslint",
"plugins": ["react", "flowtype", "import", "jsx-a11y", "prettier"],
"extends": [
"airbnb",
"eslint:recommended",
"plugin:react/recommended",
"plugin:flowtype/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:jsx-a11y/recommended",
"plugin:prettier/recommended",
"prettier/react"
],
"parser": "babel-eslint",
"plugins": [
"jsx-a11y",
"jest",
"flowtype"
"prettier/react",
"prettier/flowtype"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
}
},
"env": {
"browser": true,
"amd": true,
"node": true,
"es6": true
},
"rules": {
"react/jsx-filename-extension": [
1,
{
"extensions": [
".js",
".jsx"
]
}
],
"react/forbid-prop-types": [
1,
{
"forbid": [
"object",
"any"
]
}
],
"class-methods-use-this": 0,
"semi": [
"error",
"never"
],
"consistent-return": "off",
"max-len": [
"error",
120,
2,
{
"ignoreUrls": true,
"ignoreComments": false,
"ignoreRegExpLiterals": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true
}
],
"import/no-unresolved": 0,
"import/no-extraneous-dependencies": 0,
"import/extensions": 0,
"import/prefer-default-export": 0,
"react/default-props-match-prop-types": [
"error",
{
"allowRequiredDefaults": true
}
],
// https://github.com/yannickcr/eslint-plugin-react/issues/1593 ^
"jsx-a11y/label-has-for": 0,
"indent": [
"error",
2,
{
"SwitchCase": 1
"ignoreTemplateLiterals": true,
"ignoreUrls": true
}
],
"no-console": [
"error",
{
"allow": [
"warn",
"error"
]
"allow": ["warn", "error"]
}
],
"semi": ["error", "never"],
"flowtype/require-valid-file-annotation": [
2,
"always",
@ -84,32 +59,36 @@
"annotationStyle": "line"
}
],
"flowtype/generic-spacing": 0,
"import/extensions": 0,
"import/no-extraneous-dependencies": 0,
"import/no-unresolved": 0,
"import/prefer-default-export": 0,
"jsx-a11y/anchor-is-valid": [
"error",
{
"components": [
"Link"
],
"specialLink": [
"to",
"hrefLeft",
"hrefRight"
],
"aspects": [
"noHref",
"invalidHref",
"preferButton"
]
"components": ["Link"],
"specialLink": ["to", "hrefLeft", "hrefRight"],
"aspects": ["noHref", "invalidHref", "preferButton"]
}
],
"react/default-props-match-prop-types": ["error", { "allowRequiredDefaults": true }],
"react/forbid-prop-types": [
1,
{
"forbid": ["object", "any"]
}
],
"react/require-default-props": 0,
"react/no-array-index-key": 0,
"react/require-default-props": 0,
"react/state-in-constructor": 0,
"react/jsx-filename-extension": [
1,
{
"extensions": [".js", ".jsx"]
}
],
"react/jsx-props-no-spreading": 0,
"react/state-in-constructor": 0
},
"env": {
"jest/globals": true,
"browser": true
"prettier/prettier": "error",
"jsx-a11y/no-autofocus": "warn"
}
}
}

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
10

15
.prettierignore Normal file
View File

@ -0,0 +1,15 @@
!.eslintrc.js
build_webpack
config
contracts
flow-typed
flow-typed/npm
migrations
node_modules
public
scripts
src/assets
src/config
test
*.spec*
*.test*

View File

@ -1,6 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true
}
"printWidth": 120,
"trailingComma": "all",
"singleQuote": true,
"semi": false
}

View File

@ -19,19 +19,27 @@
"build": "REACT_APP_APP_VERSION=$npm_package_version node scripts/build.js",
"build-mainnet": "REACT_APP_NETWORK=mainnet yarn build",
"flow": "flow",
"precommit": "./precommit.sh",
"format:staged": "lint-staged",
"lint:check": "eslint './src/**/*.{js,jsx}'",
"lint:fix": "yarn lint:check --fix",
"prettier": "prettier './src/**/*.{js,jsx}'",
"prettier:check": "yarn prettier --check",
"prettier:fix": "yarn prettier --write",
"start": "node scripts/start.js",
"start-mainnet": "REACT_APP_NETWORK=mainnet yarn start",
"test": "NODE_ENV=test && node scripts/test.js --env=jsdom",
"format": "prettier-eslint $PWD'/src/**/*.{js,jsx}' --write",
"format:staged": "lint-staged"
"test": "NODE_ENV=test && node scripts/test.js --env=jsdom"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged --allow-empty"
}
},
"lint-staged": {
"./src/**/*.{js,jsx}": "prettier-eslint --write"
"src/**/*.{js,jsx}": [
"eslint --fix",
"prettier --write"
]
},
"pre-commit": [
"precommit"
],
"dependencies": {
"@gnosis.pm/safe-contracts": "1.1.1-dev.1",
"@gnosis.pm/util-contracts": "2.0.6",
@ -124,15 +132,13 @@
"css-loader": "3.4.0",
"detect-port": "^1.3.0",
"dotenv-expand": "^5.1.0",
"eslint": "6.7.2",
"eslint-config-airbnb": "18.0.1",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-flowtype": "4.5.2",
"eslint-plugin-import": "2.19.1",
"eslint-plugin-jest": "23.1.1",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-flowtype": "^4.6.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "7.17.0",
"eslint-plugin-react": "^7.18.3",
"ethereumjs-abi": "0.6.8",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "5.0.2",
@ -140,6 +146,7 @@
"fs-extra": "8.1.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"husky": "^4.2.2",
"jest": "24.9.0",
"jest-dom": "4.0.0",
"json-loader": "^0.5.7",
@ -147,9 +154,7 @@
"postcss-loader": "^3.0.0",
"postcss-mixins": "6.2.3",
"postcss-simple-vars": "^5.0.2",
"pre-commit": "^1.2.2",
"prettier": "^1.19.1",
"prettier-eslint-cli": "5.0.0",
"run-with-testrpc": "0.3.1",
"style-loader": "1.0.2",
"terser-webpack-plugin": "2.3.1",

View File

@ -1,41 +0,0 @@
#!/bin/bash
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep ".jsx\{0,1\}$")
ESLINT="$(git rev-parse --show-toplevel)/node_modules/.bin/eslint"
if [[ "$STAGED_FILES" = "" ]]; then
exit 0
fi
PASS=true
echo -e "\nValidating Javascript:\n"
# Check for eslint
if [[ ! -x "$ESLINT" ]]; then
echo -e "\t\033[41mPlease install ESlint\033[0m (npm i --save-dev eslint)"
exit 1
fi
for FILE in $STAGED_FILES
do
"$ESLINT" "$FILE" "--fix"
if [[ "$?" == 0 ]]; then
echo -e "\t\033[32mESLint Passed: $FILE\033[0m"
else
echo -e "\t\033[41mESLint Failed: $FILE\033[0m"
PASS=false
fi
done
echo -e "\nJavascript validation completed!\n"
if ! $PASS; then
echo -e "\033[0;31mCOMMIT FAILED, PLEASE FIX ESLINT ERRORS:\033[0m Your commit contains files that should pass ESLint but do not. Please fix the ESLint errors in a new commit.\n"
exit 1
else
echo -e "\033[42mCOMMIT SUCCEEDED\033[0m\n"
fi
exit $?

View File

@ -40,10 +40,7 @@ const List = ({ items, activeItem, onItemClick, classes }: Props) => {
{items.map(i => (
<Item
key={i.id}
className={cn(
classes.menuOption,
activeItem === i.id && classes.active
)}
className={cn(classes.menuOption, activeItem === i.id && classes.active)}
onClick={() => onItemClick(i.id)}
>
<div className="container">

View File

@ -35,7 +35,7 @@ const useStyles = makeStyles(() =>
height: 'auto',
position: 'static',
},
})
}),
)
type Props = {
@ -49,13 +49,7 @@ const GenericModal = ({ title, body, footer, onClose }: Props) => {
const classes = useStyles()
return (
<Modal
title="GenericModal"
description="GenericModal"
handleClose={onClose}
paperClassName={classes.paper}
open
>
<Modal title="GenericModal" description="GenericModal" handleClose={onClose} paperClassName={classes.paper} open>
<TitleSection>
{title}
<IconButton onClick={onClose} disableRipple>

View File

@ -20,13 +20,7 @@ const TitleWrapper = styled.div`
align-items: center;
`
export const ModalTitle = ({
title,
iconUrl,
}: {
title: string,
iconUrl: string,
}) => {
export const ModalTitle = ({ title, iconUrl }: { title: string, iconUrl: string }) => {
return (
<TitleWrapper>
{iconUrl && <IconImg src={iconUrl} alt={title} />}
@ -58,12 +52,7 @@ export const ModalFooterConfirmation = ({
<Button minWidth={130} onClick={handleCancel}>
{cancelText}
</Button>
<Button
color="primary"
minWidth={130}
onClick={handleOk}
variant="contained"
>
<Button color="primary" minWidth={130} onClick={handleOk} variant="contained">
{okText}
</Button>
</FooterWrapper>

View File

@ -143,14 +143,12 @@ const CookiesBanner = () => {
</span>
<div className={classes.content}>
<p className={classes.text}>
We use cookies to give you the best experience and to help improve our
website. Please read our{' '}
We use cookies to give you the best experience and to help improve our website. Please read our{' '}
<Link className={classes.link} to="https://safe.gnosis.io/cookie">
Cookie Policy
</Link>{' '}
for more information. By clicking &quot;Accept all&quot;, you agree to
the storing of cookies on your device to enhance site navigation,
analyze site usage and provide customer support.
for more information. By clicking &quot;Accept all&quot;, you agree to the storing of cookies on your device
to enhance site navigation, analyze site usage and provide customer support.
</p>
<div className={classes.form}>
<div className={classes.formItem}>

View File

@ -33,9 +33,7 @@ type EtherscanBtnProps = {
value: string,
}
const EtherscanBtn = ({
type, value, className, increaseZindex = false,
}: EtherscanBtnProps) => {
const EtherscanBtn = ({ type, value, className, increaseZindex = false }: EtherscanBtnProps) => {
const classes = useStyles()
const customClasses = increaseZindex ? { popper: classes.increasedPopperZindex } : {}

View File

@ -18,14 +18,9 @@ type EtherscanLinkProps = {
value: string,
}
const EtherscanLink = ({
type, value, cut, classes, knownAddress,
}: EtherscanLinkProps) => (
const EtherscanLink = ({ type, value, cut, classes, knownAddress }: EtherscanLinkProps) => (
<Block className={classes.etherscanLink}>
<Span
className={cn(knownAddress && classes.addressParagraph, classes.address)}
size="md"
>
<Span className={cn(knownAddress && classes.addressParagraph, classes.address)} size="md">
{cut ? shortVersionOf(value, cut) : value}
</Span>
<CopyBtn className={cn(classes.button, classes.firstButton)} content={value} />

View File

@ -42,9 +42,7 @@ const useStyles = makeStyles({
},
})
const appVersion = process.env.REACT_APP_APP_VERSION
? `v${process.env.REACT_APP_APP_VERSION} `
: 'Versions'
const appVersion = process.env.REACT_APP_APP_VERSION ? `v${process.env.REACT_APP_APP_VERSION} ` : 'Versions'
const Footer = () => {
const date = new Date()
@ -59,50 +57,27 @@ const Footer = () => {
<footer className={classes.footer}>
<span className={classes.item}>©{date.getFullYear()} Gnosis</span>
<span className={classes.sep}>|</span>
<Link
className={cn(classes.item, classes.link)}
to="https://safe.gnosis.io/terms"
target="_blank"
>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/terms" target="_blank">
Terms
</Link>
<span className={classes.sep}>|</span>
<Link
className={cn(classes.item, classes.link)}
to="https://safe.gnosis.io/privacy"
target="_blank"
>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/privacy" target="_blank">
Privacy
</Link>
<span className={classes.sep}>|</span>
<Link
className={cn(classes.item, classes.link)}
to="https://safe.gnosis.io/licenses"
target="_blank"
>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/licenses" target="_blank">
Licenses
</Link>
<span className={classes.sep}>|</span>
<Link
className={cn(classes.item, classes.link)}
to="https://safe.gnosis.io/imprint"
target="_blank"
>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/imprint" target="_blank">
Imprint
</Link>
<span className={classes.sep}>|</span>
<Link
className={cn(classes.item, classes.link)}
to="https://safe.gnosis.io/cookie"
target="_blank"
>
<Link className={cn(classes.item, classes.link)} to="https://safe.gnosis.io/cookie" target="_blank">
Cookie Policy
</Link>
<span className={classes.sep}>-</span>
<GnoButtonLink
className={cn(classes.item, classes.link, classes.buttonLink)}
onClick={openCookiesHandler}
>
<GnoButtonLink className={cn(classes.item, classes.link, classes.buttonLink)} onClick={openCookiesHandler}>
Preferences
</GnoButtonLink>
<span className={classes.sep}>|</span>

View File

@ -54,12 +54,7 @@ const buildKeyStyleFrom = (size: number, center: boolean, dotSize: number) => ({
borderRadius: `${size}px`,
})
const buildDotStyleFrom = (
size: number,
top: number,
right: number,
mode: Mode
) => ({
const buildDotStyleFrom = (size: number, top: number, right: number, mode: Mode) => ({
width: `${size}px`,
height: `${size}px`,
borderRadius: `${size}px`,

View File

@ -62,55 +62,42 @@ const styles = () => ({
},
})
const Layout = openHoc(
({
open,
toggle,
clickAway,
classes,
providerInfo,
providerDetails,
}: Props) => (
<Row className={classes.summary}>
<Col start="xs" middle="xs" className={classes.logo}>
<Link to="/">
<Img src={logo} height={32} alt="Gnosis Team Safe" />
</Link>
</Col>
<Divider />
<SafeListHeader />
<Divider />
<NetworkLabel />
<Spacer />
<Provider open={open} toggle={toggle} info={providerInfo}>
{providerRef => (
<Popper
anchorEl={providerRef.current}
className={classes.popper}
open={open}
placement="bottom"
popperOptions={{ positionFixed: true }}
>
{({ TransitionProps }) => (
<Grow {...TransitionProps}>
<>
<ClickAwayListener
onClickAway={clickAway}
mouseEvent="onClick"
touchEvent={false}
>
<List className={classes.root} component="div">
{providerDetails}
</List>
</ClickAwayListener>
</>
</Grow>
)}
</Popper>
)}
</Provider>
</Row>
)
)
const Layout = openHoc(({ open, toggle, clickAway, classes, providerInfo, providerDetails }: Props) => (
<Row className={classes.summary}>
<Col start="xs" middle="xs" className={classes.logo}>
<Link to="/">
<Img src={logo} height={32} alt="Gnosis Team Safe" />
</Link>
</Col>
<Divider />
<SafeListHeader />
<Divider />
<NetworkLabel />
<Spacer />
<Provider open={open} toggle={toggle} info={providerInfo}>
{providerRef => (
<Popper
anchorEl={providerRef.current}
className={classes.popper}
open={open}
placement="bottom"
popperOptions={{ positionFixed: true }}
>
{({ TransitionProps }) => (
<Grow {...TransitionProps}>
<>
<ClickAwayListener onClickAway={clickAway} mouseEvent="onClick" touchEvent={false}>
<List className={classes.root} component="div">
{providerDetails}
</List>
</ClickAwayListener>
</>
</Grow>
)}
</Popper>
)}
</Provider>
</Row>
))
export default withStyles(styles)(Layout)

View File

@ -7,8 +7,7 @@ import Col from '~/components/layout/Col'
import { xs, sm, md, border, screenSm } from '~/theme/variables'
const network = getNetwork()
const formattedNetwork =
network[0].toUpperCase() + network.substring(1).toLowerCase()
const formattedNetwork = network[0].toUpperCase() + network.substring(1).toLowerCase()
const useStyles = makeStyles({
container: {

View File

@ -62,12 +62,7 @@ class Provider extends React.Component<Props> {
<>
<div ref={this.myRef} className={classes.root}>
<Divider />
<Col
end="sm"
middle="xs"
className={classes.provider}
onClick={toggle}
>
<Col end="sm" middle="xs" className={classes.provider} onClick={toggle}>
{info}
<IconButton disableRipple className={classes.expand}>
{open ? <ExpandLess /> : <ExpandMore />}

View File

@ -13,9 +13,7 @@ import Img from '~/components/layout/Img'
import Row from '~/components/layout/Row'
import Block from '~/components/layout/Block'
import Spacer from '~/components/Spacer'
import {
xs, sm, md, lg, background, warning, connected as connectedBg,
} from '~/theme/variables'
import { xs, sm, md, lg, background, warning, connected as connectedBg } from '~/theme/variables'
import { upperFirst } from '~/utils/css'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import CircleDot from '~/components/Header/components/CircleDot'
@ -93,9 +91,7 @@ const styles = () => ({
},
})
const UserDetails = ({
provider, connected, network, userAddress, classes, onDisconnect,
}: Props) => {
const UserDetails = ({ provider, connected, network, userAddress, classes, onDisconnect }: Props) => {
const status = connected ? 'Connected' : 'Connection error'
const address = userAddress ? shortVersionOf(userAddress, 4) : 'Address not available'
const identiconAddress = userAddress || 'random'

View File

@ -54,17 +54,9 @@ const styles = () => ({
},
})
const ProviderInfo = ({
provider,
network,
userAddress,
connected,
classes,
}: Props) => {
const ProviderInfo = ({ provider, network, userAddress, connected, classes }: Props) => {
const providerText = `${provider} [${network}]`
const cutAddress = connected
? shortVersionOf(userAddress, 4)
: 'Connection Error'
const cutAddress = connected ? shortVersionOf(userAddress, 4) : 'Connection Error'
const color = connected ? 'primary' : 'warning'
const identiconAddress = userAddress || 'random'
@ -72,32 +64,13 @@ const ProviderInfo = ({
<>
{connected && (
<>
<Identicon
className={classes.identicon}
address={identiconAddress}
diameter={30}
/>
<Identicon className={classes.identicon} address={identiconAddress} diameter={30} />
<Dot className={classes.dot} />
</>
)}
{!connected && (
<CircleDot
keySize={14}
circleSize={35}
dotSize={16}
dotTop={24}
dotRight={11}
mode="warning"
/>
)}
{!connected && <CircleDot keySize={14} circleSize={35} dotSize={16} dotTop={24} dotRight={11} mode="warning" />}
<Col start="sm" layout="column" className={classes.account}>
<Paragraph
size="xs"
transform="capitalize"
className={classes.network}
noMargin
weight="bolder"
>
<Paragraph size="xs" transform="capitalize" className={classes.network} noMargin weight="bolder">
{providerText}
</Paragraph>
<Paragraph size="xs" className={classes.address} noMargin color={color}>

View File

@ -32,22 +32,9 @@ const styles = () => ({
const ProviderDisconnected = ({ classes }: Props) => (
<>
<CircleDot
keySize={17}
circleSize={35}
dotSize={16}
dotTop={24}
dotRight={11}
mode="error"
/>
<CircleDot keySize={17} circleSize={35} dotSize={16} dotTop={24} dotRight={11} mode="error" />
<Col end="sm" middle="xs" layout="column" className={classes.account}>
<Paragraph
size="sm"
transform="capitalize"
className={classes.network}
noMargin
weight="bold"
>
<Paragraph size="sm" transform="capitalize" className={classes.network} noMargin weight="bold">
Not Connected
</Paragraph>
<Paragraph size="sm" color="fancy" className={classes.connect} noMargin>

View File

@ -65,5 +65,5 @@ const SafeListHeader = ({ safesCount }: Props) => {
export default connect<Object, Object, ?Function, ?Object>(
// $FlowFixMe
state => ({ safesCount: safesCountSelector(state) }),
null
null,
)(SafeListHeader)

View File

@ -36,10 +36,7 @@ class HeaderComponent extends React.PureComponent<Props, State> {
async componentDidMount() {
const lastUsedProvider = await loadLastUsedProvider()
if (
INJECTED_PROVIDERS.includes(lastUsedProvider) ||
process.env.NODE_ENV === 'test'
) {
if (INJECTED_PROVIDERS.includes(lastUsedProvider) || process.env.NODE_ENV === 'test') {
web3Connect.connectToInjected()
}
}
@ -48,11 +45,7 @@ class HeaderComponent extends React.PureComponent<Props, State> {
const { enqueueSnackbar, closeSnackbar } = this.props
this.setState({ hasError: true })
showSnackbar(
NOTIFICATIONS.CONNECT_WALLET_ERROR_MSG,
enqueueSnackbar,
closeSnackbar
)
showSnackbar(NOTIFICATIONS.CONNECT_WALLET_ERROR_MSG, enqueueSnackbar, closeSnackbar)
logComponentStack(error, info)
}
@ -71,14 +64,7 @@ class HeaderComponent extends React.PureComponent<Props, State> {
return <ProviderDisconnected />
}
return (
<ProviderAccessible
provider={provider}
network={network}
userAddress={userAddress}
connected={available}
/>
)
return <ProviderAccessible provider={provider} network={network} userAddress={userAddress} connected={available} />
}
getProviderDetailsBased = () => {

View File

@ -62,13 +62,10 @@ export default class Identicon extends React.PureComponent<Props> {
return image
}
render() {
const { diameter, className } = this.props
const style = this.getStyleFrom(diameter)
return (
<div className={className} style={style} ref={this.identicon} />
)
return <div className={className} style={style} ref={this.identicon} />
}
}

View File

@ -20,24 +20,16 @@ const styles = {
class ListItemText extends React.PureComponent<Props> {
render() {
const {
primary, secondary, classes, cut = false,
} = this.props
const { primary, secondary, classes, cut = false } = this.props
const cutStyle = cut ? {
secondary: classes.itemTextSecondary,
} : undefined
const cutStyle = cut
? {
secondary: classes.itemTextSecondary,
}
: undefined
return (
<MuiListItemText
classes={cutStyle}
inset
primary={primary}
secondary={secondary}
/>
)
return <MuiListItemText classes={cutStyle} inset primary={primary} secondary={secondary} />
}
}
export default withStyles(styles)(ListItemText)

View File

@ -40,7 +40,14 @@ const styles = () => ({
})
const GnoModal = ({
title, description, open, children, handleClose, modalClassName, classes, paperClassName,
title,
description,
open,
children,
handleClose,
modalClassName,
classes,
paperClassName,
}: Props) => (
<Modal
aria-labelledby={title}

View File

@ -43,7 +43,7 @@ class Notifier extends Component<Props> {
componentDidUpdate() {
const { notifications = [], enqueueSnackbar, removeSnackbar } = this.props
notifications.forEach((notification) => {
notifications.forEach(notification => {
// Do nothing if snackbar is already displayed
if (this.displayed.includes(notification.key)) {
return
@ -66,7 +66,7 @@ class Notifier extends Component<Props> {
})
}
storeDisplayed = (id) => {
storeDisplayed = id => {
this.displayed = [...this.displayed, id]
}

View File

@ -24,9 +24,7 @@ type Props = {
isOpen: boolean,
}
const ScanQRModal = ({
classes, onClose, isOpen, onScan,
}: Props) => {
const ScanQRModal = ({ classes, onClose, isOpen, onScan }: Props) => {
const [hasWebcam, setHasWebcam] = useState(null)
const scannerRef: Object = React.createRef()
const openImageDialog = () => {
@ -73,10 +71,10 @@ const ScanQRModal = ({
<QrReader
ref={scannerRef}
legacyMode={!hasWebcam}
onScan={(data) => {
onScan={data => {
if (data) onScan(data)
}}
onError={(err) => {
onError={err => {
console.error(err)
}}
style={{ width: '400px', height: '400px' }}
@ -85,12 +83,7 @@ const ScanQRModal = ({
</Col>
<Hairline />
<Row align="center" className={classes.buttonRow}>
<Button
color="secondary"
className={classes.button}
minWidth={154}
onClick={onClose}
>
<Button color="secondary" className={classes.button} minWidth={154} onClick={onClose}>
Close
</Button>
<Button

View File

@ -1,7 +1,5 @@
// @flow
import {
lg, sm, background, secondaryText,
} from '~/theme/variables'
import { lg, sm, background, secondaryText } from '~/theme/variables'
export const styles = () => ({
heading: {

View File

@ -1,15 +1,17 @@
// @flow
navigator.getMedia = navigator.getUserMedia // use the proper vendor prefix
|| navigator.webkitGetUserMedia
|| navigator.mozGetUserMedia
|| navigator.msGetUserMedia
navigator.getMedia =
navigator.getUserMedia || // use the proper vendor prefix
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia
export const checkWebcam = (success: Function, err: Function) => navigator.getMedia(
{ video: true },
() => {
success()
},
() => {
err()
},
)
export const checkWebcam = (success: Function, err: Function) =>
navigator.getMedia(
{ video: true },
() => {
success()
},
() => {
err()
},
)

View File

@ -72,13 +72,7 @@ const useStyles = makeStyles({
},
})
const SafeList = ({
safes,
onSafeClick,
setDefaultSafe,
defaultSafe,
currentSafe,
}: SafeListProps) => {
const SafeList = ({ safes, onSafeClick, setDefaultSafe, defaultSafe, currentSafe }: SafeListProps) => {
const classes = useStyles()
return (
@ -99,11 +93,7 @@ const SafeList = ({
<div className={classes.noIcon}>placeholder</div>
)}
<ListItemIcon>
<Identicon
address={safe.address}
diameter={32}
className={classes.icon}
/>
<Identicon address={safe.address} diameter={32} className={classes.icon} />
</ListItemIcon>
<ListItemText
primary={safe.name}

View File

@ -14,10 +14,7 @@ import Hairline from '~/components/layout/Hairline'
import Row from '~/components/layout/Row'
import { WELCOME_ADDRESS } from '~/routes/routes'
import { type Safe } from '~/routes/safe/store/models/safe'
import {
defaultSafeSelector,
safeParamAddressFromStateSelector,
} from '~/routes/safe/store/selectors'
import { defaultSafeSelector, safeParamAddressFromStateSelector } from '~/routes/safe/store/selectors'
import setDefaultSafe from '~/routes/safe/store/actions/setDefaultSafe'
import { sortedSafeListSelector } from './selectors'
import SafeList from './SafeList'
@ -48,16 +45,10 @@ const filterBy = (filter: string, safes: List<Safe>): List<Safe> =>
(safe: Safe) =>
!filter ||
safe.address.toLowerCase().includes(filter.toLowerCase()) ||
safe.name.toLowerCase().includes(filter.toLowerCase())
safe.name.toLowerCase().includes(filter.toLowerCase()),
)
const Sidebar = ({
children,
safes,
setDefaultSafeAction,
defaultSafe,
currentSafe,
}: SidebarProps) => {
const Sidebar = ({ children, safes, setDefaultSafeAction, defaultSafe, currentSafe }: SidebarProps) => {
const [isOpen, setIsOpen] = useState<boolean>(false)
const [filter, setFilter] = useState<string>('')
const classes = useSidebarStyles()
@ -154,5 +145,5 @@ export default connect<Object, Object, ?Function, ?Object>(
defaultSafe: defaultSafeSelector(state),
currentSafe: safeParamAddressFromStateSelector(state),
}),
{ setDefaultSafeAction: setDefaultSafe }
{ setDefaultSafeAction: setDefaultSafe },
)(Sidebar)

View File

@ -1,13 +1,6 @@
// @flow
import { makeStyles } from '@material-ui/core/styles'
import {
xs,
mediumFontSize,
secondaryText,
md,
headerHeight,
screenSm,
} from '~/theme/variables'
import { xs, mediumFontSize, secondaryText, md, headerHeight, screenSm } from '~/theme/variables'
const sidebarWidth = '400px'
const sidebarMarginLeft = '12px'

View File

@ -9,6 +9,5 @@ const style = {
flexGrow: 1,
}
export default ({ className }: Props) => (
<div className={className} style={style} />
)
// eslint-disable-next-line react/display-name
export default ({ className }: Props) => <div className={className} style={style} />

View File

@ -30,15 +30,7 @@ type Props = {
buttonLabels?: Array<string>,
}
const Controls = ({
onPrevious,
firstPage,
penultimate,
lastPage,
disabled,
currentStep,
buttonLabels,
}: Props) => {
const Controls = ({ onPrevious, firstPage, penultimate, lastPage, disabled, currentStep, buttonLabels }: Props) => {
const back = firstPage ? 'Cancel' : 'Back'
let next

View File

@ -23,9 +23,7 @@ type Props = {
padding?: boolean,
}
const OpenPaper = ({
classes, children, controls, padding = true,
}: Props) => (
const OpenPaper = ({ classes, children, controls, padding = true }: Props) => (
<Paper className={classes.root} elevation={1}>
<Block className={padding ? classes.padding : ''}>{children}</Block>
{controls}

View File

@ -5,10 +5,6 @@ type Props = {
children: React.Node,
}
const Step = ({ children }: Props) => (
<div>
{children}
</div>
)
const Step = ({ children }: Props) => <div>{children}</div>
export default Step

View File

@ -52,7 +52,7 @@ const GnoStepper = (props: Props) => {
const getPageProps = (pages: React.Node): PageProps => React.Children.toArray(pages)[page].props
const updateInitialProps = (newInitialProps) => {
const updateInitialProps = newInitialProps => {
setValues(newInitialProps)
}
@ -105,14 +105,12 @@ const GnoStepper = (props: Props) => {
return next(formValues)
}
const isLastPage = (pageNumber) => {
const isLastPage = pageNumber => {
const { steps } = props
return pageNumber === steps.length - 1
}
const {
steps, children, classes, disabledWhenValidating = false, testId, mutators, buttonLabels,
} = props
const { steps, children, classes, disabledWhenValidating = false, testId, mutators, buttonLabels } = props
const activePage = getActivePageFrom(children)
const lastPage = isLastPage(page)

View File

@ -57,9 +57,7 @@ class GnoTableHead extends React.PureComponent<Props> {
sortDirection={orderBy === column.id ? order : false}
>
{column.static ? (
<div style={column.style}>
{column.label}
</div>
<div style={column.style}>{column.label}</div>
) : (
<TableSortLabel
active={orderBy === column.id}

View File

@ -157,9 +157,7 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
noBorder,
disableLoadingOnEmptyTable,
} = this.props
const {
order, orderBy, page, orderProp, rowsPerPage, fixed,
} = this.state
const { order, orderBy, page, orderProp, rowsPerPage, fixed } = this.state
const orderByParam = orderBy || defaultOrderBy
const orderParam = order || defaultOrder
const displayRows = rowsPerPage || defaultRowsPerPage
@ -189,10 +187,7 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
</Table>
)}
{isEmpty && (
<Row
className={classes.loader}
style={this.getEmptyStyle(emptyRows + 1)}
>
<Row className={classes.loader} style={this.getEmptyStyle(emptyRows + 1)}>
<CircularProgress size={60} />
</Row>
)}

View File

@ -39,13 +39,14 @@ export const stableSort = (dataArray: List<any>, cmp: any, fixed: boolean): List
return a[1] - b[1]
})
const sortedElems: List<any> = stabilizedThis.map((el) => el[0])
const sortedElems: List<any> = stabilizedThis.map(el => el[0])
return fixedElems.concat(sortedElems)
}
export type Order = 'asc' | 'desc'
export const getSorting = (order: Order, orderBy: string, orderProp: boolean) => (order === 'desc'
? (a: any, b: any) => desc(a, b, orderBy, orderProp)
: (a: any, b: any) => -desc(a, b, orderBy, orderProp))
export const getSorting = (order: Order, orderBy: string, orderProp: boolean) =>
order === 'desc'
? (a: any, b: any) => desc(a, b, orderBy, orderProp)
: (a: any, b: any) => -desc(a, b, orderBy, orderProp)

View File

@ -3,11 +3,7 @@ import * as React from 'react'
import { Field } from 'react-final-form'
import { OnChange } from 'react-final-form-listeners'
import TextField from '~/components/forms/TextField'
import {
composeValidators,
required,
mustBeEthereumAddress,
} from '~/components/forms/validator'
import { composeValidators, required, mustBeEthereumAddress } from '~/components/forms/validator'
import { getAddressFromENS } from '~/logic/wallets/getWeb3'
type Props = {
@ -23,7 +19,7 @@ type Props = {
disabled?: boolean,
}
const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
const isValidEnsName = name => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
// an idea for second field was taken from here
// https://github.com/final-form/react-final-form-listeners/blob/master/src/OnBlur.js
@ -45,11 +41,7 @@ const AddressInput = ({
name={name}
component={TextField}
type="text"
validate={composeValidators(
required,
mustBeEthereumAddress,
...validators,
)}
validate={composeValidators(required, mustBeEthereumAddress, ...validators)}
inputAdornment={inputAdornment}
placeholder={placeholder}
text={text}
@ -59,7 +51,7 @@ const AddressInput = ({
disabled={disabled}
/>
<OnChange name={name}>
{async (value) => {
{async value => {
if (isValidEnsName(value)) {
try {
const resolverAddr = await getAddressFromENS(value)

View File

@ -5,22 +5,11 @@ import Checkbox, { type CheckoxProps } from '@material-ui/core/Checkbox'
class GnoCheckbox extends React.PureComponent<CheckoxProps> {
render() {
const {
input: {
checked, name, onChange, ...restInput
},
meta,
input: { checked, name, onChange, ...restInput },
...rest
} = this.props
return (
<Checkbox
{...rest}
name={name}
inputProps={restInput}
onChange={onChange}
checked={!!checked}
/>
)
return <Checkbox {...rest} name={name} inputProps={restInput} onChange={onChange} checked={!!checked} />
}
}

View File

@ -6,7 +6,7 @@ import { Form } from 'react-final-form'
export type OnSubmit = (
values: Object,
form: FormApi,
callback: ?(errors: ?Object) => ?Object
callback: ?(errors: ?Object) => ?Object,
) => ?Object | Promise<?Object> | void
type Props = {
@ -25,9 +25,7 @@ const stylesBasedOn = (padding: number): $Shape<CSSStyleDeclaration> => ({
flex: '1 0 auto',
})
const GnoForm = ({
onSubmit, validation, initialValues, children, padding = 0, formMutators, testId = '',
}: Props) => (
const GnoForm = ({ onSubmit, validation, initialValues, children, padding = 0, formMutators, testId = '' }: Props) => (
<Form
validate={validation}
onSubmit={onSubmit}

View File

@ -10,9 +10,7 @@ const style = {
}
const SelectInput = ({
input: {
name, value, onChange, ...restInput
},
input: { name, value, onChange, ...restInput },
meta,
label,
formControlProps,

View File

@ -21,11 +21,8 @@ const styles = () => ({
class TextField extends React.PureComponent<TextFieldProps> {
render() {
const {
input: {
name, onChange, value, ...restInput
},
input: { name, onChange, value, ...restInput },
meta,
render,
text,
inputAdornment,
classes,

View File

@ -23,13 +23,7 @@ const styles = () => ({
})
const TextareaField = ({ classes, ...props }: TextFieldProps) => (
<Field
{...props}
component={TextField}
multiline
rows="5"
className={classes.textarea}
/>
<Field {...props} component={TextField} multiline rows="5" className={classes.textarea} />
)
export default withStyles(styles)(TextareaField)

View File

@ -20,7 +20,8 @@ type Field = boolean | string | null | typeof undefined
export const required = (value: Field) => (value ? undefined : 'Required')
export const mustBeInteger = (value: string) => (!Number.isInteger(Number(value)) || value.includes('.') ? 'Must be an integer' : undefined)
export const mustBeInteger = (value: string) =>
!Number.isInteger(Number(value)) || value.includes('.') ? 'Must be an integer' : undefined
export const mustBeFloat = (value: number) => (value && Number.isNaN(Number(value)) ? 'Must be a number' : undefined)
@ -75,16 +76,19 @@ export const mustBeEthereumContractAddress = simpleMemoize(async (address: strin
: undefined
})
export const minMaxLength = (minLen: string | number, maxLen: string | number) => (value: string) => (value.length >= +minLen && value.length <= +maxLen ? undefined : `Should be ${minLen} to ${maxLen} symbols`)
export const minMaxLength = (minLen: string | number, maxLen: string | number) => (value: string) =>
value.length >= +minLen && value.length <= +maxLen ? undefined : `Should be ${minLen} to ${maxLen} symbols`
export const ADDRESS_REPEATED_ERROR = 'Address already introduced'
export const uniqueAddress = (addresses: string[] | List<string>) => simpleMemoize((value: string) => {
const addressAlreadyExists = addresses.some((address) => sameAddress(value, address))
return addressAlreadyExists ? ADDRESS_REPEATED_ERROR : undefined
})
export const uniqueAddress = (addresses: string[] | List<string>) =>
simpleMemoize((value: string) => {
const addressAlreadyExists = addresses.some(address => sameAddress(value, address))
return addressAlreadyExists ? ADDRESS_REPEATED_ERROR : undefined
})
export const composeValidators = (...validators: Function[]): FieldValidator => (value: Field) => validators.reduce((error, validator) => error || validator(value), undefined)
export const composeValidators = (...validators: Function[]): FieldValidator => (value: Field) =>
validators.reduce((error, validator) => error || validator(value), undefined)
export const inLimit = (limit: number, base: number, baseText: string, symbol: string = 'ETH') => (value: string) => {
const amount = Number(value)

View File

@ -7,10 +7,7 @@ export type Open = {
clickAway: () => void,
}
export default withStateHandlers(
() => ({ open: false }),
{
toggle: ({ open }) => () => ({ open: !open }),
clickAway: () => () => ({ open: false }),
},
)
export default withStateHandlers(() => ({ open: false }), {
toggle: ({ open }) => () => ({ open: !open }),
clickAway: () => () => ({ open: false }),
})

View File

@ -19,9 +19,7 @@ type Props = {
class Block extends PureComponent<Props> {
render() {
const {
margin, padding, justify, children, className, ...props
} = this.props
const { margin, padding, justify, children, className, ...props } = this.props
const paddingStyle = padding ? capitalize(padding, 'padding') : undefined
return (

View File

@ -14,9 +14,7 @@ const calculateStyleBased = (minWidth, minHeight) => ({
minHeight: minHeight && `${minHeight}px`,
})
const GnoButton = ({
minWidth, minHeight = 35, testId = '', style = {}, ...props
}: Props) => {
const GnoButton = ({ minWidth, minHeight = 35, testId = '', style = {}, ...props }: Props) => {
const calculatedStyle = calculateStyleBased(minWidth, minHeight)
return <Button style={{ ...calculatedStyle, ...style }} data-testid={testId} {...props} />

View File

@ -23,6 +23,8 @@ const GnoButtonLink = ({
testId = '',
className = '',
...props
}: Props) => <button type={type} className={cx(styles.btnLink, size, color, weight, className)} data-testid={testId} {...props} />
}: Props) => (
<button type={type} className={cx(styles.btnLink, size, color, weight, className)} data-testid={testId} {...props} />
)
export default GnoButtonLink

View File

@ -11,8 +11,6 @@ const style = {
height: '100%',
}
const Divider = ({ className }: Props) => (
<div className={className} style={style} />
)
const Divider = ({ className }: Props) => <div className={className} style={style} />
export default Divider

View File

@ -20,9 +20,7 @@ type Props = {
}
const Heading = (props: Props) => {
const {
align, tag, truncate, margin, color, children, testId, className = '', ...rest
} = props
const { align, tag, truncate, margin, color, children, testId, className = '', ...rest } = props
const classes = cx(className, 'heading', align, tag, margin ? capitalize(margin, 'margin') : undefined, color, {
truncate,

View File

@ -14,9 +14,7 @@ type Props = {
testId?: string,
}
const Img = ({
fullwidth, alt, bordered, className, style, testId = '', ...props
}: Props) => {
const Img = ({ fullwidth, alt, bordered, className, style, testId = '', ...props }: Props) => {
const classes = cx(styles.img, { fullwidth, bordered }, className)
return <img alt={alt} style={style} className={classes} data-testid={testId} {...props} />

View File

@ -16,9 +16,7 @@ type Props = {
innerRef?: React.ElementRef<any>,
}
const GnosisLink = ({
to, children, color, className, padding, innerRef, ...props
}: Props) => {
const GnosisLink = ({ to, children, color, className, padding, innerRef, ...props }: Props) => {
const internal = /^\/(?!\/)/.test(to)
const classes = cx(styles.link, color || 'regular', padding ? capitalize(padding, 'padding') : undefined, className)
const LinkElement = internal ? Link : 'a'
@ -29,13 +27,7 @@ const GnosisLink = ({
}
return (
<LinkElement
className={classes}
href={internal ? null : to}
to={internal ? to : null}
{...refs}
{...props}
>
<LinkElement className={classes} href={internal ? null : to} to={internal ? to : null} {...refs} {...props}>
{children}
</LinkElement>
)

View File

@ -8,13 +8,11 @@ const cx = classNames.bind(styles)
type Props = {
children: React.Node,
align?: 'center',
overflow?: boolean
overflow?: boolean,
}
const Page = ({ children, align, overflow }: Props) => (
<main className={cx(styles.page, align, { overflow })}>
{children}
</main>
<main className={cx(styles.page, align, { overflow })}>{children}</main>
)
export default Page

View File

@ -78,7 +78,7 @@ const PageFrame = ({ children, classes, currentNetwork }: Props) => {
export default withStyles(notificationStyles)(
connect(
(state) => ({
state => ({
currentNetwork: networkSelector(state),
}),
null,

View File

@ -20,9 +20,7 @@ type Props = {
class Paragraph extends React.PureComponent<Props> {
render() {
const {
weight, children, color, align, size, transform, noMargin, className, dot, ...props
} = this.props
const { weight, children, color, align, size, transform, noMargin, className, dot, ...props } = this.props
return (
<p

View File

@ -15,9 +15,7 @@ type Props = {
testId?: string,
}
const Row = ({
children, className, margin, align, grow, testId = '', ...props
}: Props) => {
const Row = ({ children, className, margin, align, grow, testId = '', ...props }: Props) => {
const rowClassNames = cx(
styles.row,
margin ? capitalize(margin, 'margin') : undefined,

View File

@ -6,13 +6,11 @@ import TableCell from '@material-ui/core/TableCell'
import TableHead from '@material-ui/core/TableHead'
import TableRow from '@material-ui/core/TableRow'
export {
TableBody, TableCell, TableHead, TableRow,
}
export { TableBody, TableCell, TableHead, TableRow }
type Props = {
children: React.Node,
size?: number
size?: number,
}
const buildWidthFrom = (size: number) => ({
@ -29,9 +27,7 @@ const GnoTable = ({ size, children }: Props) => {
return (
<div style={overflowStyle}>
<Table style={style}>
{children}
</Table>
<Table style={style}>{children}</Table>
</div>
)
}

View File

@ -2,13 +2,13 @@
import type { RecordOf } from 'immutable'
export type AddressBookEntry = {
address: string;
name: string;
isOwner: boolean;
address: string,
name: string,
isOwner: boolean,
}
export type AddressBookProps = {
addressBook: Map<string, AddressBookEntry>
addressBook: Map<string, AddressBookEntry>,
}
export type AddressBook = RecordOf<AddressBookProps>

View File

@ -4,7 +4,9 @@ import type { AddressBookEntryType } from '~/logic/addressBook/model/addressBook
export const ADD_ENTRY = 'ADD_ENTRY'
export const addAddressBookEntry = createAction<string, *, *>(ADD_ENTRY, (entry: AddressBookEntryType): AddressBookEntryType => ({
entry,
}))
export const addAddressBookEntry = createAction<string, *, *>(
ADD_ENTRY,
(entry: AddressBookEntryType): AddressBookEntryType => ({
entry,
}),
)

View File

@ -4,4 +4,6 @@ import type { AddressBook } from '~/logic/addressBook/model/addressBook'
export const LOAD_ADDRESS_BOOK = 'LOAD_ADDRESS_BOOK'
export const loadAddressBook = createAction<string, *, *>(LOAD_ADDRESS_BOOK, (addressBook: AddressBook) => ({ addressBook }))
export const loadAddressBook = createAction<string, *, *>(LOAD_ADDRESS_BOOK, (addressBook: AddressBook) => ({
addressBook,
}))

View File

@ -18,7 +18,7 @@ const loadAddressBookFromStorage = () => async (dispatch: ReduxDispatch<GlobalSt
// Fetch all the current safes, in case that we don't have a safe on the adbk, we add it
const safes = safesListSelector(state)
const adbkEntries = addressBook.keySeq().toArray()
safes.forEach((safe) => {
safes.forEach(safe => {
const { address } = safe
const found = adbkEntries.includes(address)
if (!found) {

View File

@ -3,7 +3,6 @@ import { createAction } from 'redux-actions'
export const REMOVE_ENTRY = 'REMOVE_ENTRY'
export const removeAddressBookEntry = createAction<string, *, *>(REMOVE_ENTRY, (entryAddress: string): void => ({
entryAddress,
}))

View File

@ -4,7 +4,9 @@ import type { AddressBookEntry } from '~/logic/addressBook/model/addressBook'
export const UPDATE_ENTRY = 'UPDATE_ENTRY'
export const updateAddressBookEntry = createAction<string, *, *>(UPDATE_ENTRY, (entry: AddressBookEntry): AddressBookEntry => ({
entry,
}))
export const updateAddressBookEntry = createAction<string, *, *>(
UPDATE_ENTRY,
(entry: AddressBookEntry): AddressBookEntry => ({
entry,
}),
)

View File

@ -11,12 +11,7 @@ import enqueueSnackbar from '~/logic/notifications/store/actions/enqueueSnackbar
import { saveAddressBook } from '~/logic/addressBook/utils'
import type { AddressBookProps } from '~/logic/addressBook/model/addressBook'
const watchedActions = [
ADD_ENTRY,
REMOVE_ENTRY,
UPDATE_ENTRY,
]
const watchedActions = [ADD_ENTRY, REMOVE_ENTRY, UPDATE_ENTRY]
const addressBookMiddleware = (store: Store<GlobalState>) => (next: Function) => async (action: AnyAction) => {
const handledAction = next(action)

View File

@ -24,7 +24,6 @@ export const buildAddressBook = (storedAdbk: AddressBook): AddressBookProps => {
return addressBookBuilt
}
export default handleActions<State, *>(
{
[LOAD_ADDRESS_BOOK]: (state: State, action: ActionType<Function>): State => {
@ -44,23 +43,22 @@ export default handleActions<State, *>(
const { entry } = action.payload
// Adds the entry to all the safes (if it does not already exists)
const newState = state.withMutations((map) => {
const newState = state.withMutations(map => {
const adbkMap = map.get('addressBook')
if (adbkMap) {
adbkMap.keySeq()
.forEach((safeAddress) => {
const safeAddressBook = state.getIn(['addressBook', safeAddress])
adbkMap.keySeq().forEach(safeAddress => {
const safeAddressBook = state.getIn(['addressBook', safeAddress])
if (safeAddressBook) {
const adbkAddressList = getAddressesListFromAdbk(safeAddressBook)
const found = adbkAddressList.includes(entry.address)
if (!found) {
const updatedSafeAdbkList = safeAddressBook.push(entry)
map.setIn(['addressBook', safeAddress], updatedSafeAdbkList)
}
if (safeAddressBook) {
const adbkAddressList = getAddressesListFromAdbk(safeAddressBook)
const found = adbkAddressList.includes(entry.address)
if (!found) {
const updatedSafeAdbkList = safeAddressBook.push(entry)
map.setIn(['addressBook', safeAddress], updatedSafeAdbkList)
}
})
}
})
}
})
return newState
@ -69,13 +67,13 @@ export default handleActions<State, *>(
const { entry } = action.payload
// Updates the entry from all the safes
const newState = state.withMutations((map) => {
const newState = state.withMutations(map => {
map
.get('addressBook')
.keySeq()
.forEach((safeAddress) => {
.forEach(safeAddress => {
const entriesList: List<AddressBookEntry> = state.getIn(['addressBook', safeAddress])
const entryIndex = entriesList.findIndex((entryItem) => sameAddress(entryItem.address, entry.address))
const entryIndex = entriesList.findIndex(entryItem => sameAddress(entryItem.address, entry.address))
const updatedEntriesList = entriesList.set(entryIndex, entry)
map.setIn(['addressBook', safeAddress], updatedEntriesList)
})
@ -86,13 +84,13 @@ export default handleActions<State, *>(
[REMOVE_ENTRY]: (state: State, action: ActionType<Function>): State => {
const { entryAddress } = action.payload
// Removes the entry from all the safes
const newState = state.withMutations((map) => {
const newState = state.withMutations(map => {
map
.get('addressBook')
.keySeq()
.forEach((safeAddress) => {
.forEach(safeAddress => {
const entriesList = state.getIn(['addressBook', safeAddress])
const entryIndex = entriesList.findIndex((entry) => sameAddress(entry.address, entryAddress))
const entryIndex = entriesList.findIndex(entry => sameAddress(entry.address, entryAddress))
const updatedEntriesList = entriesList.remove(entryIndex)
map.setIn(['addressBook', safeAddress], updatedEntriesList)
})

View File

@ -1,3 +1,4 @@
/* eslint-disable import/named */
// @flow
import { List, Map } from 'immutable'
import { createSelector, Selector } from 'reselect'
@ -7,7 +8,8 @@ import type { GlobalState } from '~/store'
import type { AddressBook } from '~/logic/addressBook/model/addressBook'
import { safeParamAddressFromStateSelector } from '~/routes/safe/store/selectors'
export const addressBookMapSelector = (state: GlobalState): Map<string, AddressBook> => state[ADDRESS_BOOK_REDUCER_ID].get('addressBook')
export const addressBookMapSelector = (state: GlobalState): Map<string, AddressBook> =>
state[ADDRESS_BOOK_REDUCER_ID].get('addressBook')
export const getAddressBook: Selector<GlobalState, AddressBook> = createSelector(
addressBookMapSelector,
@ -38,7 +40,7 @@ export const getNameFromAddressBook = (userAddress: string): string | null => {
return null
}
const addressBook = useSelector(getAddressBook)
const result = addressBook.filter((addressBookItem) => addressBookItem.address === userAddress)
const result = addressBook.filter(addressBookItem => addressBookItem.address === userAddress)
if (result.size > 0) {
return result.get(0).name
}

View File

@ -21,10 +21,11 @@ export const saveAddressBook = async (addressBook: AddressBook) => {
}
}
export const getAddressesListFromAdbk = (addressBook: AddressBook) => Array.from(addressBook).map((entry) => entry.address)
export const getAddressesListFromAdbk = (addressBook: AddressBook) =>
Array.from(addressBook).map(entry => entry.address)
const getNameFromAdbk = (addressBook: AddressBook, userAddress: string): string | null => {
const entry = addressBook.find((addressBookItem) => addressBookItem.address === userAddress)
const entry = addressBook.find(addressBookItem => addressBookItem.address === userAddress)
if (entry) {
return entry.name
}
@ -39,12 +40,11 @@ export const getNameFromAddressBook = (userAddress: string): string | null => {
return getNameFromAdbk(addressBook, userAddress)
}
export const getOwnersWithNameFromAddressBook = (addressBook: AddressBook, ownerList: List<Owner>) => {
if (!ownerList) {
return []
}
const ownersListWithAdbkNames = ownerList.map((owner) => {
const ownersListWithAdbkNames = ownerList.map(owner => {
const ownerName = getNameFromAdbk(addressBook, owner.address)
return {
address: owner.address,

View File

@ -3,4 +3,6 @@ import { createAction } from 'redux-actions'
export const OPEN_COOKIE_BANNER = 'OPEN_COOKIE_BANNER'
export const openCookieBanner = createAction<string, *, *>(OPEN_COOKIE_BANNER, (cookieBannerOpen: boolean) => ({ cookieBannerOpen }))
export const openCookieBanner = createAction<string, *, *>(OPEN_COOKIE_BANNER, (cookieBannerOpen: boolean) => ({
cookieBannerOpen,
}))

View File

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

View File

@ -7,14 +7,15 @@ import fetchCurrenciesRates from '~/logic/currencyValues/api/fetchCurrenciesRate
import { currencyValuesListSelector } from '~/logic/currencyValues/store/selectors'
import { setCurrencyBalances } from '~/logic/currencyValues/store/actions/setCurrencyBalances'
// eslint-disable-next-line max-len
const fetchCurrencySelectedValue = (currencyValueSelected: AVAILABLE_CURRENCIES) => async (dispatch: ReduxDispatch<GlobalState>, getState: Function) => {
const fetchCurrencySelectedValue = (currencyValueSelected: AVAILABLE_CURRENCIES) => async (
dispatch: ReduxDispatch<GlobalState>,
getState: Function,
) => {
const state = getState()
const currencyBalancesList = currencyValuesListSelector(state)
const selectedCurrencyRateInBaseCurrency = await fetchCurrenciesRates(AVAILABLE_CURRENCIES.USD, currencyValueSelected)
const newList = []
for (const currencyValue of currencyBalancesList) {
const { balanceInBaseCurrency } = currencyValue

View File

@ -10,21 +10,24 @@ import { loadFromStorage } from '~/utils/storage'
import fetchCurrencySelectedValue from '~/logic/currencyValues/store/actions/fetchCurrencySelectedValue'
import { CURRENCY_SELECTED_KEY } from '~/logic/currencyValues/store/actions/saveCurrencySelected'
export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
try {
const tokensFetched = await fetchTokenCurrenciesBalances(safeAddress)
// eslint-disable-next-line max-len
const currencyList = List(tokensFetched.data.filter((currencyBalance) => currencyBalance.balanceUsd).map((currencyBalance) => {
const { balanceUsd, tokenAddress } = currencyBalance
return makeBalanceCurrency({
currencyName: balanceUsd ? AVAILABLE_CURRENCIES.USD : null,
tokenAddress,
balanceInBaseCurrency: balanceUsd,
balanceInSelectedCurrency: balanceUsd,
})
}))
const currencyList = List(
tokensFetched.data
.filter(currencyBalance => currencyBalance.balanceUsd)
.map(currencyBalance => {
const { balanceUsd, tokenAddress } = currencyBalance
return makeBalanceCurrency({
currencyName: balanceUsd ? AVAILABLE_CURRENCIES.USD : null,
tokenAddress,
balanceInBaseCurrency: balanceUsd,
balanceInSelectedCurrency: balanceUsd,
})
}),
)
dispatch(setCurrencyBalances(currencyList))
const currencyStored = await loadFromStorage(CURRENCY_SELECTED_KEY)

View File

@ -7,10 +7,11 @@ import type { GlobalState } from '~/store'
import { saveToStorage } from '~/utils/storage'
import { setCurrencySelected } from '~/logic/currencyValues/store/actions/setCurrencySelected'
export const CURRENCY_SELECTED_KEY = 'CURRENCY_SELECTED_KEY'
const saveCurrencySelected = (currencySelected: AVAILABLE_CURRENCIES) => async (dispatch: ReduxDispatch<GlobalState>) => {
const saveCurrencySelected = (currencySelected: AVAILABLE_CURRENCIES) => async (
dispatch: ReduxDispatch<GlobalState>,
) => {
await saveToStorage(CURRENCY_SELECTED_KEY, { currencyValueSelected: currencySelected })
dispatch(setCurrencySelected(currencySelected))
}

View File

@ -5,6 +5,8 @@ import type { CurrencyValues, CurrencyValuesProps } from '~/logic/currencyValues
export const SET_CURRENCY_BALANCES = 'SET_CURRENCY_BALANCES'
// eslint-disable-next-line max-len
export const setCurrencyBalances = createAction<string, *>(SET_CURRENCY_BALANCES, (currencyBalances: Map<string, CurrencyValues>): CurrencyValuesProps => ({ currencyBalances }))
export const setCurrencyBalances = createAction<string, *>(
SET_CURRENCY_BALANCES,
(currencyBalances: Map<string, CurrencyValues>): CurrencyValuesProps => ({ currencyBalances }),
)

View File

@ -1,13 +1,12 @@
// @flow
import { createAction } from 'redux-actions'
import type {
CurrencyValuesProps,
} from '~/logic/currencyValues/store/model/currencyValues'
import type { CurrencyValuesProps } from '~/logic/currencyValues/store/model/currencyValues'
import { AVAILABLE_CURRENCIES } from '~/logic/currencyValues/store/model/currencyValues'
export const SET_CURRENT_CURRENCY = 'SET_CURRENT_CURRENCY'
// eslint-disable-next-line max-len
export const setCurrencySelected = createAction<string, *>(SET_CURRENT_CURRENCY, (currencyValueSelected: AVAILABLE_CURRENCIES): CurrencyValuesProps => ({ currencyValueSelected }))
export const setCurrencySelected = createAction<string, *>(
SET_CURRENT_CURRENCY,
(currencyValueSelected: AVAILABLE_CURRENCIES): CurrencyValuesProps => ({ currencyValueSelected }),
)

View File

@ -38,9 +38,8 @@ export const AVAILABLE_CURRENCIES = {
MYR: 'MYR',
}
export type BalanceCurrencyType = {
currencyName: AVAILABLE_CURRENCIES;
currencyName: AVAILABLE_CURRENCIES,
tokenAddress: string,
balanceInBaseCurrency: string,
balanceInSelectedCurrency: string,
@ -54,8 +53,8 @@ export const makeBalanceCurrency = Record({
})
export type CurrencyValuesProps = {
currencyValueSelected: AVAILABLE_CURRENCIES;
currencyValuesList: BalanceCurrencyType[]
currencyValueSelected: AVAILABLE_CURRENCIES,
currencyValuesList: BalanceCurrencyType[],
}
export type CurrencyValues = RecordOf<CurrencyValuesProps>

View File

@ -4,6 +4,6 @@ import { List } from 'immutable'
import { type GlobalState } from '~/store'
import { CURRENCY_VALUES_KEY } from '~/logic/currencyValues/store/reducer/currencyValues'
export const currencyValuesListSelector = (state: GlobalState) => (state[CURRENCY_VALUES_KEY].get('currencyBalances') ? state[CURRENCY_VALUES_KEY].get('currencyBalances') : List([]))
export const currencyValuesListSelector = (state: GlobalState) =>
state[CURRENCY_VALUES_KEY].get('currencyBalances') ? state[CURRENCY_VALUES_KEY].get('currencyBalances') : List([])
export const currentCurrencySelector = (state: GlobalState) => state[CURRENCY_VALUES_KEY].get('currencyValueSelected')

View File

@ -6,7 +6,7 @@ import loadCurrentSession from '~/logic/currentSession/store/actions/loadCurrent
import { makeCurrentSession } from '~/logic/currentSession/store/model/currentSession'
const loadCurrentSessionFromStorage = () => async (dispatch: ReduxDispatch<GlobalState>) => {
const currentSession = (await getCurrentSessionFromStorage())
const currentSession = await getCurrentSessionFromStorage()
dispatch(loadCurrentSession(makeCurrentSession(currentSession ? currentSession : {})))
}

View File

@ -1,7 +1,5 @@
// @flow
import {
Record, type RecordFactory, type RecordOf,
} from 'immutable'
import { Record, type RecordFactory, type RecordOf } from 'immutable'
export type CurrentSessionProps = {
viewedSafes: Array<string>,

View File

@ -11,16 +11,12 @@ export type State = Map<string, *>
export default handleActions<State, *>(
{
[LOAD_CURRENT_SESSION]: (
state: State,
action: ActionType<Function>,
): State => state.merge(Map(action.payload)),
[LOAD_CURRENT_SESSION]: (state: State, action: ActionType<Function>): State => state.merge(Map(action.payload)),
[UPDATE_VIEWED_SAFES]: (state: State, action: ActionType<Function>): State => {
const safeAddress = action.payload
const newState = state.updateIn(
['viewedSafes'],
(prev) => (prev.includes(safeAddress) ? prev : [...prev, safeAddress]),
const newState = state.updateIn(['viewedSafes'], prev =>
prev.includes(safeAddress) ? prev : [...prev, safeAddress],
)
saveCurrentSessionToStorage(newState)

View File

@ -4,7 +4,8 @@ import { loadFromStorage, saveToStorage } from '~/utils/storage'
const CURRENT_SESSION_STORAGE_KEY = 'CURRENT_SESSION'
export const getCurrentSessionFromStorage = async (): Promise<CurrentSessionProps | *> => loadFromStorage(CURRENT_SESSION_STORAGE_KEY)
export const getCurrentSessionFromStorage = async (): Promise<CurrentSessionProps | *> =>
loadFromStorage(CURRENT_SESSION_STORAGE_KEY)
export const saveCurrentSessionToStorage = async (currentSession: CurrentSession): Promise<*> => {
try {

View File

@ -200,6 +200,7 @@ export const enhanceSnackbarForAction = (notification: Notification, key?: strin
options: {
...notification.options,
onClick,
// eslint-disable-next-line react/display-name
action: (actionKey: number) => (
<IconButton onClick={() => store.dispatch(closeSnackbarAction({ key: actionKey }))}>
<IconClose />
@ -208,18 +209,13 @@ export const enhanceSnackbarForAction = (notification: Notification, key?: strin
},
})
export const showSnackbar = (
notification: Notification,
enqueueSnackbar: Function,
closeSnackbar: Function,
) => enqueueSnackbar(
notification.message,
{
export const showSnackbar = (notification: Notification, enqueueSnackbar: Function, closeSnackbar: Function) =>
enqueueSnackbar(notification.message, {
...notification.options,
action: (key) => (
// eslint-disable-next-line react/display-name
action: key => (
<IconButton onClick={() => closeSnackbar(key)}>
<IconClose />
</IconButton>
),
},
)
})

View File

@ -144,14 +144,19 @@ export const NOTIFICATIONS: Notifications = {
message: 'A pending transaction requires your confirmation!',
key: 'TX_WAITING_MSG',
options: {
variant: WARNING, persist: true, preventDuplicate: true,
variant: WARNING,
persist: true,
preventDuplicate: true,
},
},
TX_INCOMING_MSG: {
message: 'Incoming transfer: ',
key: 'TX_INCOMING_MSG',
options: {
variant: SUCCESS, persist: false, autoHideDuration: longDuration, preventDuplicate: true,
variant: SUCCESS,
persist: false,
autoHideDuration: longDuration,
preventDuplicate: true,
},
},

View File

@ -21,10 +21,10 @@ export default handleActions<NotificationReducerState, *>(
const { key, dismissAll } = action.payload
if (key) {
return state.update(key, (prev) => prev.set('dismissed', true))
return state.update(key, prev => prev.set('dismissed', true))
}
if (dismissAll) {
return state.withMutations((map) => {
return state.withMutations(map => {
map.forEach((notification, notificationKey) => {
map.set(notificationKey, notification.set('dismissed', true))
})

View File

@ -11,4 +11,6 @@ export const notificationsListSelector: Selector<
GlobalState,
{},
List<Notification>,
> = createSelector(notificationsMapSelector, (notifications: Map<string, Notification>): List<Notification> => notifications.toList())
> = createSelector(notificationsMapSelector, (notifications: Map<string, Notification>): List<Notification> =>
notifications.toList(),
)

View File

@ -22,7 +22,7 @@ export const generateSignaturesFromTxConfirmations = (
let sigs = '0x'
Object.keys(confirmationsMap)
.sort()
.forEach((addr) => {
.forEach(addr => {
const conf = confirmationsMap[addr]
if (conf.signature) {
sigs += conf.signature.slice(2)

View File

@ -11,30 +11,28 @@ export const getAwaitingTransactions = (
return Map({})
}
const allAwaitingTransactions = allTransactions.map((safeTransactions) => {
const nonCancelledTransactions = safeTransactions.filter(
(transaction: Transaction) => {
// If transactions are not executed, but there's a transaction with the same nonce EXECUTED later
// it means that the transaction was cancelled (Replaced) and shouldn't get executed
if (!transaction.isExecuted) {
if (cancellationTransactionsByNonce.get(transaction.nonce)) {
// eslint-disable-next-line no-param-reassign
transaction = transaction.set('cancelled', true)
}
const allAwaitingTransactions = allTransactions.map(safeTransactions => {
const nonCancelledTransactions = safeTransactions.filter((transaction: Transaction) => {
// If transactions are not executed, but there's a transaction with the same nonce EXECUTED later
// it means that the transaction was cancelled (Replaced) and shouldn't get executed
if (!transaction.isExecuted) {
if (cancellationTransactionsByNonce.get(transaction.nonce)) {
// eslint-disable-next-line no-param-reassign
transaction = transaction.set('cancelled', true)
}
// The transaction is not executed and is not cancelled, so it's still waiting confirmations
if (!transaction.executionTxHash && !transaction.cancelled) {
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this
// transaction
const transactionWaitingUser = transaction.confirmations.filter(
(confirmation) => confirmation.owner && confirmation.owner.address !== userAccount,
)
}
// The transaction is not executed and is not cancelled, so it's still waiting confirmations
if (!transaction.executionTxHash && !transaction.cancelled) {
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this
// transaction
const transactionWaitingUser = transaction.confirmations.filter(
confirmation => confirmation.owner && confirmation.owner.address !== userAccount,
)
return transactionWaitingUser.size > 0
}
return false
},
)
return transactionWaitingUser.size > 0
}
return false
})
return nonCancelledTransactions
})

View File

@ -4,7 +4,7 @@ import { getWeb3 } from '~/logic/wallets/getWeb3'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
const estimateDataGasCosts = (data) => {
const estimateDataGasCosts = data => {
const reducer = (accumulator, currentValue) => {
if (currentValue === EMPTY_DATA) {
return accumulator + 0

View File

@ -26,12 +26,13 @@ export const estimateTxGasCosts = async (
let txData
if (isExecution) {
// https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures
const signatures = tx && tx.confirmations
? generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
: `0x000000000000000000000000${from.replace(
'0x',
'',
)}000000000000000000000000000000000000000000000000000000000000000001`
const signatures =
tx && tx.confirmations
? generateSignaturesFromTxConfirmations(tx.confirmations, preApprovingOwner)
: `0x000000000000000000000000${from.replace(
'0x',
'',
)}000000000000000000000000000000000000000000000000000000000000000001`
txData = await safeInstance.methods
.execTransaction(to, tx ? tx.value : 0, data, CALL, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, signatures)
.encodeABI()

View File

@ -3,7 +3,8 @@ import {
DEFAULT_FALLBACK_HANDLER_ADDRESS,
getEncodedMultiSendCallData,
getGnosisSafeInstanceAt,
MULTI_SEND_ADDRESS, SAFE_MASTER_COPY_ADDRESS,
MULTI_SEND_ADDRESS,
SAFE_MASTER_COPY_ADDRESS,
} from '~/logic/contracts/safeContracts'
import type { MultiSendTransactionInstanceType } from '~/logic/contracts/safeContracts'
import { DELEGATE_CALL } from '~/logic/safe/transactions'
@ -25,7 +26,9 @@ export const upgradeSafeToLastVersion = async (safeAddress: string, createTransa
})
}
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const fallbackHandlerTxData = safeInstance.contract.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI()
const fallbackHandlerTxData = safeInstance.contract.methods
.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS)
.encodeABI()
const updateSafeTxData = safeInstance.contract.methods.changeMasterCopy(SAFE_MASTER_COPY_ADDRESS).encodeABI()
const txs = [
{

View File

@ -23,26 +23,30 @@ const activateTokensByBalance = (safeAddress: string) => async (
// addresses: potentially active tokens by balance
// balances: tokens' balance returned by the backend
const { addresses, balances } = result.data.reduce((acc, { tokenAddress, balance }) => ({
addresses: [...acc.addresses, tokenAddress],
balances: [[tokenAddress, balance]],
}), {
addresses: [],
balances: [],
})
const { addresses, balances } = result.data.reduce(
(acc, { tokenAddress, balance }) => ({
addresses: [...acc.addresses, tokenAddress],
balances: [[tokenAddress, balance]],
}),
{
addresses: [],
balances: [],
},
)
// update balance list for the safe
dispatch(updateSafe({
address: safeAddress,
balances: Set(balances),
}))
dispatch(
updateSafe({
address: safeAddress,
balances: Set(balances),
}),
)
// active tokens by balance, excluding those already blacklisted and the `null` address
const activeByBalance = addresses.filter((address) => address !== null && !blacklistedTokens.includes(address))
const activeByBalance = addresses.filter(address => address !== null && !blacklistedTokens.includes(address))
// need to persist those already active tokens, despite its balances
const activeTokens = alreadyActiveTokens.toSet()
.union(activeByBalance)
const activeTokens = alreadyActiveTokens.toSet().union(activeByBalance)
// update list of active tokens
dispatch(updateActiveTokens(safeAddress, activeTokens))

View File

@ -15,8 +15,8 @@ export default handleActions<State, *>(
[ADD_TOKENS]: (state: State, action: ActionType<Function>): State => {
const { tokens } = action.payload
const newState = state.withMutations((map) => {
tokens.forEach((token) => {
const newState = state.withMutations(map => {
tokens.forEach(token => {
map.set(token.address, token)
})
})

View File

@ -21,14 +21,16 @@ export const getEthAsToken = (balance: string) => {
}
export const calculateActiveErc20TokensFrom = (tokens: List<Token>) => {
const activeTokens = List().withMutations((list) => tokens.forEach((token: Token) => {
const isDeactivated = isEther(token.symbol) || !token.status
if (isDeactivated) {
return
}
const activeTokens = List().withMutations(list =>
tokens.forEach((token: Token) => {
const isDeactivated = isEther(token.symbol) || !token.status
if (isDeactivated) {
return
}
list.push(token)
}))
list.push(token)
}),
)
return activeTokens
}
@ -49,4 +51,5 @@ export const isAddressAToken = async (tokenAddress: string) => {
return call !== '0x'
}
export const isTokenTransfer = (data: string, value: number): boolean => !!data && data.substring(0, 10) === '0xa9059cbb' && value === 0
export const isTokenTransfer = (data: string, value: number): boolean =>
!!data && data.substring(0, 10) === '0xa9059cbb' && value === 0

View File

@ -43,7 +43,7 @@ export const removeTokenFromStorage = async (safeAddress: string, token: Token)
export const removeFromActiveTokens = async (safeAddress: string, token: Token) => {
const activeTokens = await getActiveTokens()
const index = activeTokens.findIndex((activeToken) => activeToken.name === token.name)
const index = activeTokens.findIndex(activeToken => activeToken.name === token.name)
if (index !== -1) {
await saveActiveTokens(safeAddress, activeTokens.delete(index))

View File

@ -47,4 +47,5 @@ export const isUserOwner = (safe: Safe, userAccount: string): boolean => {
return owners.find((owner: Owner) => sameAddress(owner.address, userAccount)) !== undefined
}
export const isUserOwnerOnAnySafe = (safes: List<Safe>, userAccount: string): boolean => safes.some((safe) => isUserOwner(safe, userAccount))
export const isUserOwnerOnAnySafe = (safes: List<Safe>, userAccount: string): boolean =>
safes.some(safe => isUserOwner(safe, userAccount))

View File

@ -60,9 +60,7 @@ export const getEtherScanLink = (type: 'address' | 'tx', value: string) => {
const getInfuraUrl = () => {
const isMainnet = process.env.REACT_APP_NETWORK === 'mainnet'
return `https://${isMainnet ? 'mainnet' : 'rinkeby'}.infura.io:443/v3/${
process.env.REACT_APP_INFURA_TOKEN
}`
return `https://${isMainnet ? 'mainnet' : 'rinkeby'}.infura.io:443/v3/${process.env.REACT_APP_INFURA_TOKEN}`
}
// With some wallets from web3connect you have to use their provider instance only for signing
@ -130,9 +128,7 @@ const getProviderName: Function = (web3Provider): string => {
return name
}
export const getAccountFrom: Function = async (
web3Provider
): Promise<string | null> => {
export const getAccountFrom: Function = async (web3Provider): Promise<string | null> => {
const accounts = await web3Provider.eth.getAccounts()
if (process.env.NODE_ENV === 'test' && window.testAccountIndex) {
@ -148,9 +144,7 @@ const getNetworkIdFrom = async web3Provider => {
return networkId
}
export const getProviderInfo: Function = async (
web3Provider
): Promise<ProviderProps> => {
export const getProviderInfo: Function = async (web3Provider): Promise<ProviderProps> => {
web3 = new Web3(web3Provider)
const name = getProviderName(web3)

Some files were not shown because too many files have changed in this diff Show More