diff --git a/.flowconfig b/.flowconfig index b9bcc824..a03850b1 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,19 +1,25 @@ [ignore] -.*/migrations/** -.*/scripts/** +/migrations/**/.* +/contracts/**/.* +/scripts/**/.* +/public/**/.* +/src/test/**/.* +/babel.config.js +/jest.config.js +/truffle.js [untyped] -.*/config/** +/config/**/.* [declarations] -.*/node_modules/** -.*/flow-typed/** +/node_modules/**/.* +/flow-typed/**/.* [include] -/src/** +/src/**/.* [libs] -/flow-typed +/flow-typed/**/.* [lints] diff --git a/src/components/CookiesBanner/index.jsx b/src/components/CookiesBanner/index.jsx new file mode 100644 index 00000000..f631ecd8 --- /dev/null +++ b/src/components/CookiesBanner/index.jsx @@ -0,0 +1,145 @@ +// @flow +import Checkbox from '@material-ui/core/Checkbox' +import Close from '@material-ui/icons/Close' +import FormControlLabel from '@material-ui/core/FormControlLabel' +import IconButton from '@material-ui/core/IconButton' +import React, { useState } from 'react' +import { makeStyles } from '@material-ui/core/styles' +import { useSelector, useDispatch } from 'react-redux' +import Link from '~/components/layout/Link' +import { WELCOME_ADDRESS } from '~/routes/routes' +import Button from '~/components/layout/Button' +import { primary, mainFontFamily } from '~/theme/variables' +import saveCookiesToStorage from '~/logic/cookies/store/actions/saveCookiesToStorage' +import type { CookiesProps } from '~/logic/cookies/store/model/cookie' +import { cookiesSelector } from '~/logic/cookies/store/selectors' + +const useStyles = makeStyles({ + container: { + backgroundColor: '#fff', + bottom: '0', + boxShadow: '0 2px 4px 0 rgba(212, 212, 211, 0.59)', + boxSizing: 'border-box', + display: 'flex', + justifyContent: 'center', + left: '0', + minHeight: '200px', + padding: '27px 15px', + position: 'fixed', + width: '100%', + }, + content: { + maxWidth: '100%', + width: '830px', + }, + text: { + color: primary, + fontFamily: mainFontFamily, + fontSize: '16px', + fontWeight: 'normal', + lineHeight: '1.38', + margin: '0 0 25px', + textAlign: 'center', + }, + form: { + columnGap: '10px', + display: 'grid', + gridTemplateColumns: '1fr', + rowGap: '10px', + '@media (min-width: 960px)': { + gridTemplateColumns: '1fr 1fr 1fr', + }, + }, + formItem: { + alignItems: 'center', + display: 'flex', + justifyContent: 'center', + }, + link: { + textDecoration: 'underline', + '&:hover': { + textDecoration: 'none', + }, + }, + close: { + position: 'absolute', + right: '12px', + top: '12px', + }, +}) + +const acceptCookiesHandler = (newState: CookiesProps) => { + const dispatch = useDispatch() + // Aca tenes q pasarle el estado nuevo de los dos switches + dispatch(saveCookiesToStorage(newState)) +} + +const CookiesBanner = () => { + const classes = useStyles() + const cookiesState: CookiesProps = useSelector(cookiesSelector) + const { acceptedNecessary, acceptedAnalytics } = cookiesState + const showBanner = !acceptedNecessary || !acceptedAnalytics + const [localNecessary, setLocalNecessary] = useState(true) + const [localAnalytics, setLocalAnalytics] = useState(false) + + + return showBanner ? ( +
+ {}} className={classes.close}> +
+

+We use cookies to give you the best + experience and to help improve our website. Please read our + {' '} + Cookie Policy + {' '} + for more information. By clicking "Accept cookies", + you agree to the storing of cookies on your device to enhance site + navigation and analyze site usage. +

+
+
+ setLocalNecessary((prev) => !prev)} + value={localNecessary} + control={( + + )} + /> +
+
+ setLocalAnalytics((prev) => !prev)} + value={localAnalytics} + control={( + + )} + /> +
+
+ +
+
+
+
+ ) : null +} + +export default CookiesBanner diff --git a/src/components/Notifier/index.js b/src/components/Notifier/index.js index 78143021..21206b5d 100644 --- a/src/components/Notifier/index.js +++ b/src/components/Notifier/index.js @@ -75,9 +75,4 @@ class Notifier extends Component { } } -export default withSnackbar( - connect( - selector, - actions, - )(Notifier), -) +export default withSnackbar(connect(selector, actions)(Notifier)) diff --git a/src/components/layout/PageFrame/index.jsx b/src/components/layout/PageFrame/index.jsx index e8559ea7..cdaf4f3f 100644 --- a/src/components/layout/PageFrame/index.jsx +++ b/src/components/layout/PageFrame/index.jsx @@ -15,6 +15,7 @@ import AlertIcon from './assets/alert.svg' import CheckIcon from './assets/check.svg' import ErrorIcon from './assets/error.svg' import InfoIcon from './assets/info.svg' +import CookiesBanner from '~/components/CookiesBanner' import styles from './index.scss' const notificationStyles = { @@ -92,6 +93,7 @@ const PageFrame = ({ children, classes, currentNetwork }: Props) => { {children} + ) } diff --git a/src/index.js b/src/index.js index a824221b..7759063b 100644 --- a/src/index.js +++ b/src/index.js @@ -16,9 +16,14 @@ if (process.env.NODE_ENV !== 'production') { whyDidYouRender(React) } +// $FlowFixMe store.dispatch(loadActiveTokens()) store.dispatch(loadSafesFromStorage()) store.dispatch(loadDefaultSafe()) store.dispatch(loadCookiesFromStorage()) -ReactDOM.render(, document.getElementById('root')) +const root = document.getElementById('root') + +if (root !== null) { + ReactDOM.render(, root) +} diff --git a/src/logic/contracts/safeContracts.js b/src/logic/contracts/safeContracts.js index a1fad299..258b35fb 100644 --- a/src/logic/contracts/safeContracts.js +++ b/src/logic/contracts/safeContracts.js @@ -75,7 +75,10 @@ export const deploySafeContract = async (safeAccounts: string[], numConfirmation const gasPrice = await calculateGasPrice() return proxyFactoryMaster.createProxy(safeMaster.address, gnosisSafeData, { - from: userAccount, gas, gasPrice, value: 0, + from: userAccount, + gas, + gasPrice, + value: 0, }) } diff --git a/src/logic/cookies/store/actions/setCookiesPermissions.js b/src/logic/cookies/store/actions/setCookiesPermissions.js index edeab5d8..ccddfc02 100644 --- a/src/logic/cookies/store/actions/setCookiesPermissions.js +++ b/src/logic/cookies/store/actions/setCookiesPermissions.js @@ -5,6 +5,8 @@ import type { Cookie, CookiesProps } from '~/logic/cookies/store/model/cookie' export const SET_COOKIES_PERMISSIONS = 'SET_COOKIES_PERMISSIONS' - // eslint-disable-next-line max-len -export const setCookiesPermissions = createAction(SET_COOKIES_PERMISSIONS, (cookies: Map): CookiesProps => cookies) +export const setCookiesPermissions = createAction( + SET_COOKIES_PERMISSIONS, + (cookies: Map): CookiesProps => cookies, +) diff --git a/src/logic/cookies/store/model/cookie.js b/src/logic/cookies/store/model/cookie.js index 4729659b..7435f6bb 100644 --- a/src/logic/cookies/store/model/cookie.js +++ b/src/logic/cookies/store/model/cookie.js @@ -2,8 +2,8 @@ import type { RecordOf } from 'immutable' export type CookiesProps = { - acceptedNecessary: boolean; - acceptedAnalytics: boolean; + acceptedNecessary: boolean, + acceptedAnalytics: boolean, } export type Cookie = RecordOf diff --git a/src/logic/cookies/store/selectors/index.js b/src/logic/cookies/store/selectors/index.js index 444432d8..604abe13 100644 --- a/src/logic/cookies/store/selectors/index.js +++ b/src/logic/cookies/store/selectors/index.js @@ -2,5 +2,4 @@ import { type GlobalState } from '~/store' import { COOKIE_REDUCER_ID } from '~/logic/cookies/store/reducer/cookies' - export const cookiesSelector = (state: GlobalState) => state[COOKIE_REDUCER_ID] diff --git a/src/logic/notifications/store/actions/enqueueSnackbar.js b/src/logic/notifications/store/actions/enqueueSnackbar.js index bcdd7c87..dae418f4 100644 --- a/src/logic/notifications/store/actions/enqueueSnackbar.js +++ b/src/logic/notifications/store/actions/enqueueSnackbar.js @@ -8,9 +8,7 @@ export const ENQUEUE_SNACKBAR = 'ENQUEUE_SNACKBAR' const addSnackbar = createAction(ENQUEUE_SNACKBAR) -const enqueueSnackbar = (notification: NotificationProps) => ( - dispatch: ReduxDispatch, -) => { +const enqueueSnackbar = (notification: NotificationProps) => (dispatch: ReduxDispatch) => { const newNotification = { ...notification, key: new Date().getTime(), diff --git a/src/logic/notifications/store/selectors/index.js b/src/logic/notifications/store/selectors/index.js index bf6371fa..de27db1c 100644 --- a/src/logic/notifications/store/selectors/index.js +++ b/src/logic/notifications/store/selectors/index.js @@ -5,11 +5,10 @@ import { type GlobalState } from '~/store' import { NOTIFICATIONS_REDUCER_ID } from '~/logic/notifications/store/reducer/notifications' import { type Notification } from '~/logic/notifications/store/models/notification' -const notificationsMapSelector = ( - state: GlobalState, -): Map => state[NOTIFICATIONS_REDUCER_ID] +const notificationsMapSelector = (state: GlobalState): Map => state[NOTIFICATIONS_REDUCER_ID] -export const notificationsListSelector: Selector> = createSelector( - notificationsMapSelector, - (notifications: Map): List => notifications.toList(), -) +export const notificationsListSelector: Selector< + GlobalState, + {}, + List, +> = createSelector(notificationsMapSelector, (notifications: Map): List => notifications.toList()) diff --git a/src/logic/tokens/store/selectors/index.js b/src/logic/tokens/store/selectors/index.js index 30ab6b48..b119c540 100644 --- a/src/logic/tokens/store/selectors/index.js +++ b/src/logic/tokens/store/selectors/index.js @@ -13,7 +13,8 @@ export const tokenListSelector: Selector, List) => tokens.toList(), ) -export const orderedTokenListSelector: Selector> = createSelector( - tokenListSelector, - (tokens: List) => tokens.sortBy((token: Token) => token.get('symbol')), -) +export const orderedTokenListSelector: Selector< + GlobalState, + RouterProps, + List, +> = createSelector(tokenListSelector, (tokens: List) => tokens.sortBy((token: Token) => token.get('symbol'))) diff --git a/src/logic/wallets/store/selectors/index.js b/src/logic/wallets/store/selectors/index.js index 17fdf1f3..d76af237 100644 --- a/src/logic/wallets/store/selectors/index.js +++ b/src/logic/wallets/store/selectors/index.js @@ -6,40 +6,25 @@ import { ETHEREUM_NETWORK_IDS, ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3' const providerSelector = (state: any): Provider => state[PROVIDER_REDUCER_ID] -export const userAccountSelector = createSelector( - providerSelector, - (provider: Provider) => { - const account = provider.get('account') +export const userAccountSelector = createSelector(providerSelector, (provider: Provider) => { + const account = provider.get('account') - return account || '' - }, -) + return account || '' +}) -export const providerNameSelector = createSelector( - providerSelector, - (provider: Provider) => { - const name = provider.get('name') +export const providerNameSelector = createSelector(providerSelector, (provider: Provider) => { + const name = provider.get('name') - return name ? name.toLowerCase() : undefined - }, -) + return name ? name.toLowerCase() : undefined +}) -export const networkSelector = createSelector( - providerSelector, - (provider: Provider) => { - const networkId = provider.get('network') - const network = ETHEREUM_NETWORK_IDS[networkId] || ETHEREUM_NETWORK.UNKNOWN +export const networkSelector = createSelector(providerSelector, (provider: Provider) => { + const networkId = provider.get('network') + const network = ETHEREUM_NETWORK_IDS[networkId] || ETHEREUM_NETWORK.UNKNOWN - return network - }, -) + return network +}) -export const loadedSelector = createSelector( - providerSelector, - (provider: Provider) => provider.get('loaded'), -) +export const loadedSelector = createSelector(providerSelector, (provider: Provider) => provider.get('loaded')) -export const availableSelector = createSelector( - providerSelector, - (provider: Provider) => provider.get('available'), -) +export const availableSelector = createSelector(providerSelector, (provider: Provider) => provider.get('available')) diff --git a/src/routes/index.js b/src/routes/index.js index d6416d91..ff3d3271 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -72,8 +72,8 @@ const Routes = ({ defaultSafe, location }: RoutesProps) => { ) } +// $FlowFixMe export default connect( - // $FlowFixMe (state) => ({ defaultSafe: defaultSafeSelector(state) }), null, )(withRouter(Routes)) diff --git a/src/routes/safe/store/actions/processTransaction.js b/src/routes/safe/store/actions/processTransaction.js index e3425387..c87d13a7 100644 --- a/src/routes/safe/store/actions/processTransaction.js +++ b/src/routes/safe/store/actions/processTransaction.js @@ -16,11 +16,7 @@ import { TX_TYPE_EXECUTION, TX_TYPE_CONFIRMATION, } from '~/logic/safe/transactions' -import { - type NotificationsQueue, - getNotificationsFromTxType, - showSnackbar, -} from '~/logic/notifications' +import { type NotificationsQueue, getNotificationsFromTxType, showSnackbar } from '~/logic/notifications' import { getErrorMessage } from '~/test/utils/ethereumErrors' // https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures diff --git a/src/routes/safe/store/middleware/safeStorage.js b/src/routes/safe/store/middleware/safeStorage.js index d52bd317..a58ed541 100644 --- a/src/routes/safe/store/middleware/safeStorage.js +++ b/src/routes/safe/store/middleware/safeStorage.js @@ -90,7 +90,10 @@ const safeStorageMware = (store: Store) => (next: Function) => asyn case REMOVE_SAFE_OWNER: { const { safeAddress, ownerAddress } = action.payload const { owners } = safes.get(safeAddress) - setOwners(safeAddress, owners.filter((o) => o.address.toLowerCase() !== ownerAddress.toLowerCase())) + setOwners( + safeAddress, + owners.filter((o) => o.address.toLowerCase() !== ownerAddress.toLowerCase()), + ) break } case REPLACE_SAFE_OWNER: { @@ -110,7 +113,10 @@ const safeStorageMware = (store: Store) => (next: Function) => asyn const { safeAddress, ownerAddress, ownerName } = action.payload const { owners } = safes.get(safeAddress) const ownerToUpdateIndex = owners.findIndex((o) => o.address.toLowerCase() === ownerAddress.toLowerCase()) - setOwners(safeAddress, owners.update(ownerToUpdateIndex, (owner) => owner.set('name', ownerName))) + setOwners( + safeAddress, + owners.update(ownerToUpdateIndex, (owner) => owner.set('name', ownerName)), + ) break } case SET_DEFAULT_SAFE: { diff --git a/src/routes/safe/store/reducer/safe.js b/src/routes/safe/store/reducer/safe.js index f4dc3467..bdb67ad8 100644 --- a/src/routes/safe/store/reducer/safe.js +++ b/src/routes/safe/store/reducer/safe.js @@ -46,12 +46,15 @@ export default handleActions( const tokenAddress = action.payload const newState = state.withMutations((map) => { - map.get('safes').keySeq().forEach((safeAddress) => { - const safeActiveTokens = map.getIn(['safes', safeAddress, 'activeTokens']) - const activeTokens = safeActiveTokens.add(tokenAddress) + map + .get('safes') + .keySeq() + .forEach((safeAddress) => { + const safeActiveTokens = map.getIn(['safes', safeAddress, 'activeTokens']) + const activeTokens = safeActiveTokens.add(tokenAddress) - map.updateIn(['safes', safeAddress], (prevSafe) => prevSafe.merge({ activeTokens })) - }) + map.updateIn(['safes', safeAddress], (prevSafe) => prevSafe.merge({ activeTokens })) + }) }) return newState diff --git a/src/test/builder/safe.dom.utils.js b/src/test/builder/safe.dom.utils.js index 18679c8f..729864ed 100644 --- a/src/test/builder/safe.dom.utils.js +++ b/src/test/builder/safe.dom.utils.js @@ -115,7 +115,7 @@ export const whenSafeDeployed = (): Promise => new Promise((resolve, rej const interval = setInterval(() => { if (times >= MAX_TIMES_EXECUTED) { clearInterval(interval) - reject(new Error('Didn\'t load the safe')) + reject(new Error("Didn't load the safe")) } const url = `${window.location}` console.log(url) diff --git a/src/test/safe.dom.funds.threshold>1.test.js b/src/test/safe.dom.funds.threshold>1.test.js index 9f4aaf77..4c507fa0 100644 --- a/src/test/safe.dom.funds.threshold>1.test.js +++ b/src/test/safe.dom.funds.threshold>1.test.js @@ -12,9 +12,7 @@ import { fillAndSubmitSendFundsForm } from './utils/transactions' import { TRANSACTIONS_TAB_BTN_TEST_ID } from '~/routes/safe/components/Layout' import { TRANSACTION_ROW_TEST_ID } from '~/routes/safe/components/Transactions/TxsTable' import { useTestAccountAt, resetTestAccount } from './utils/accounts' -import { - CONFIRM_TX_BTN_TEST_ID, -} from '~/routes/safe/components/Transactions/TxsTable/ExpandedTx/OwnersColumn/ButtonRow' +import { CONFIRM_TX_BTN_TEST_ID } from '~/routes/safe/components/Transactions/TxsTable/ExpandedTx/OwnersColumn/ButtonRow' import { APPROVE_TX_MODAL_SUBMIT_BTN_TEST_ID } from '~/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal' afterEach(resetTestAccount) diff --git a/src/theme/variables.js b/src/theme/variables.js index 84d9f9ea..f39ffbd7 100644 --- a/src/theme/variables.js +++ b/src/theme/variables.js @@ -1,65 +1,67 @@ // @flow -const border = '#e8e7e6' const background = '#f7f5f5' -const primary = '#001428' -const secondary = '#008C73' -const fontColor = '#001428' -const fancyColor = '#f02525' -const warningColor = '#ffc05f' -const errorColor = '#f02525' -const secondaryTextOrSvg = '#B2B5B2' +const border = '#e8e7e6' const connectedColor = '#008C73' const disabled = '#5D6D74' -const xs = '4px' -const sm = '8px' -const md = '16px' -const lg = '24px' -const xl = '32px' -const xxl = '40px' -const marginButtonImg = '12px' +const errorColor = '#f02525' +const fancyColor = '#f02525' +const fontColor = '#001428' const headerHeight = '53px' +const lg = '24px' +const mainFontFamily = 'Averta, sans-serif' +const marginButtonImg = '12px' +const md = '16px' +const primary = '#001428' +const secondary = '#008C73' +const secondaryTextOrSvg = '#B2B5B2' +const sm = '8px' +const warningColor = '#ffc05f' +const xl = '32px' +const xs = '4px' +const xxl = '40px' module.exports = { - primary, - secondary, - disabled, background, - fontColor, - secondaryText: secondaryTextOrSvg, - fancy: fancyColor, - warning: warningColor, - error: errorColor, - connected: connectedColor, - headerHeight, - xs, - sm, - md, - lg, - xl, - xxl, - border, - marginButtonImg, - fontSizeHeadingXs: 13, - fontSizeHeadingSm: 16, - fontSizeHeadingMd: 20, - fontSizeHeadingLg: 32, - buttonLargeFontSize: '16px', - lightFont: 300, - regularFont: 400, - bolderFont: 500, boldFont: 700, + bolderFont: 500, + border, + buttonLargeFontSize: '16px', + connected: connectedColor, + disabled, + error: errorColor, extraBoldFont: 800, - extraSmallFontSize: '11px', - smallFontSize: '12px', - mediumFontSize: '14px', - largeFontSize: '16px', extraLargeFontSize: '20px', - xxlFontSize: '32px', - screenXs: 480, - screenXsMax: 767, - screenSm: 768, - screenSmMax: 991, + extraSmallFontSize: '11px', + fancy: fancyColor, + fontColor, + fontSizeHeadingLg: 32, + fontSizeHeadingMd: 20, + fontSizeHeadingSm: 16, + fontSizeHeadingXs: 13, + headerHeight, + largeFontSize: '16px', + lg, + lightFont: 300, + mainFontFamily, + marginButtonImg, + md, + mediumFontSize: '14px', + primary, + regularFont: 400, + screenLg: 1200, screenMd: 992, screenMdMax: 1199, - screenLg: 1200, + screenSm: 768, + screenSmMax: 991, + screenXs: 480, + screenXsMax: 767, + secondary, + secondaryText: secondaryTextOrSvg, + sm, + smallFontSize: '12px', + warning: warningColor, + xl, + xs, + xxl, + xxlFontSize: '32px', }