Apps fixes (#871)

* Fix 850

* Fix 853

* Apps flag using string value

* Fix unresponsive app when switching to another app

* Fix Apps send TX

* Confirmation Modal, correct app name
This commit is contained in:
nicolas 2020-05-05 14:24:46 -03:00 committed by GitHub
parent c6f911b8ad
commit a79a86e5cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 15 deletions

View File

@ -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">

View File

@ -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 />

View File

@ -100,7 +100,7 @@ const TabsComponent = (props: Props) => {
label={labelTransactions} label={labelTransactions}
value={`${match.url}/transactions`} value={`${match.url}/transactions`}
/> />
{!process.env.REACT_APP_APPS_DISABLED && ( {process.env.REACT_APP_APPS_DISABLED !== 'true' && (
<Tab <Tab
classes={{ classes={{
selected: classes.tabWrapperSelected, selected: classes.tabWrapperSelected,

View File

@ -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_APPS_DISABLED && ( {process.env.REACT_APP_APPS_DISABLED !== 'true' && (
<Route <Route
exact exact
path={`${match.path}/apps`} path={`${match.path}/apps`}

20
src/utils/url.js Normal file
View File

@ -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
}
}