Merge branch 'development' into dont-fetch-ownername-in-fetchTransactions
# Conflicts: # yarn.lock
This commit is contained in:
commit
e402b51ff8
|
@ -27,5 +27,6 @@ REACT_APP_APP_VERSION=$npm_package_version
|
||||||
# all environments
|
# all environments
|
||||||
REACT_APP_INFURA_TOKEN=
|
REACT_APP_INFURA_TOKEN=
|
||||||
|
|
||||||
# For Apps
|
# For Apps
|
||||||
REACT_APP_GNOSIS_APPS_URL=http://localhost:3002
|
REACT_APP_GNOSIS_APPS_URL=https://safe-apps.staging.gnosisdev.com
|
||||||
|
REACT_APP_APPS_DISABLED=false
|
||||||
|
|
10
package.json
10
package.json
|
@ -48,11 +48,11 @@
|
||||||
"prettier --write"
|
"prettier --write"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"productName": "Safe Electron",
|
"productName": "Safe Multisig",
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "io.gnosis.safe.macos",
|
"appId": "io.gnosis.safe.macos",
|
||||||
"afterSign": "scripts/notarize.js",
|
"afterSign": "scripts/notarize.js",
|
||||||
"productName": "Safe Electron",
|
"productName": "Safe Multisig",
|
||||||
"asar": true,
|
"asar": true,
|
||||||
"publish": [
|
"publish": [
|
||||||
{
|
{
|
||||||
|
@ -136,9 +136,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
|
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
|
||||||
"@gnosis.pm/util-contracts": "2.0.6",
|
"@gnosis.pm/util-contracts": "2.0.6",
|
||||||
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#a057248",
|
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#a057248",
|
||||||
"@ledgerhq/hw-transport-node-hid": "5.12.0",
|
"@ledgerhq/hw-transport-node-hid": "5.12.0",
|
||||||
"@material-ui/core": "4.9.10",
|
"@material-ui/core": "4.9.10",
|
||||||
"@material-ui/icons": "4.9.1",
|
"@material-ui/icons": "4.9.1",
|
||||||
"@material-ui/lab": "4.0.0-alpha.39",
|
"@material-ui/lab": "4.0.0-alpha.39",
|
||||||
|
|
|
@ -129,14 +129,18 @@ function createWindow() {
|
||||||
autoUpdater.init(mainWindow);
|
autoUpdater.init(mainWindow);
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.webContents.on('crashed', () => {
|
mainWindow.webContents.on('crashed', (event) => {
|
||||||
log.info('App Crashed');
|
log.info(`App Crashed: ${event}`);
|
||||||
mainWindow.reload();
|
mainWindow.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.on("closed", () => (mainWindow = null));
|
mainWindow.on("closed", () => (mainWindow = null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process.on('uncaughtException',function(error){
|
||||||
|
log.error(error);
|
||||||
|
});
|
||||||
|
|
||||||
app.userAgentFallback = process.platform ==='win32' ?
|
app.userAgentFallback = process.platform ==='win32' ?
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36' :
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36' :
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) old-airport-include/1.0.0 Chrome Electron/7.1.7 Safari/537.36';
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) old-airport-include/1.0.0 Chrome Electron/7.1.7 Safari/537.36';
|
||||||
|
@ -144,7 +148,7 @@ app.userAgentFallback = process.platform ==='win32' ?
|
||||||
app.commandLine.appendSwitch('ignore-certificate-errors');
|
app.commandLine.appendSwitch('ignore-certificate-errors');
|
||||||
app.on("ready", () =>{
|
app.on("ready", () =>{
|
||||||
// Hide the menu
|
// Hide the menu
|
||||||
//Menu.setApplicationMenu(null);
|
Menu.setApplicationMenu(null);
|
||||||
if(!isDev) createServer();
|
if(!isDev) createServer();
|
||||||
createWindow();
|
createWindow();
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ The most trusted platform to store digital assets on Ethereum
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
|
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,21 @@
|
||||||
// It has the same sandbox as a Chrome extension.
|
// It has the same sandbox as a Chrome extension.
|
||||||
|
|
||||||
const TransportNodeHid = require("@ledgerhq/hw-transport-node-hid").default;
|
const TransportNodeHid = require("@ledgerhq/hw-transport-node-hid").default;
|
||||||
|
const log = require('electron-log');
|
||||||
window.TransportNodeHid = TransportNodeHid;
|
window.TransportNodeHid = TransportNodeHid;
|
||||||
|
|
||||||
window.isDesktop = true;
|
window.isDesktop = true;
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', () => {
|
window.addEventListener('DOMContentLoaded', () => {
|
||||||
|
console.error = (...args) => {
|
||||||
|
log.error(...args)
|
||||||
|
}
|
||||||
|
console.warn = (...args) => {
|
||||||
|
log.warn(...args)
|
||||||
|
}
|
||||||
|
console.log = (...args) => {
|
||||||
|
log.info(...args)
|
||||||
|
}
|
||||||
const replaceText = (selector, text) => {
|
const replaceText = (selector, text) => {
|
||||||
const element = document.getElementById(selector)
|
const element = document.getElementById(selector)
|
||||||
if (element) element.innerText = text
|
if (element) element.innerText = text
|
||||||
|
|
|
@ -28,6 +28,22 @@ export const Menu = styled.div.attrs(() => ({ className: 'background' }))`
|
||||||
border-top-left-radius: 8px;
|
border-top-left-radius: 8px;
|
||||||
border-bottom-left-radius: 8px;
|
border-bottom-left-radius: 8px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 0.7em !important;
|
||||||
|
scroll-behavior: smooth !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: darkgrey !important;
|
||||||
|
outline: 1px solid slategrey !important;
|
||||||
|
border-radius: 10px !important;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export const Content = styled.div.attrs(() => ({ className: 'background' }))`
|
export const Content = styled.div.attrs(() => ({ className: 'background' }))`
|
||||||
|
|
|
@ -29,6 +29,7 @@ type Props = {
|
||||||
userAddress: string,
|
userAddress: string,
|
||||||
classes: Object,
|
classes: Object,
|
||||||
onDisconnect: Function,
|
onDisconnect: Function,
|
||||||
|
openDashboard?: Function,
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = () => ({
|
const styles = () => ({
|
||||||
|
@ -72,6 +73,15 @@ const styles = () => ({
|
||||||
},
|
},
|
||||||
disconnect: {
|
disconnect: {
|
||||||
padding: `${md} ${lg}`,
|
padding: `${md} ${lg}`,
|
||||||
|
'& button': {
|
||||||
|
background: '#f02525',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dashboard: {
|
||||||
|
padding: `${md} ${lg} ${xs}`,
|
||||||
|
},
|
||||||
|
dashboardText: {
|
||||||
|
letterSpacing: '1px',
|
||||||
},
|
},
|
||||||
disconnectText: {
|
disconnectText: {
|
||||||
letterSpacing: '1px',
|
letterSpacing: '1px',
|
||||||
|
@ -92,7 +102,7 @@ const styles = () => ({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const UserDetails = ({ classes, connected, network, onDisconnect, provider, userAddress }: Props) => {
|
const UserDetails = ({ classes, connected, network, onDisconnect, openDashboard, provider, userAddress }: Props) => {
|
||||||
const status = connected ? 'Connected' : 'Connection error'
|
const status = connected ? 'Connected' : 'Connection error'
|
||||||
const address = userAddress ? shortVersionOf(userAddress, 4) : 'Address not available'
|
const address = userAddress ? shortVersionOf(userAddress, 4) : 'Address not available'
|
||||||
const identiconAddress = userAddress || 'random'
|
const identiconAddress = userAddress || 'random'
|
||||||
|
@ -154,6 +164,15 @@ const UserDetails = ({ classes, connected, network, onDisconnect, provider, user
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</Row>
|
</Row>
|
||||||
<Hairline margin="xs" />
|
<Hairline margin="xs" />
|
||||||
|
{openDashboard && (
|
||||||
|
<Row className={classes.dashboard}>
|
||||||
|
<Button color="primary" fullWidth onClick={openDashboard} size="medium" variant="contained">
|
||||||
|
<Paragraph className={classes.dashboardText} color="white" noMargin size="md">
|
||||||
|
{upperFirst(provider)} Wallet
|
||||||
|
</Paragraph>
|
||||||
|
</Button>
|
||||||
|
</Row>
|
||||||
|
)}
|
||||||
<Row className={classes.disconnect}>
|
<Row className={classes.disconnect}>
|
||||||
<Button color="primary" fullWidth onClick={onDisconnect} size="medium" variant="contained">
|
<Button color="primary" fullWidth onClick={onDisconnect} size="medium" variant="contained">
|
||||||
<Paragraph className={classes.disconnectText} color="white" noMargin size="md">
|
<Paragraph className={classes.disconnectText} color="white" noMargin size="md">
|
||||||
|
|
|
@ -54,6 +54,10 @@ class HeaderComponent extends React.PureComponent<Props, State> {
|
||||||
logComponentStack(error, info)
|
logComponentStack(error, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOpenDashboard = () => {
|
||||||
|
const { wallet } = onboard.getState()
|
||||||
|
return wallet.type === 'sdk' && wallet.dashboard
|
||||||
|
}
|
||||||
onDisconnect = () => {
|
onDisconnect = () => {
|
||||||
const { closeSnackbar, enqueueSnackbar, removeProvider } = this.props
|
const { closeSnackbar, enqueueSnackbar, removeProvider } = this.props
|
||||||
|
|
||||||
|
@ -84,6 +88,7 @@ class HeaderComponent extends React.PureComponent<Props, State> {
|
||||||
connected={available}
|
connected={available}
|
||||||
network={network}
|
network={network}
|
||||||
onDisconnect={this.onDisconnect}
|
onDisconnect={this.onDisconnect}
|
||||||
|
openDashboard={this.getOpenDashboard()}
|
||||||
provider={provider}
|
provider={provider}
|
||||||
userAddress={userAddress}
|
userAddress={userAddress}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
import type { Dispatch as ReduxDispatch } from 'redux'
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
|
|
||||||
import fetchCollectibles from '~/logic/collectibles/store/actions/fetchCollectibles'
|
|
||||||
import { nftAssetsSelector } from '~/logic/collectibles/store/selectors'
|
import { nftAssetsSelector } from '~/logic/collectibles/store/selectors'
|
||||||
import updateActiveAssets from '~/routes/safe/store/actions/updateActiveAssets'
|
import updateActiveAssets from '~/routes/safe/store/actions/updateActiveAssets'
|
||||||
import {
|
import {
|
||||||
|
@ -24,7 +23,6 @@ const activateAssetsByBalance = (safeAddress: string) => async (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await dispatch(fetchCollectibles())
|
|
||||||
const availableAssets = nftAssetsSelector(state)
|
const availableAssets = nftAssetsSelector(state)
|
||||||
const alreadyActiveAssets = safeActiveAssetsSelectorBySafe(safeAddress, safes)
|
const alreadyActiveAssets = safeActiveAssetsSelectorBySafe(safeAddress, safes)
|
||||||
const blacklistedAssets = safeBlacklistedAssetsSelectorBySafe(safeAddress, safes)
|
const blacklistedAssets = safeBlacklistedAssetsSelectorBySafe(safeAddress, safes)
|
||||||
|
|
|
@ -43,7 +43,6 @@ const wallets = [
|
||||||
{
|
{
|
||||||
walletName: 'portis',
|
walletName: 'portis',
|
||||||
apiKey: PORTIS_DAPP_ID,
|
apiKey: PORTIS_DAPP_ID,
|
||||||
label: 'Login with Email',
|
|
||||||
desktop: true,
|
desktop: true,
|
||||||
},
|
},
|
||||||
{ walletName: 'authereum', desktop: false },
|
{ walletName: 'authereum', desktop: false },
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
import { BigNumber } from 'bignumber.js'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
@ -8,6 +9,8 @@ import Heading from '~/components/layout/Heading'
|
||||||
import Img from '~/components/layout/Img'
|
import Img from '~/components/layout/Img'
|
||||||
import { getEthAsToken } from '~/logic/tokens/utils/tokenHelpers'
|
import { getEthAsToken } from '~/logic/tokens/utils/tokenHelpers'
|
||||||
|
|
||||||
|
const humanReadableBalance = (balance, decimals) => BigNumber(balance).times(`1e-${decimals}`).toFixed()
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
`
|
`
|
||||||
|
@ -28,13 +31,14 @@ const confirmTransactions = (
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
safeName: string,
|
safeName: string,
|
||||||
ethBalance: string,
|
ethBalance: string,
|
||||||
|
nameApp: string,
|
||||||
iconApp: string,
|
iconApp: string,
|
||||||
txs: Array<any>,
|
txs: Array<any>,
|
||||||
openModal: () => void,
|
openModal: () => void,
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
onConfirm: () => void,
|
onConfirm: () => void,
|
||||||
) => {
|
) => {
|
||||||
const title = <ModalTitle iconUrl={iconApp} title="Compound" />
|
const title = <ModalTitle iconUrl={iconApp} title={nameApp} />
|
||||||
|
|
||||||
const body = (
|
const body = (
|
||||||
<>
|
<>
|
||||||
|
@ -49,7 +53,7 @@ const confirmTransactions = (
|
||||||
<Heading tag="h3">Value</Heading>
|
<Heading tag="h3">Value</Heading>
|
||||||
<div className="value-section">
|
<div className="value-section">
|
||||||
<Img alt="Ether" height={40} src={getEthAsToken('0').logoUri} />
|
<Img alt="Ether" height={40} src={getEthAsToken('0').logoUri} />
|
||||||
<Bold>{tx.value} ETH</Bold>
|
<Bold>{humanReadableBalance(tx.value, 18)} ETH</Bold>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="section">
|
<div className="section">
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
safeParamAddressFromStateSelector,
|
safeParamAddressFromStateSelector,
|
||||||
} from '~/routes/safe/store/selectors'
|
} from '~/routes/safe/store/selectors'
|
||||||
import { loadFromStorage, saveToStorage } from '~/utils/storage'
|
import { loadFromStorage, saveToStorage } from '~/utils/storage'
|
||||||
|
import { isSameHref } from '~/utils/url'
|
||||||
|
|
||||||
const APPS_STORAGE_KEY = 'APPS_STORAGE_KEY'
|
const APPS_STORAGE_KEY = 'APPS_STORAGE_KEY'
|
||||||
const APPS_LEGAL_DISCLAIMER_STORAGE_KEY = 'APPS_LEGAL_DISCLAIMER_STORAGE_KEY'
|
const APPS_LEGAL_DISCLAIMER_STORAGE_KEY = 'APPS_LEGAL_DISCLAIMER_STORAGE_KEY'
|
||||||
|
@ -30,7 +31,6 @@ const StyledIframe = styled.iframe`
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: ${(props) => (props.shouldDisplay ? 'block' : 'none')};
|
|
||||||
`
|
`
|
||||||
const Centered = styled.div`
|
const Centered = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -68,7 +68,8 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
const getSelectedApp = () => appList.find((e) => e.id === selectedApp)
|
const getSelectedApp = () => appList.find((e) => e.id === selectedApp)
|
||||||
|
|
||||||
const sendMessageToIframe = (messageId, data) => {
|
const sendMessageToIframe = (messageId, data) => {
|
||||||
iframeEl.contentWindow.postMessage({ messageId, data }, getSelectedApp().url)
|
const app = getSelectedApp()
|
||||||
|
iframeEl.contentWindow.postMessage({ messageId, data }, app.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleIframeMessage = async (data) => {
|
const handleIframeMessage = async (data) => {
|
||||||
|
@ -89,6 +90,7 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
safeAddress,
|
safeAddress,
|
||||||
safeName,
|
safeName,
|
||||||
ethBalance,
|
ethBalance,
|
||||||
|
getSelectedApp().name,
|
||||||
getSelectedApp().iconUrl,
|
getSelectedApp().iconUrl,
|
||||||
data.data,
|
data.data,
|
||||||
openModal,
|
openModal,
|
||||||
|
@ -172,16 +174,18 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const app = getSelectedApp()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{appIsLoading && <Loader />}
|
{appIsLoading && <Loader />}
|
||||||
<StyledIframe
|
<StyledIframe
|
||||||
frameBorder="0"
|
frameBorder="0"
|
||||||
id="iframeId"
|
id={`iframe-${app.name}`}
|
||||||
ref={iframeRef}
|
ref={iframeRef}
|
||||||
shouldDisplay={!appIsLoading}
|
shouldDisplay={!appIsLoading}
|
||||||
src={getSelectedApp().url}
|
src={app.url}
|
||||||
title={getSelectedApp().name}
|
title={app.name}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -250,8 +254,9 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getSelectedApp().url.includes(origin)) {
|
const app = getSelectedApp()
|
||||||
console.error(`ThirdPartyApp: A message from was received from an unknown origin ${origin}`)
|
if (!app.url.includes(origin)) {
|
||||||
|
console.error(`ThirdPartyApp: A message was received from an unknown origin ${origin}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +268,7 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('message', onIframeMessage)
|
window.removeEventListener('message', onIframeMessage)
|
||||||
}
|
}
|
||||||
})
|
}, [selectedApp])
|
||||||
|
|
||||||
// load legalDisclaimer
|
// load legalDisclaimer
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -276,7 +281,7 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLegalDisclaimer()
|
checkLegalDisclaimer()
|
||||||
})
|
}, [])
|
||||||
|
|
||||||
// Load apps list
|
// Load apps list
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -333,7 +338,8 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iframeEl) {
|
const app = getSelectedApp()
|
||||||
|
if (!iframeEl || !selectedApp || !isSameHref(iframeEl.src, app.url)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +348,7 @@ function Apps({ closeModal, closeSnackbar, enqueueSnackbar, openModal }: Props)
|
||||||
return () => {
|
return () => {
|
||||||
iframeEl.removeEventListener('load', onIframeLoaded)
|
iframeEl.removeEventListener('load', onIframeLoaded)
|
||||||
}
|
}
|
||||||
}, [iframeEl])
|
}, [iframeEl, selectedApp])
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Loader />
|
return <Loader />
|
||||||
|
|
|
@ -100,7 +100,7 @@ const TabsComponent = (props: Props) => {
|
||||||
label={labelTransactions}
|
label={labelTransactions}
|
||||||
value={`${match.url}/transactions`}
|
value={`${match.url}/transactions`}
|
||||||
/>
|
/>
|
||||||
{process.env.REACT_APP_ENV !== 'production' && (
|
{process.env.REACT_APP_APPS_DISABLED !== 'true' && (
|
||||||
<Tab
|
<Tab
|
||||||
classes={{
|
classes={{
|
||||||
selected: classes.tabWrapperSelected,
|
selected: classes.tabWrapperSelected,
|
||||||
|
|
|
@ -91,7 +91,7 @@ const Layout = (props: Props) => {
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path={`${match.path}/balances/:assetType?`} render={() => wrapInSuspense(<Balances />, null)} />
|
<Route exact path={`${match.path}/balances/:assetType?`} render={() => wrapInSuspense(<Balances />, null)} />
|
||||||
<Route exact path={`${match.path}/transactions`} render={() => wrapInSuspense(<TxsTable />, null)} />
|
<Route exact path={`${match.path}/transactions`} render={() => wrapInSuspense(<TxsTable />, null)} />
|
||||||
{process.env.REACT_APP_ENV !== 'production' && (
|
{process.env.REACT_APP_APPS_DISABLED !== 'true' && (
|
||||||
<Route
|
<Route
|
||||||
exact
|
exact
|
||||||
path={`${match.path}/apps`}
|
path={`${match.path}/apps`}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { batch, useDispatch, useSelector } from 'react-redux'
|
import { batch, useDispatch, useSelector } from 'react-redux'
|
||||||
|
|
||||||
|
import fetchCollectibles from '~/logic/collectibles/store/actions/fetchCollectibles'
|
||||||
import { fetchCurrencyValues } from '~/logic/currencyValues/store/actions/fetchCurrencyValues'
|
import { fetchCurrencyValues } from '~/logic/currencyValues/store/actions/fetchCurrencyValues'
|
||||||
import activateAssetsByBalance from '~/logic/tokens/store/actions/activateAssetsByBalance'
|
import activateAssetsByBalance from '~/logic/tokens/store/actions/activateAssetsByBalance'
|
||||||
import fetchSafeTokens from '~/logic/tokens/store/actions/fetchSafeTokens'
|
import fetchSafeTokens from '~/logic/tokens/store/actions/fetchSafeTokens'
|
||||||
|
@ -24,7 +25,11 @@ export const useFetchTokens = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (COLLECTIBLES_LOCATION_REGEX.test(history.location.pathname)) {
|
if (COLLECTIBLES_LOCATION_REGEX.test(history.location.pathname)) {
|
||||||
dispatch(activateAssetsByBalance(address))
|
batch(() => {
|
||||||
|
dispatch(fetchCollectibles()).then(() => {
|
||||||
|
dispatch(activateAssetsByBalance(address))
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, [history.location.pathname])
|
}, [history.location.pathname])
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
export const isValid = (url: string, protocolsAllowed = ['https:', 'http:']): boolean => {
|
||||||
|
try {
|
||||||
|
const urlInfo = new URL(url)
|
||||||
|
return protocolsAllowed.includes(urlInfo.protocol)
|
||||||
|
} catch (error) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isSameHref = (url1: string, url2: string) => {
|
||||||
|
try {
|
||||||
|
const a = new URL(url1)
|
||||||
|
const b = new URL(url2)
|
||||||
|
return a.href === b.href
|
||||||
|
} catch (error) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue