From 560281227a73d5ffe3d250f5ec86009ddff451e0 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Thu, 16 Jul 2020 10:55:34 -0300 Subject: [PATCH 01/52] Fix ts error Add type return on fetchCurrencyValues --- src/logic/currencyValues/store/actions/fetchCurrencyValues.ts | 3 ++- src/routes/safe/store/middleware/notificationsMiddleware.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts b/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts index 2c098cbfba..6ef3b97a33 100644 --- a/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts +++ b/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts @@ -6,8 +6,9 @@ import { setCurrencyRate } from 'src/logic/currencyValues/store/actions/setCurre import { setSelectedCurrency } from 'src/logic/currencyValues/store/actions/setSelectedCurrency' import { AVAILABLE_CURRENCIES, CurrencyRateValue } from 'src/logic/currencyValues/store/model/currencyValues' import { loadCurrencyValues } from 'src/logic/currencyValues/store/utils/currencyValuesStorage' +import { Dispatch } from 'redux' -export const fetchCurrencyValues = (safeAddress: string) => async (dispatch) => { +export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: Dispatch): Promise => { try { const storedCurrencies: Map | any = await loadCurrencyValues() const storedCurrency = storedCurrencies[safeAddress] diff --git a/src/routes/safe/store/middleware/notificationsMiddleware.ts b/src/routes/safe/store/middleware/notificationsMiddleware.ts index 48b752aec7..081fb19fa6 100644 --- a/src/routes/safe/store/middleware/notificationsMiddleware.ts +++ b/src/routes/safe/store/middleware/notificationsMiddleware.ts @@ -105,7 +105,7 @@ const notificationsMiddleware = (store) => (next) => async (action) => { action.payload.forEach((incomingTransactions, safeAddress) => { const { latestIncomingTxBlock } = state.safes.get('safes').get(safeAddress) const viewedSafes = state.currentSession ? state.currentSession.get('viewedSafes') : [] - const recurringUser = viewedSafes.includes(safeAddress) + const recurringUser = viewedSafes?.includes(safeAddress) const newIncomingTransactions = incomingTransactions.filter((tx) => tx.blockNumber > latestIncomingTxBlock) From ac742d8d59f4070106588217b265d2ff05b15c26 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Thu, 16 Jul 2020 11:14:02 -0300 Subject: [PATCH 02/52] Add skeleton for loading balance value --- src/routes/safe/components/Balances/Coins/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Balances/Coins/index.tsx b/src/routes/safe/components/Balances/Coins/index.tsx index edc89a0532..7506730ee6 100644 --- a/src/routes/safe/components/Balances/Coins/index.tsx +++ b/src/routes/safe/components/Balances/Coins/index.tsx @@ -30,6 +30,7 @@ import { getBalanceData, } from 'src/routes/safe/components/Balances/dataFetcher' import { extendedSafeTokensSelector, grantedSelector } from 'src/routes/safe/container/selector' +import { Skeleton } from '@material-ui/lab' const useStyles = makeStyles(styles as any) @@ -76,7 +77,11 @@ const Coins = (props) => { break } case BALANCE_TABLE_VALUE_ID: { - cellItem =
{row[id]}
+ cellItem = row[id] ? ( +
{row[id]}
+ ) : ( + + ) break } default: { From 0c7c5aa774578e4fab665f62627f747334663ef1 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Thu, 16 Jul 2020 12:13:36 -0300 Subject: [PATCH 03/52] Fix texts in uppercase --- src/routes/safe/components/Balances/Coins/index.tsx | 3 --- .../Settings/ThresholdSettings/ChangeThreshold/index.tsx | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/routes/safe/components/Balances/Coins/index.tsx b/src/routes/safe/components/Balances/Coins/index.tsx index 7506730ee6..4f36a259d3 100644 --- a/src/routes/safe/components/Balances/Coins/index.tsx +++ b/src/routes/safe/components/Balances/Coins/index.tsx @@ -2,9 +2,6 @@ import TableCell from '@material-ui/core/TableCell' import TableContainer from '@material-ui/core/TableContainer' import TableRow from '@material-ui/core/TableRow' import { makeStyles } from '@material-ui/core/styles' -//import CallMade from '@material-ui/icons/CallMade' -//import CallReceived from '@material-ui/icons/CallReceived' -//import classNames from 'classnames/bind' import { List } from 'immutable' import React from 'react' import { useSelector } from 'react-redux' diff --git a/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx b/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx index d9f1f7656e..9c5179bd28 100644 --- a/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx +++ b/src/routes/safe/components/Settings/ThresholdSettings/ChangeThreshold/index.tsx @@ -112,10 +112,10 @@ const ChangeThreshold = ({ classes, onChangeThreshold, onClose, owners, safeAddr From 2b8056e1bf5ca187b6a4ac5e3f9561f2f8d962fa Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 09:16:46 -0300 Subject: [PATCH 04/52] Adds ETH Icon in currencyValues dropdown --- .../store/model/currencyValues.ts | 1 + .../components/CurrencyDropdown/index.tsx | 30 +++++++++++++------ .../safe/components/CurrencyDropdown/style.ts | 7 +++++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/logic/currencyValues/store/model/currencyValues.ts b/src/logic/currencyValues/store/model/currencyValues.ts index dcfefb471a..716cd3f340 100644 --- a/src/logic/currencyValues/store/model/currencyValues.ts +++ b/src/logic/currencyValues/store/model/currencyValues.ts @@ -1,6 +1,7 @@ import { Record } from 'immutable' export enum AVAILABLE_CURRENCIES { + ETH = 'ETH', USD = 'USD', EUR = 'EUR', CAD = 'CAD', diff --git a/src/routes/safe/components/CurrencyDropdown/index.tsx b/src/routes/safe/components/CurrencyDropdown/index.tsx index 419450400e..c7eb029ab2 100644 --- a/src/routes/safe/components/CurrencyDropdown/index.tsx +++ b/src/routes/safe/components/CurrencyDropdown/index.tsx @@ -18,8 +18,11 @@ import { currentCurrencySelector } from 'src/logic/currencyValues/store/selector import { useDropdownStyles } from 'src/routes/safe/components/CurrencyDropdown/style' import { safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' import { DropdownListTheme } from 'src/theme/mui' +import { setImageToPlaceholder } from '../Balances/utils' +import Img from '../../../../components/layout/Img' +import etherIcon from 'src/assets/icons/icon_etherTokens.svg' -const CurrencyDropdown = () => { +const CurrencyDropdown = (): React.ReactElement => { const currenciesList = Object.values(AVAILABLE_CURRENCIES) const safeAddress = useSelector(safeParamAddressFromStateSelector) const dispatch = useDispatch() @@ -96,14 +99,23 @@ const CurrencyDropdown = () => { value={currencyName} > -
+ {currencyName === AVAILABLE_CURRENCIES.ETH ? ( + ether + ) : ( +
+ )} {currencyName === selectedCurrency ? ( diff --git a/src/routes/safe/components/CurrencyDropdown/style.ts b/src/routes/safe/components/CurrencyDropdown/style.ts index 2756ef70f7..67bac5e389 100644 --- a/src/routes/safe/components/CurrencyDropdown/style.ts +++ b/src/routes/safe/components/CurrencyDropdown/style.ts @@ -18,6 +18,13 @@ export const useDropdownStyles = makeStyles({ height: '20px !important', width: '26px !important', }, + etherFlag: { + backgroundPosition: '50% 50%', + backgroundRepeat: 'no-repeat', + backgroundSize: 'contain', + width: '26px', + height: '26px', + }, iconLeft: { marginRight: '10px', }, From e7693d25a429432df318995fbaf19b3552d2df96 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 09:40:41 -0300 Subject: [PATCH 05/52] Adds getExchangeRatesUrlFallback Adds support for ETH as currency --- src/config/index.ts | 2 ++ .../api/fetchCurrenciesRates.ts | 23 +++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/config/index.ts b/src/config/index.ts index 8409d2b862..dd522ab29c 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -87,6 +87,8 @@ export const getIntercomId = () => export const getExchangeRatesUrl = () => 'https://api.exchangeratesapi.io/latest' +export const getExchangeRatesUrlFallback = () => 'https://api.coinbase.com/v2/exchange-rates' + export const getSafeLastVersion = () => process.env.REACT_APP_LATEST_SAFE_VERSION || '1.1.1' export const buildSafeCreationTxUrl = (safeAddress) => { diff --git a/src/logic/currencyValues/api/fetchCurrenciesRates.ts b/src/logic/currencyValues/api/fetchCurrenciesRates.ts index 469866512f..83d360fbdc 100644 --- a/src/logic/currencyValues/api/fetchCurrenciesRates.ts +++ b/src/logic/currencyValues/api/fetchCurrenciesRates.ts @@ -1,6 +1,6 @@ import axios from 'axios' -import { getExchangeRatesUrl } from 'src/config' +import { getExchangeRatesUrl, getExchangeRatesUrlFallback } from 'src/config' import { AVAILABLE_CURRENCIES } from '../store/model/currencyValues' const fetchCurrenciesRates = async ( @@ -9,11 +9,24 @@ const fetchCurrenciesRates = async ( ): Promise => { let rate = 0 const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}` + const fallbackUrl = `${getExchangeRatesUrlFallback()}?currency=${baseCurrency}` - const result = await axios.get(url) - if (result && result.data) { - const { rates } = result.data - rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 + try { + const result = await axios.get(url) + if (result && result.data) { + const { rates } = result.data + rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 + } + } catch (error) { + try { + const result = await axios.get(fallbackUrl) + if (result && result.data) { + const { rates } = result.data?.data + rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 + } + } catch (error) { + console.log('Fetching data from exchangesRatesApiFallback errored', error) + } } return rate From 762861d47e27eea536c89b4e8207320a96c71ce9 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 09:47:05 -0300 Subject: [PATCH 06/52] Alphabetically sort currencies --- .../store/model/currencyValues.ts | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/logic/currencyValues/store/model/currencyValues.ts b/src/logic/currencyValues/store/model/currencyValues.ts index 716cd3f340..96b0d0c9f4 100644 --- a/src/logic/currencyValues/store/model/currencyValues.ts +++ b/src/logic/currencyValues/store/model/currencyValues.ts @@ -4,37 +4,37 @@ export enum AVAILABLE_CURRENCIES { ETH = 'ETH', USD = 'USD', EUR = 'EUR', + AUD = 'AUD', + BGN = 'BGN', + BRL = 'BRL', CAD = 'CAD', - HKD = 'HKD', - ISK = 'ISK', - PHP = 'PHP', + CHF = 'CHF', + CNY = 'CNY', + CZK = 'CZK', DKK = 'DKK', + GBP = 'GBP', + HKD = 'HKD', + HRK = 'HRK', HUF = 'HUF', - CZK = 'CZK', - AUD = 'AUD', - RON = 'RON', - SEK = 'SEK', IDR = 'IDR', + ILS = 'ILS', INR = 'INR', - BRL = 'BRL', - RUB = 'RUB', - HRK = 'HRK', + ISK = 'ISK', JPY = 'JPY', - THB = 'THB', - CHF = 'CHF', - SGD = 'SGD', - PLN = 'PLN', - BGN = 'BGN', - TRY = 'TRY', - CNY = 'CNY', + KRW = 'KRW', + MXN = 'MXN', + MYR = 'MYR', NOK = 'NOK', NZD = 'NZD', + PHP = 'PHP', + PLN = 'PLN', + RON = 'RON', + RUB = 'RUB', + SEK = 'SEK', + SGD = 'SGD', + THB = 'THB', + TRY = 'TRY', ZAR = 'ZAR', - MXN = 'MXN', - ILS = 'ILS', - GBP = 'GBP', - KRW = 'KRW', - MYR = 'MYR', } type BalanceCurrencyRecord = { From a12b62aeb17ad0431971ffa654ed3032d3e9e1f5 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 09:52:25 -0300 Subject: [PATCH 07/52] Add types --- src/routes/safe/components/Balances/Coins/index.tsx | 7 ++++++- src/routes/safe/components/Balances/index.tsx | 13 ++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/routes/safe/components/Balances/Coins/index.tsx b/src/routes/safe/components/Balances/Coins/index.tsx index 4f36a259d3..b975064f3a 100644 --- a/src/routes/safe/components/Balances/Coins/index.tsx +++ b/src/routes/safe/components/Balances/Coins/index.tsx @@ -31,7 +31,12 @@ import { Skeleton } from '@material-ui/lab' const useStyles = makeStyles(styles as any) -const Coins = (props) => { +type Props = { + showReceiveFunds: () => void + showSendFunds: (tokenAddress: string) => void +} + +const Coins = (props: Props): React.ReactElement => { const { showReceiveFunds, showSendFunds } = props const classes = useStyles() const columns = generateColumns() diff --git a/src/routes/safe/components/Balances/index.tsx b/src/routes/safe/components/Balances/index.tsx index 52763fea73..adcbef13f0 100644 --- a/src/routes/safe/components/Balances/index.tsx +++ b/src/routes/safe/components/Balances/index.tsx @@ -1,4 +1,4 @@ -import { withStyles } from '@material-ui/core/styles' +import { makeStyles } from '@material-ui/core/styles' import React, { useEffect, useState } from 'react' import { useSelector } from 'react-redux' @@ -41,7 +41,10 @@ const INITIAL_STATE = { export const COINS_LOCATION_REGEX = /\/balances\/?$/ export const COLLECTIBLES_LOCATION_REGEX = /\/balances\/collectibles$/ -const Balances = (props) => { +const useStyles = makeStyles(styles as any) + +const Balances = (): React.ReactElement => { + const classes = useStyles() const [state, setState] = useState(INITIAL_STATE) const address = useSelector(safeParamAddressFromStateSelector) @@ -66,7 +69,7 @@ const Balances = (props) => { setState((prevState) => ({ ...prevState, [`show${action}`]: false })) } - const showSendFunds = (tokenAddress) => { + const showSendFunds = (tokenAddress: string): void => { setState((prevState) => ({ ...prevState, sendFunds: { @@ -95,7 +98,7 @@ const Balances = (props) => { manageTokensButton, receiveModal, tokenControls, - } = props.classes + } = classes const { erc721Enabled, sendFunds, showManageCollectibleModal, showReceive, showToken } = state return ( @@ -227,4 +230,4 @@ const Balances = (props) => { ) } -export default withStyles(styles as any)(Balances) +export default Balances From 672d8f4482fdb20ffda5811051d5957e93b04823 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 09:55:34 -0300 Subject: [PATCH 08/52] Type formatAmount --- src/logic/tokens/utils/formatAmount.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/tokens/utils/formatAmount.ts b/src/logic/tokens/utils/formatAmount.ts index 033822a87a..d1eada60e3 100644 --- a/src/logic/tokens/utils/formatAmount.ts +++ b/src/logic/tokens/utils/formatAmount.ts @@ -12,8 +12,8 @@ const lt100mFormatter = new Intl.NumberFormat([], { maximumFractionDigits: 0 }) // same format for billions and trillions const lt1000tFormatter = new Intl.NumberFormat([], { maximumFractionDigits: 3, notation: 'compact' } as any) -export const formatAmount = (number) => { - let numberFloat: any = parseFloat(number) +export const formatAmount = (number: string): string => { + let numberFloat: number | string = parseFloat(number) if (numberFloat === 0) { numberFloat = '0' From fc866db8bbfa555faeca44f35119e6274a8cc5ac Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 10:25:52 -0300 Subject: [PATCH 09/52] Adds formatAmountInUsFormat util function --- src/logic/tokens/utils/formatAmount.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/logic/tokens/utils/formatAmount.ts b/src/logic/tokens/utils/formatAmount.ts index d1eada60e3..504e23015d 100644 --- a/src/logic/tokens/utils/formatAmount.ts +++ b/src/logic/tokens/utils/formatAmount.ts @@ -39,3 +39,10 @@ export const formatAmount = (number: string): string => { return numberFloat } + +export const formatAmountInUsFormat = (number: number | string): string => { + const options = { style: 'currency', currency: 'USD' } + const numberFormat = new Intl.NumberFormat('en-US', options) + const numberFloat: number = parseFloat(number as string) + return numberFormat.format(numberFloat).replace('$', '') +} From 46760749ddee3740ec52c7988a3cf196c6b328ad Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 11:01:00 -0300 Subject: [PATCH 10/52] Add types Uses formatAmountInUsFormat for BALANCE_TABLE_BALANCE_ID --- src/components/Table/sorting.ts | 2 +- .../store/model/currencyValues.ts | 2 +- .../safe/components/Balances/Coins/index.tsx | 15 ++++++++- .../safe/components/Balances/dataFetcher.ts | 33 ++++++++++++------- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/components/Table/sorting.ts b/src/components/Table/sorting.ts index b15a7b3394..ee4f7e40dd 100644 --- a/src/components/Table/sorting.ts +++ b/src/components/Table/sorting.ts @@ -2,7 +2,7 @@ import { List } from 'immutable' export const FIXED = 'fixed' -export const buildOrderFieldFrom = (attr) => `${attr}Order` +export const buildOrderFieldFrom = (attr: string): string => `${attr}Order` const desc = (a, b, orderBy, orderProp) => { const order = orderProp ? buildOrderFieldFrom(orderBy) : orderBy diff --git a/src/logic/currencyValues/store/model/currencyValues.ts b/src/logic/currencyValues/store/model/currencyValues.ts index 96b0d0c9f4..d27340668d 100644 --- a/src/logic/currencyValues/store/model/currencyValues.ts +++ b/src/logic/currencyValues/store/model/currencyValues.ts @@ -37,7 +37,7 @@ export enum AVAILABLE_CURRENCIES { ZAR = 'ZAR', } -type BalanceCurrencyRecord = { +export type BalanceCurrencyRecord = { currencyName?: string tokenAddress?: string balanceInBaseCurrency: string diff --git a/src/routes/safe/components/Balances/Coins/index.tsx b/src/routes/safe/components/Balances/Coins/index.tsx index b975064f3a..4d966bc6ad 100644 --- a/src/routes/safe/components/Balances/Coins/index.tsx +++ b/src/routes/safe/components/Balances/Coins/index.tsx @@ -36,6 +36,19 @@ type Props = { showSendFunds: (tokenAddress: string) => void } +export type BalanceDataRow = List<{ + asset: { + name: string + address: string + logoUri: string + } + assetOrder: string + balance: string + balanceOrder: number + fixed: boolean + value: string +}> + const Coins = (props: Props): React.ReactElement => { const { showReceiveFunds, showSendFunds } = props const classes = useStyles() @@ -46,7 +59,7 @@ const Coins = (props: Props): React.ReactElement => { const activeTokens = useSelector(extendedSafeTokensSelector) const currencyValues = useSelector(safeFiatBalancesListSelector) const granted = useSelector(grantedSelector) - const [filteredData, setFilteredData] = React.useState(List()) + const [filteredData, setFilteredData] = React.useState(List()) React.useMemo(() => { setFilteredData(getBalanceData(activeTokens, selectedCurrency, currencyValues, currencyRate)) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index d4ab9eeee2..ee8a57d2d4 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -1,9 +1,15 @@ import { BigNumber } from 'bignumber.js' import { List } from 'immutable' -import { FIXED, buildOrderFieldFrom } from 'src/components/Table/sorting' -import { formatAmount } from 'src/logic/tokens/utils/formatAmount' +import { buildOrderFieldFrom, FIXED } from 'src/components/Table/sorting' +import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' import { ETH_ADDRESS } from 'src/logic/tokens/utils/tokenHelpers' +import { + AVAILABLE_CURRENCIES, + BalanceCurrencyRecord, +} from '../../../../logic/currencyValues/store/model/currencyValues' +import { TokenProps } from '../../../../logic/tokens/store/model/token' +import { BalanceDataRow } from './Coins' export const BALANCE_TABLE_ASSET_ID = 'asset' export const BALANCE_TABLE_BALANCE_ID = 'balance' @@ -33,22 +39,25 @@ const getTokenPriceInCurrency = (token, currencySelected, currencyValues, curren return `${balance} ${currencySelected}` } -// eslint-disable-next-line max-len -export const getBalanceData = (activeTokens, currencySelected, currencyValues, currencyRate) => { - const rows = activeTokens.map((token) => ({ +export const getBalanceData = ( + activeTokens: List, + currencySelected: AVAILABLE_CURRENCIES, + currencyValues: List, + currencyRate: number, +): BalanceDataRow => { + return activeTokens.map((token) => ({ [BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri, address: token.address, }, - [buildOrderFieldFrom(BALANCE_TABLE_ASSET_ID)]: token.name, - [BALANCE_TABLE_BALANCE_ID]: `${formatAmount(token.balance)} ${token.symbol}`, - [buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)]: Number(token.balance), - [FIXED]: token.get('symbol') === 'ETH', + [buildOrderFieldFrom(BALANCE_TABLE_ASSET_ID) as string]: token.name as string, + [buildOrderFieldFrom(BALANCE_TABLE_ASSET_ID) as string]: token.name, + [BALANCE_TABLE_BALANCE_ID]: `${formatAmountInUsFormat(token.balance)} ${token.symbol}`, + [buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID) as string]: Number(token.balance) as number, + [FIXED]: token.symbol === 'ETH', [BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(token, currencySelected, currencyValues, currencyRate), - })) - - return rows + })) as BalanceDataRow } export const generateColumns = () => { From 3c5e37ab715b19abbf19bc8c41895ab1a9b3a701 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 11:14:19 -0300 Subject: [PATCH 11/52] Updates max and min fraction digits on formatAmountInUsFormat Add tests --- src/logic/tokens/utils/formatAmount.ts | 2 +- .../logic/token/utils/formatAmount.test.ts | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/test/logic/token/utils/formatAmount.test.ts diff --git a/src/logic/tokens/utils/formatAmount.ts b/src/logic/tokens/utils/formatAmount.ts index 504e23015d..be158d4f8b 100644 --- a/src/logic/tokens/utils/formatAmount.ts +++ b/src/logic/tokens/utils/formatAmount.ts @@ -41,7 +41,7 @@ export const formatAmount = (number: string): string => { } export const formatAmountInUsFormat = (number: number | string): string => { - const options = { style: 'currency', currency: 'USD' } + const options = { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 8 } const numberFormat = new Intl.NumberFormat('en-US', options) const numberFloat: number = parseFloat(number as string) return numberFormat.format(numberFloat).replace('$', '') diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts new file mode 100644 index 0000000000..3ed8537912 --- /dev/null +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -0,0 +1,60 @@ +import { formatAmountInUsFormat } from '../../../../logic/tokens/utils/formatAmount' + + +describe('FormatsAmountsInUsFormat', () => { + it('Given 0 returns 0.00', () => { + // given + const input = 0 + const resultExpected = '0.00' + + // when + const result = formatAmountInUsFormat(input) + + // then + expect(result).toBe(resultExpected) + }) + it('Given 1 returns 1.00', () => { + // given + const input = 1 + const resultExpected = '1.00' + + // when + const result = formatAmountInUsFormat(input) + + // then + expect(result).toBe(resultExpected) + }) + it('Given 19797.899 returns 19,797.899', () => { + // given + const input = 19797.899 + const resultExpected = '19,797.899' + + // when + const result = formatAmountInUsFormat(input) + + // then + expect(result).toBe(resultExpected) + }) + it('Given 19797899.479 returns 19,797,899.479', () => { + // given + const input = 19797899.479 + const resultExpected = '19,797,899.479' + + // when + const result = formatAmountInUsFormat(input) + + // then + expect(result).toBe(resultExpected) + }) + it('Given 19797899479.999 returns 19,797,899,479.999', () => { + // given + const input = 19797899479.999 + const resultExpected = '19,797,899,479.999' + + // when + const result = formatAmountInUsFormat(input) + + // then + expect(result).toBe(resultExpected) + }) +}) \ No newline at end of file From 5aac964c92966a02b5e0e6454afb02224ae48a7d Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 17 Jul 2020 11:23:28 -0300 Subject: [PATCH 12/52] Updates max and min fraction digits on formatAmountInUsFormat Add tests --- .../logic/token/utils/formatAmount.test.ts | 111 +++++++++++++++++- 1 file changed, 109 insertions(+), 2 deletions(-) diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts index 3ed8537912..96ad280e85 100644 --- a/src/test/logic/token/utils/formatAmount.test.ts +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -1,5 +1,111 @@ -import { formatAmountInUsFormat } from '../../../../logic/tokens/utils/formatAmount' +import { formatAmountInUsFormat, formatAmount } from '../../../../logic/tokens/utils/formatAmount' +describe('formatAmount', () => { + it('Given 0 returns 0', () => { + // given + const input = '0' + const resultExpected = '0' + + // when + const result = formatAmount(input) + + // then + expect(result).toBe(resultExpected) + }) + it('Given 1 returns 1', () => { + // given + const input = '1' + const resultExpected = '1' + + // when + const result = formatAmount(input) + + // then + expect(result).toBe(resultExpected) + }) + it('Given 19797.899 returns 19,797.899', () => { + // given + const input = '19797.899' + const resultExpected = '19,797.899' + + // when + const result = formatAmount(input) + + // then + expect(result).toBe(resultExpected) + }) + it('Given number > 0.001 && < 1000 returns the same number as string', () => { + // given + const input = 999 + const resultExpected = '999' + + // when + const result = formatAmount(input.toString()) + // then + expect(result).toBe(resultExpected) + }) + it('Given 9999 returns 9,999', () => { + // given + const input = 9999 + const resultExpected = '9,999' + + // when + const result = formatAmount(input.toString()) + // then + expect(result).toBe(resultExpected) + }) + it('Given 99999 returns 99,999', () => { + // given + const input = 99999 + const resultExpected = '99,999' + + // when + const result = formatAmount(input.toString()) + // then + expect(result).toBe(resultExpected) + }) + it('Given 999999 returns 999,999', () => { + // given + const input = 999999 + const resultExpected = '999,999' + + // when + const result = formatAmount(input.toString()) + // then + expect(result).toBe(resultExpected) + }) + it('Given 9999999 returns 9,999,999', () => { + // given + const input = 9999999 + const resultExpected = '9,999,999' + + // when + const result = formatAmount(input.toString()) + // then + expect(result).toBe(resultExpected) + }) + it('Given number < 0.001 returns < 0.001', () => { + // given + const input = 0.000001 + const resultExpected = '< 0.001' + + // when + const result = formatAmount(input.toString()) + // then + expect(result).toBe(resultExpected) + }) + it('Given number > 10 ** 15 returns > 1000T', () => { + // given + const input = 10 ** 15 * 2 + const resultExpected = '> 1000T' + + // when + const result = formatAmount(input.toString()) + + // then + expect(result).toBe(resultExpected) + }) +}) describe('FormatsAmountsInUsFormat', () => { it('Given 0 returns 0.00', () => { @@ -57,4 +163,5 @@ describe('FormatsAmountsInUsFormat', () => { // then expect(result).toBe(resultExpected) }) -}) \ No newline at end of file +}) + From 4648ac0079fa39b649c28f20710b7a61f6b080f4 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Sat, 18 Jul 2020 11:40:46 -0300 Subject: [PATCH 13/52] Add types --- src/logic/currencyValues/store/actions/fetchCurrencyRate.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts b/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts index 34a0dfbf49..be4ec8626e 100644 --- a/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts +++ b/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts @@ -1,8 +1,11 @@ import fetchCurrenciesRates from 'src/logic/currencyValues/api/fetchCurrenciesRates' import { setCurrencyRate } from 'src/logic/currencyValues/store/actions/setCurrencyRate' import { AVAILABLE_CURRENCIES } from 'src/logic/currencyValues/store/model/currencyValues' +import { Dispatch } from 'redux' -const fetchCurrencyRate = (safeAddress: string, selectedCurrency: AVAILABLE_CURRENCIES) => async (dispatch) => { +const fetchCurrencyRate = (safeAddress: string, selectedCurrency: AVAILABLE_CURRENCIES) => async ( + dispatch: Dispatch, +): Promise => { if (AVAILABLE_CURRENCIES.USD === selectedCurrency) { return dispatch(setCurrencyRate(safeAddress, 1)) } From 188f8fb5e5333e949975f7c901b5fb83d0950159 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Sun, 19 Jul 2020 13:38:33 -0300 Subject: [PATCH 14/52] Fix currencyValues types --- src/logic/currencyValues/store/model/currencyValues.ts | 4 ++-- src/store/index.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/logic/currencyValues/store/model/currencyValues.ts b/src/logic/currencyValues/store/model/currencyValues.ts index d27340668d..04b187000a 100644 --- a/src/logic/currencyValues/store/model/currencyValues.ts +++ b/src/logic/currencyValues/store/model/currencyValues.ts @@ -1,4 +1,4 @@ -import { Record } from 'immutable' +import { List, Record } from 'immutable' export enum AVAILABLE_CURRENCIES { ETH = 'ETH', @@ -47,7 +47,7 @@ export type BalanceCurrencyRecord = { export type CurrencyRateValue = { currencyRate?: number selectedCurrency?: AVAILABLE_CURRENCIES - currencyBalances?: BalanceCurrencyRecord[] + currencyBalances?: List } export const makeBalanceCurrency = Record({ diff --git a/src/store/index.ts b/src/store/index.ts index ea87073664..ffad05e7f1 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -29,10 +29,11 @@ import incomingTransactions, { } from 'src/routes/safe/store/reducer/incomingTransactions' import safe, { SAFE_REDUCER_ID, SafeReducerMap } from 'src/routes/safe/store/reducer/safe' import transactions, { TRANSACTIONS_REDUCER_ID } from 'src/routes/safe/store/reducer/transactions' -import { Map } from 'immutable' +import { Map, RecordOf } from 'immutable' import { NFTAssets, NFTTokens } from '../logic/collectibles/sources/OpenSea' import { ProviderRecord } from '../logic/wallets/store/model/provider' import { Token } from 'src/logic/tokens/store/model/token' +import { CurrencyRateValue } from '../logic/currencyValues/store/model/currencyValues' export const history = createHashHistory({ hashType: 'slash' }) @@ -77,7 +78,7 @@ export type AppReduxState = CombinedState<{ [CANCELLATION_TRANSACTIONS_REDUCER_ID]: Map [INCOMING_TRANSACTIONS_REDUCER_ID]: Map [NOTIFICATIONS_REDUCER_ID]: Map - [CURRENCY_VALUES_KEY]: Map + [CURRENCY_VALUES_KEY]: Map> [COOKIES_REDUCER_ID]: Map [ADDRESS_BOOK_REDUCER_ID]: Map [CURRENT_SESSION_REDUCER_ID]: Map From f4ae5468d31ae3599c9ae965c8059dc5d1e42903 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Sun, 19 Jul 2020 13:40:07 -0300 Subject: [PATCH 15/52] Adds safeFiatBalancesTotalSelector --- .../currencyValues/store/selectors/index.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/store/selectors/index.ts b/src/logic/currencyValues/store/selectors/index.ts index 8594f1e19a..8abebbf77b 100644 --- a/src/logic/currencyValues/store/selectors/index.ts +++ b/src/logic/currencyValues/store/selectors/index.ts @@ -1,10 +1,13 @@ -import { List } from 'immutable' +import { List, Map, RecordOf } from 'immutable' import { createSelector } from 'reselect' import { CURRENCY_VALUES_KEY } from 'src/logic/currencyValues/store/reducer/currencyValues' import { safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' +import { AppReduxState } from '../../../../store' +import { CurrencyRateValue } from '../model/currencyValues' -export const currencyValuesSelector = (state) => state[CURRENCY_VALUES_KEY] +export const currencyValuesSelector = (state: AppReduxState): Map> => + state[CURRENCY_VALUES_KEY] export const safeFiatBalancesSelector = createSelector( currencyValuesSelector, @@ -27,3 +30,13 @@ export const currentCurrencySelector = createSelector(safeFiatBalancesSelector, export const currencyRateSelector = createSelector(safeFiatBalancesSelector, (currencyValuesMap) => currencyValuesMap ? currencyValuesMap.get('currencyRate') : null, ) + +export const safeFiatBalancesTotalSelector = createSelector(safeFiatBalancesListSelector, (currencyBalances) => { + if (!currencyBalances) return 0 + + return currencyBalances + .map((balanceRecord) => balanceRecord.balanceInSelectedCurrency) + .reduce((accumulator, currentBalanceInSelectedCurrency) => { + return accumulator + parseFloat(currentBalanceInSelectedCurrency) + }, 0) +}) From 2ec2a6b1855190ce38b2f588de273bb30ff26595 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Sun, 19 Jul 2020 13:40:42 -0300 Subject: [PATCH 16/52] Adds total balance to safe header --- src/routes/safe/components/Layout/Header/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index cedb0bd61d..bd8c9d20ed 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -18,12 +18,15 @@ import Row from 'src/components/layout/Row' import { SAFE_VIEW_NAME_HEADING_TEST_ID } from 'src/routes/safe/components/Layout' import { grantedSelector } from 'src/routes/safe/container/selector' import { safeNameSelector, safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' +import { safeFiatBalancesTotalSelector } from '../../../../../logic/currencyValues/store/selectors' +import { formatAmountInUsFormat } from '../../../../../logic/tokens/utils/formatAmount' const LayoutHeader = (props) => { const { classes, onShow, showSendFunds } = props const address = useSelector(safeParamAddressFromStateSelector) const granted = useSelector(grantedSelector) const name = useSelector(safeNameSelector) + const currentSafeBalance = useSelector(safeFiatBalancesTotalSelector) if (!address) return null return ( @@ -33,7 +36,7 @@ const LayoutHeader = (props) => { - {name} + {name} | {formatAmountInUsFormat(currentSafeBalance)} USD {!granted && Read Only} From 91eb07025e2fb3ac3dd1743305209116d0ba287c Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 10:26:17 -0300 Subject: [PATCH 17/52] Fix types --- src/routes/safe/components/Balances/dataFetcher.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index 9888375453..bccd1597ca 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -46,20 +46,21 @@ export const getBalanceData = ( currencyValues: List, currencyRate: number, ): BalanceDataRow => { - return activeTokens.map((token) => ({ + const rows = activeTokens.map((token) => ({ [BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri, address: token.address, symbol: token.symbol, }, - [buildOrderFieldFrom(BALANCE_TABLE_ASSET_ID) as string]: token.name as string, - [buildOrderFieldFrom(BALANCE_TABLE_ASSET_ID) as string]: token.name, + ['assetOrder']: token.name, [BALANCE_TABLE_BALANCE_ID]: `${formatAmountInUsFormat(token.balance)} ${token.symbol}`, - [buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID) as string]: Number(token.balance) as number, + ['balanceOrder']: Number(token.balance), [FIXED]: token.symbol === 'ETH', [BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(token, currencySelected, currencyValues, currencyRate), - })) as BalanceDataRow + })) + + return rows } export const generateColumns = (): List => { From 931d0ce3c946c6000cd37ddc5d30f8af8e960203 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 10:30:15 -0300 Subject: [PATCH 18/52] Adds currentCurrency on header --- src/routes/safe/components/Layout/Header/index.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index bd8c9d20ed..eaf8c17fae 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -18,7 +18,10 @@ import Row from 'src/components/layout/Row' import { SAFE_VIEW_NAME_HEADING_TEST_ID } from 'src/routes/safe/components/Layout' import { grantedSelector } from 'src/routes/safe/container/selector' import { safeNameSelector, safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' -import { safeFiatBalancesTotalSelector } from '../../../../../logic/currencyValues/store/selectors' +import { + currentCurrencySelector, + safeFiatBalancesTotalSelector, +} from '../../../../../logic/currencyValues/store/selectors' import { formatAmountInUsFormat } from '../../../../../logic/tokens/utils/formatAmount' const LayoutHeader = (props) => { @@ -27,6 +30,7 @@ const LayoutHeader = (props) => { const granted = useSelector(grantedSelector) const name = useSelector(safeNameSelector) const currentSafeBalance = useSelector(safeFiatBalancesTotalSelector) + const currentCurrency = useSelector(currentCurrencySelector) if (!address) return null return ( @@ -36,7 +40,7 @@ const LayoutHeader = (props) => { - {name} | {formatAmountInUsFormat(currentSafeBalance)} USD + {name} | {formatAmountInUsFormat(currentSafeBalance)} {currentCurrency} {!granted && Read Only} From 31f1ce0466be2a903045ee5bbea124d1a1a119e4 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 10:54:57 -0300 Subject: [PATCH 19/52] Adds types to getTokenPriceInCurrency --- src/routes/safe/components/Balances/dataFetcher.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index bccd1597ca..962e490cdd 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -1,5 +1,5 @@ import { BigNumber } from 'bignumber.js' -import { List } from 'immutable' +import { List, RecordOf } from 'immutable' import { buildOrderFieldFrom, FIXED } from 'src/components/Table/sorting' import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' @@ -16,8 +16,12 @@ export const BALANCE_TABLE_ASSET_ID = 'asset' export const BALANCE_TABLE_BALANCE_ID = 'balance' export const BALANCE_TABLE_VALUE_ID = 'value' -// eslint-disable-next-line max-len -const getTokenPriceInCurrency = (token, currencySelected, currencyValues, currencyRate) => { +const getTokenPriceInCurrency = ( + token: RecordOf, + currencySelected: AVAILABLE_CURRENCIES, + currencyValues: List, + currencyRate: number | null, +): string => { if (!currencySelected) { return '' } @@ -41,7 +45,7 @@ const getTokenPriceInCurrency = (token, currencySelected, currencyValues, curren } export const getBalanceData = ( - activeTokens: List, + activeTokens: List>, currencySelected: AVAILABLE_CURRENCIES, currencyValues: List, currencyRate: number, From 58168ebf822c5e1735746442388f87cda486a45d Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 11:01:14 -0300 Subject: [PATCH 20/52] Fix balance currency rate conversion --- .../currencyValues/store/selectors/index.ts | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/logic/currencyValues/store/selectors/index.ts b/src/logic/currencyValues/store/selectors/index.ts index 8abebbf77b..1c8d333922 100644 --- a/src/logic/currencyValues/store/selectors/index.ts +++ b/src/logic/currencyValues/store/selectors/index.ts @@ -5,6 +5,7 @@ import { CURRENCY_VALUES_KEY } from 'src/logic/currencyValues/store/reducer/curr import { safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' import { AppReduxState } from '../../../../store' import { CurrencyRateValue } from '../model/currencyValues' +import { BigNumber } from 'bignumber.js' export const currencyValuesSelector = (state: AppReduxState): Map> => state[CURRENCY_VALUES_KEY] @@ -31,12 +32,17 @@ export const currencyRateSelector = createSelector(safeFiatBalancesSelector, (cu currencyValuesMap ? currencyValuesMap.get('currencyRate') : null, ) -export const safeFiatBalancesTotalSelector = createSelector(safeFiatBalancesListSelector, (currencyBalances) => { - if (!currencyBalances) return 0 - - return currencyBalances - .map((balanceRecord) => balanceRecord.balanceInSelectedCurrency) - .reduce((accumulator, currentBalanceInSelectedCurrency) => { - return accumulator + parseFloat(currentBalanceInSelectedCurrency) - }, 0) -}) +export const safeFiatBalancesTotalSelector = createSelector( + safeFiatBalancesListSelector, + currencyRateSelector, + (currencyBalances, currencyRate) => { + if (!currencyBalances) return 0 + + const totalInBaseCurrency = currencyBalances + .map((balanceRecord) => balanceRecord.balanceInBaseCurrency) + .reduce((accumulator, currentBalanceInSelectedCurrency) => { + return accumulator + parseFloat(currentBalanceInSelectedCurrency) + }, 0) + return new BigNumber(totalInBaseCurrency).times(currencyRate).toFixed(2) + }, +) From 0318452cab36cf52c5a11336feb6356fd30d4881 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 11:34:40 -0300 Subject: [PATCH 21/52] Add guards for modules --- src/routes/safe/store/actions/fetchSafe.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/routes/safe/store/actions/fetchSafe.ts b/src/routes/safe/store/actions/fetchSafe.ts index b73f5b7353..b82389c4df 100644 --- a/src/routes/safe/store/actions/fetchSafe.ts +++ b/src/routes/safe/store/actions/fetchSafe.ts @@ -39,8 +39,8 @@ const buildOwnersFrom = ( }) }) -const buildModulesLinkedList = (modules: string[], nextModule: string): Array | null => { - if (modules.length) { +const buildModulesLinkedList = (modules: string[] | null, nextModule: string): Array | null => { + if (modules && modules.length) { return modules.map((moduleAddress, index, modules) => { const prevModule = modules[index + 1] return [moduleAddress, prevModule !== undefined ? prevModule : nextModule] @@ -111,7 +111,7 @@ export const checkAndUpdateSafe = (safeAdd: string) => async (dispatch: Dispatch dispatch( addSafeModules({ safeAddress, - modulesAddresses: buildModulesLinkedList(modules.array, modules.next), + modulesAddresses: buildModulesLinkedList(modules?.array, modules?.next), }), ) From f32e606779b9ffe66313c232a279d4f2d1b9cf48 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 11:40:34 -0300 Subject: [PATCH 22/52] Add guards for modules --- src/routes/safe/store/actions/fetchSafe.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/safe/store/actions/fetchSafe.ts b/src/routes/safe/store/actions/fetchSafe.ts index b82389c4df..9fe934441d 100644 --- a/src/routes/safe/store/actions/fetchSafe.ts +++ b/src/routes/safe/store/actions/fetchSafe.ts @@ -40,7 +40,7 @@ const buildOwnersFrom = ( }) const buildModulesLinkedList = (modules: string[] | null, nextModule: string): Array | null => { - if (modules && modules.length) { + if (modules?.length) { return modules.map((moduleAddress, index, modules) => { const prevModule = modules[index + 1] return [moduleAddress, prevModule !== undefined ? prevModule : nextModule] From 753ff665147620535ac9337331ac1e31f5b56e66 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 13:12:30 -0300 Subject: [PATCH 23/52] Uses console error for api --- src/logic/currencyValues/api/fetchCurrenciesRates.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/api/fetchCurrenciesRates.ts b/src/logic/currencyValues/api/fetchCurrenciesRates.ts index 83d360fbdc..11b5414934 100644 --- a/src/logic/currencyValues/api/fetchCurrenciesRates.ts +++ b/src/logic/currencyValues/api/fetchCurrenciesRates.ts @@ -18,14 +18,15 @@ const fetchCurrenciesRates = async ( rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 } } catch (error) { + console.error('Fetching data from getExchangeRatesUrl errored', error) try { const result = await axios.get(fallbackUrl) if (result && result.data) { - const { rates } = result.data?.data + const { rates } = result.data.data rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 } } catch (error) { - console.log('Fetching data from exchangesRatesApiFallback errored', error) + console.error('Fetching data from exchangesRatesApiFallback errored', error) } } From 302125b3a4d93a8a49cb892f8d26496490d57cdb Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 13:14:36 -0300 Subject: [PATCH 24/52] Remove anys --- src/logic/currencyValues/store/actions/fetchCurrencyValues.ts | 2 +- src/logic/currencyValues/store/utils/currencyValuesStorage.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts b/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts index 6ef3b97a33..8e591eab49 100644 --- a/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts +++ b/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts @@ -10,7 +10,7 @@ import { Dispatch } from 'redux' export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: Dispatch): Promise => { try { - const storedCurrencies: Map | any = await loadCurrencyValues() + const storedCurrencies: Map | unknown = await loadCurrencyValues() const storedCurrency = storedCurrencies[safeAddress] if (!storedCurrency) { return batch(() => { diff --git a/src/logic/currencyValues/store/utils/currencyValuesStorage.ts b/src/logic/currencyValues/store/utils/currencyValuesStorage.ts index 002c88849c..f6e083aec7 100644 --- a/src/logic/currencyValues/store/utils/currencyValuesStorage.ts +++ b/src/logic/currencyValues/store/utils/currencyValuesStorage.ts @@ -11,6 +11,6 @@ export const saveCurrencyValues = async (currencyValues: Map | any> => { +export const loadCurrencyValues = async (): Promise | unknown> => { return (await loadFromStorage(CURRENCY_VALUES_STORAGE_KEY)) || {} } From c673bc35a35d4b489da961ed3483153af93a711d Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 13:16:30 -0300 Subject: [PATCH 25/52] Redefine CurrencyRateValue types into CurrencyRateValueRecord --- src/logic/currencyValues/store/model/currencyValues.ts | 4 +++- src/store/index.ts | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/logic/currencyValues/store/model/currencyValues.ts b/src/logic/currencyValues/store/model/currencyValues.ts index 04b187000a..8a0c0786bd 100644 --- a/src/logic/currencyValues/store/model/currencyValues.ts +++ b/src/logic/currencyValues/store/model/currencyValues.ts @@ -1,4 +1,4 @@ -import { List, Record } from 'immutable' +import { List, Record, RecordOf } from 'immutable' export enum AVAILABLE_CURRENCIES { ETH = 'ETH', @@ -50,6 +50,8 @@ export type CurrencyRateValue = { currencyBalances?: List } +export type CurrencyRateValueRecord = RecordOf + export const makeBalanceCurrency = Record({ currencyName: '', tokenAddress: '', diff --git a/src/store/index.ts b/src/store/index.ts index 95334d31cb..abc4ba12d3 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -30,8 +30,8 @@ import incomingTransactions, { import safe, { SAFE_REDUCER_ID, SafeReducerMap } from 'src/routes/safe/store/reducer/safe' import transactions, { TRANSACTIONS_REDUCER_ID } from 'src/routes/safe/store/reducer/transactions' import { NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/OpenSea' -import { Map, RecordOf } from 'immutable' -import { CurrencyRateValue } from '../logic/currencyValues/store/model/currencyValues' +import { Map } from 'immutable' +import { CurrencyRateValueRecord } from '../logic/currencyValues/store/model/currencyValues' export const history = createHashHistory({ hashType: 'slash' }) @@ -76,7 +76,7 @@ export type AppReduxState = CombinedState<{ [CANCELLATION_TRANSACTIONS_REDUCER_ID]: Map [INCOMING_TRANSACTIONS_REDUCER_ID]: Map [NOTIFICATIONS_REDUCER_ID]: Map - [CURRENCY_VALUES_KEY]: Map> + [CURRENCY_VALUES_KEY]: Map [COOKIES_REDUCER_ID]: Map [ADDRESS_BOOK_REDUCER_ID]: Map [CURRENT_SESSION_REDUCER_ID]: Map From a90ecd98e089794468e4f7946bff9b63aebb9c2c Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 13:26:43 -0300 Subject: [PATCH 26/52] Redefine test texts --- src/test/logic/token/utils/formatAmount.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts index 96ad280e85..70b079be85 100644 --- a/src/test/logic/token/utils/formatAmount.test.ts +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -23,7 +23,7 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) - it('Given 19797.899 returns 19,797.899', () => { + it('Given a number between 10000 and 100000 returns a number of format XX,XXX.XXX', () => { // given const input = '19797.899' const resultExpected = '19,797.899' @@ -44,7 +44,7 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) - it('Given 9999 returns 9,999', () => { + it('Given a number between 1000 and 10000 returns a number of format X,XXX', () => { // given const input = 9999 const resultExpected = '9,999' @@ -54,7 +54,7 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) - it('Given 99999 returns 99,999', () => { + it('Given a number between 10000 and 100000 returns a number of format XX,XXX', () => { // given const input = 99999 const resultExpected = '99,999' @@ -64,7 +64,7 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) - it('Given 999999 returns 999,999', () => { + it('Given a number between 100000 and 1000000 returns a number of format XXX,XXX', () => { // given const input = 999999 const resultExpected = '999,999' @@ -74,7 +74,7 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) - it('Given 9999999 returns 9,999,999', () => { + it('Given a number between 10000000 and 100000000 returns a number of format X,XXX,XXX', () => { // given const input = 9999999 const resultExpected = '9,999,999' @@ -130,7 +130,7 @@ describe('FormatsAmountsInUsFormat', () => { // then expect(result).toBe(resultExpected) }) - it('Given 19797.899 returns 19,797.899', () => { + it('Given a number in format XXXXX.XXX returns a number of format XX,XXX.XXX', () => { // given const input = 19797.899 const resultExpected = '19,797.899' @@ -141,7 +141,7 @@ describe('FormatsAmountsInUsFormat', () => { // then expect(result).toBe(resultExpected) }) - it('Given 19797899.479 returns 19,797,899.479', () => { + it('Given a number in format XXXXXXXX.XXX returns a number of format XX,XXX,XXX.XXX', () => { // given const input = 19797899.479 const resultExpected = '19,797,899.479' @@ -152,7 +152,7 @@ describe('FormatsAmountsInUsFormat', () => { // then expect(result).toBe(resultExpected) }) - it('Given 19797899479.999 returns 19,797,899,479.999', () => { + it('Given a number in format XXXXXXXXXXX.XXX returns a number of format XX,XXX,XXX,XXX.XXX', () => { // given const input = 19797899479.999 const resultExpected = '19,797,899,479.999' From c7a0be01315582149a2a962176a72e72db1fce51 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 13:30:00 -0300 Subject: [PATCH 27/52] Use absolute imports --- src/store/index.ts | 2 +- src/test/logic/token/utils/formatAmount.test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/store/index.ts b/src/store/index.ts index abc4ba12d3..416e68992b 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -31,7 +31,7 @@ import safe, { SAFE_REDUCER_ID, SafeReducerMap } from 'src/routes/safe/store/red import transactions, { TRANSACTIONS_REDUCER_ID } from 'src/routes/safe/store/reducer/transactions' import { NFTAssets, NFTTokens } from 'src/logic/collectibles/sources/OpenSea' import { Map } from 'immutable' -import { CurrencyRateValueRecord } from '../logic/currencyValues/store/model/currencyValues' +import { CurrencyRateValueRecord } from 'src/logic/currencyValues/store/model/currencyValues' export const history = createHashHistory({ hashType: 'slash' }) diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts index 70b079be85..e2dd334b8e 100644 --- a/src/test/logic/token/utils/formatAmount.test.ts +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -1,4 +1,5 @@ -import { formatAmountInUsFormat, formatAmount } from '../../../../logic/tokens/utils/formatAmount' +import { formatAmount, formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' + describe('formatAmount', () => { it('Given 0 returns 0', () => { From c33621e61ef6977bbb72490c6fe675b2f217eef4 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Mon, 20 Jul 2020 13:34:55 -0300 Subject: [PATCH 28/52] Add types to dispatch --- src/logic/currencyValues/store/actions/fetchCurrencyRate.ts | 2 +- src/logic/currencyValues/store/actions/fetchCurrencyValues.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts b/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts index be4ec8626e..d14979961f 100644 --- a/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts +++ b/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts @@ -4,7 +4,7 @@ import { AVAILABLE_CURRENCIES } from 'src/logic/currencyValues/store/model/curre import { Dispatch } from 'redux' const fetchCurrencyRate = (safeAddress: string, selectedCurrency: AVAILABLE_CURRENCIES) => async ( - dispatch: Dispatch, + dispatch: Dispatch, ): Promise => { if (AVAILABLE_CURRENCIES.USD === selectedCurrency) { return dispatch(setCurrencyRate(safeAddress, 1)) diff --git a/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts b/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts index 8e591eab49..b109f93e8d 100644 --- a/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts +++ b/src/logic/currencyValues/store/actions/fetchCurrencyValues.ts @@ -8,7 +8,9 @@ import { AVAILABLE_CURRENCIES, CurrencyRateValue } from 'src/logic/currencyValue import { loadCurrencyValues } from 'src/logic/currencyValues/store/utils/currencyValuesStorage' import { Dispatch } from 'redux' -export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: Dispatch): Promise => { +export const fetchCurrencyValues = (safeAddress: string) => async ( + dispatch: Dispatch, +): Promise => { try { const storedCurrencies: Map | unknown = await loadCurrencyValues() const storedCurrency = storedCurrencies[safeAddress] From 5a23d8f1d826d3c943fc5f0ffa997ea675d0a652 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 21 Jul 2020 10:52:07 -0300 Subject: [PATCH 29/52] Add guard for no balance value --- src/logic/currencyValues/store/selectors/index.ts | 1 + src/routes/safe/components/Layout/Header/index.tsx | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/logic/currencyValues/store/selectors/index.ts b/src/logic/currencyValues/store/selectors/index.ts index 1c8d333922..30f87b1d38 100644 --- a/src/logic/currencyValues/store/selectors/index.ts +++ b/src/logic/currencyValues/store/selectors/index.ts @@ -37,6 +37,7 @@ export const safeFiatBalancesTotalSelector = createSelector( currencyRateSelector, (currencyBalances, currencyRate) => { if (!currencyBalances) return 0 + if (!currencyRate) return null const totalInBaseCurrency = currencyBalances .map((balanceRecord) => balanceRecord.balanceInBaseCurrency) diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index eaf8c17fae..48a8d85603 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -33,6 +33,8 @@ const LayoutHeader = (props) => { const currentCurrency = useSelector(currentCurrencySelector) if (!address) return null + const totalBalancesFormatted = currentSafeBalance ? formatAmountInUsFormat(currentSafeBalance) : '' + return ( @@ -40,7 +42,8 @@ const LayoutHeader = (props) => { - {name} | {formatAmountInUsFormat(currentSafeBalance)} {currentCurrency} + {name} + {totalBalancesFormatted ? ` | ${totalBalancesFormatted} ${currentCurrency}` : ''} {!granted && Read Only} From 9dc19b3be96cc3bc26fc8e746312b3e0628a32b7 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 21 Jul 2020 11:08:21 -0300 Subject: [PATCH 30/52] Fix ESLINT warning --- src/routes/safe/components/Balances/dataFetcher.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index 962e490cdd..582193d8b3 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -50,21 +50,19 @@ export const getBalanceData = ( currencyValues: List, currencyRate: number, ): BalanceDataRow => { - const rows = activeTokens.map((token) => ({ + return activeTokens.map((token) => ({ [BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri, address: token.address, symbol: token.symbol, }, - ['assetOrder']: token.name, + assetOrder: token.name, [BALANCE_TABLE_BALANCE_ID]: `${formatAmountInUsFormat(token.balance)} ${token.symbol}`, - ['balanceOrder']: Number(token.balance), + balanceOrder: Number(token.balance), [FIXED]: token.symbol === 'ETH', [BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(token, currencySelected, currencyValues, currencyRate), })) - - return rows } export const generateColumns = (): List => { From 5de509640801c961def6386ee743da365866cb2f Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 21 Jul 2020 11:16:16 -0300 Subject: [PATCH 31/52] Add types --- src/components/Table/sorting.ts | 9 +++++++-- .../currencyValues/store/utils/currencyValuesStorage.ts | 2 +- src/routes/safe/components/Balances/dataFetcher.ts | 6 +----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/components/Table/sorting.ts b/src/components/Table/sorting.ts index ee4f7e40dd..cdff017aa9 100644 --- a/src/components/Table/sorting.ts +++ b/src/components/Table/sorting.ts @@ -38,5 +38,10 @@ export const stableSort = (dataArray, cmp, fixed) => { return fixedElems.concat(sortedElems) } -export const getSorting = (order, orderBy, orderProp) => - order === 'desc' ? (a, b) => desc(a, b, orderBy, orderProp) : (a, b) => -desc(a, b, orderBy, orderProp) +export const getSorting = ( + order: string, + orderBy?: string, + orderProp?: boolean, +): ((a: unknown, b: unknown) => number) => { + return order === 'desc' ? (a, b) => desc(a, b, orderBy, orderProp) : (a, b) => -desc(a, b, orderBy, orderProp) +} diff --git a/src/logic/currencyValues/store/utils/currencyValuesStorage.ts b/src/logic/currencyValues/store/utils/currencyValuesStorage.ts index f6e083aec7..6a265fc881 100644 --- a/src/logic/currencyValues/store/utils/currencyValuesStorage.ts +++ b/src/logic/currencyValues/store/utils/currencyValuesStorage.ts @@ -3,7 +3,7 @@ import { CurrencyRateValue } from '../model/currencyValues' import { Map } from 'immutable' const CURRENCY_VALUES_STORAGE_KEY = 'CURRENCY_VALUES_STORAGE_KEY' -export const saveCurrencyValues = async (currencyValues: Map) => { +export const saveCurrencyValues = async (currencyValues: Map): Promise => { try { await saveToStorage(CURRENCY_VALUES_STORAGE_KEY, currencyValues) } catch (err) { diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index 582193d8b3..81d8da34e6 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -1,7 +1,7 @@ import { BigNumber } from 'bignumber.js' import { List, RecordOf } from 'immutable' -import { buildOrderFieldFrom, FIXED } from 'src/components/Table/sorting' +import { FIXED } from 'src/components/Table/sorting' import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' import { ETH_ADDRESS } from 'src/logic/tokens/utils/tokenHelpers' import { TableColumn } from 'src/components/Table/types' @@ -114,7 +114,3 @@ export const generateColumns = (): List => { return List([assetColumn, balanceColumn, value, actions]) } - -// eslint-disable-next-line max-len -export const filterByZero = (data, hideZero) => - data.filter((row) => (hideZero ? row[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)] !== 0 : true)) From e38c3795f9966a96a38ef4fb719ca8c8508a5e50 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 21 Jul 2020 12:39:08 -0300 Subject: [PATCH 32/52] Fix no balance case --- .../safe/components/Balances/Coins/index.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/routes/safe/components/Balances/Coins/index.tsx b/src/routes/safe/components/Balances/Coins/index.tsx index 22ba4dafbf..2eb79fdfbe 100644 --- a/src/routes/safe/components/Balances/Coins/index.tsx +++ b/src/routes/safe/components/Balances/Coins/index.tsx @@ -80,7 +80,7 @@ const Coins = (props: Props): React.ReactElement => { sortedData.map((row, index) => ( {autoColumns.map((column) => { - const { align, id, width }: any = column + const { align, id, width } = column let cellItem switch (id) { case BALANCE_TABLE_ASSET_ID: { @@ -92,11 +92,16 @@ const Coins = (props: Props): React.ReactElement => { break } case BALANCE_TABLE_VALUE_ID: { - cellItem = row[id] ? ( -
{row[id]}
- ) : ( - - ) + // If there are no values for that row but we have balances, we display as '0.00 {CurrencySelected}' + // In case we don't have balances, we display a skeleton + const showCurrencyValueRow = row[id] || row[BALANCE_TABLE_BALANCE_ID] + + cellItem = + showCurrencyValueRow && selectedCurrency ? ( +
{row[id] ? row[id] : `0.00 ${selectedCurrency}`}
+ ) : ( + + ) break } default: { From 2b89b222513f8967b47c2a31c5c32f831c44d1f6 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 09:02:19 -0300 Subject: [PATCH 33/52] Use optional chaining --- src/logic/currencyValues/api/fetchCurrenciesRates.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/api/fetchCurrenciesRates.ts b/src/logic/currencyValues/api/fetchCurrenciesRates.ts index 11b5414934..a368fb449b 100644 --- a/src/logic/currencyValues/api/fetchCurrenciesRates.ts +++ b/src/logic/currencyValues/api/fetchCurrenciesRates.ts @@ -13,7 +13,7 @@ const fetchCurrenciesRates = async ( try { const result = await axios.get(url) - if (result && result.data) { + if (result?.data) { const { rates } = result.data rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 } @@ -21,7 +21,7 @@ const fetchCurrenciesRates = async ( console.error('Fetching data from getExchangeRatesUrl errored', error) try { const result = await axios.get(fallbackUrl) - if (result && result.data) { + if (result?.data) { const { rates } = result.data.data rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 } From b365fb9f68c95d7a0e55769145f42b3ce00086ce Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 09:08:54 -0300 Subject: [PATCH 34/52] Absolute paths --- src/logic/currencyValues/store/selectors/index.ts | 4 ++-- src/routes/safe/components/CurrencyDropdown/index.tsx | 2 +- src/routes/safe/components/Layout/Header/index.tsx | 8 +++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/logic/currencyValues/store/selectors/index.ts b/src/logic/currencyValues/store/selectors/index.ts index 30f87b1d38..ed250f8a30 100644 --- a/src/logic/currencyValues/store/selectors/index.ts +++ b/src/logic/currencyValues/store/selectors/index.ts @@ -3,8 +3,8 @@ import { createSelector } from 'reselect' import { CURRENCY_VALUES_KEY } from 'src/logic/currencyValues/store/reducer/currencyValues' import { safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' -import { AppReduxState } from '../../../../store' -import { CurrencyRateValue } from '../model/currencyValues' +import { AppReduxState } from 'src/store/index' +import { CurrencyRateValue } from 'src/logic/currencyValues/store/model/currencyValues' import { BigNumber } from 'bignumber.js' export const currencyValuesSelector = (state: AppReduxState): Map> => diff --git a/src/routes/safe/components/CurrencyDropdown/index.tsx b/src/routes/safe/components/CurrencyDropdown/index.tsx index c7eb029ab2..0bca043849 100644 --- a/src/routes/safe/components/CurrencyDropdown/index.tsx +++ b/src/routes/safe/components/CurrencyDropdown/index.tsx @@ -19,7 +19,7 @@ import { useDropdownStyles } from 'src/routes/safe/components/CurrencyDropdown/s import { safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' import { DropdownListTheme } from 'src/theme/mui' import { setImageToPlaceholder } from '../Balances/utils' -import Img from '../../../../components/layout/Img' +import Img from 'src/components/layout/Img/index' import etherIcon from 'src/assets/icons/icon_etherTokens.svg' const CurrencyDropdown = (): React.ReactElement => { diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index 48a8d85603..c2c4205048 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -18,11 +18,9 @@ import Row from 'src/components/layout/Row' import { SAFE_VIEW_NAME_HEADING_TEST_ID } from 'src/routes/safe/components/Layout' import { grantedSelector } from 'src/routes/safe/container/selector' import { safeNameSelector, safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' -import { - currentCurrencySelector, - safeFiatBalancesTotalSelector, -} from '../../../../../logic/currencyValues/store/selectors' -import { formatAmountInUsFormat } from '../../../../../logic/tokens/utils/formatAmount' + +import { currentCurrencySelector, safeFiatBalancesTotalSelector } from 'src/logic/currencyValues/store/selectors/index' +import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' const LayoutHeader = (props) => { const { classes, onShow, showSendFunds } = props From a69502972266f63d3aff7b5e16696f9fdf795a7e Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 09:28:48 -0300 Subject: [PATCH 35/52] Adds return types Uses BigNumber in safeFiatBalancesTotalSelector --- .../currencyValues/store/selectors/index.ts | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/logic/currencyValues/store/selectors/index.ts b/src/logic/currencyValues/store/selectors/index.ts index ed250f8a30..9b278f44f6 100644 --- a/src/logic/currencyValues/store/selectors/index.ts +++ b/src/logic/currencyValues/store/selectors/index.ts @@ -4,7 +4,12 @@ import { createSelector } from 'reselect' import { CURRENCY_VALUES_KEY } from 'src/logic/currencyValues/store/reducer/currencyValues' import { safeParamAddressFromStateSelector } from 'src/routes/safe/store/selectors' import { AppReduxState } from 'src/store/index' -import { CurrencyRateValue } from 'src/logic/currencyValues/store/model/currencyValues' +import { + AVAILABLE_CURRENCIES, + BalanceCurrencyRecord, + CurrencyRateValue, + CurrencyRateValueRecord, +} from 'src/logic/currencyValues/store/model/currencyValues' import { BigNumber } from 'bignumber.js' export const currencyValuesSelector = (state: AppReduxState): Map> => @@ -13,37 +18,41 @@ export const currencyValuesSelector = (state: AppReduxState): Map { + (currencyValues, safeAddress): CurrencyRateValueRecord => { if (!currencyValues) return return currencyValues.get(safeAddress) }, ) -export const safeFiatBalancesListSelector = createSelector(safeFiatBalancesSelector, (currencyValuesMap) => { - if (!currencyValuesMap) return - return currencyValuesMap.get('currencyBalances') ? currencyValuesMap.get('currencyBalances') : List([]) -}) +export const safeFiatBalancesListSelector = createSelector( + safeFiatBalancesSelector, + (currencyValuesMap): List => { + if (!currencyValuesMap) return + return currencyValuesMap.get('currencyBalances') ? currencyValuesMap.get('currencyBalances') : List([]) + }, +) -export const currentCurrencySelector = createSelector(safeFiatBalancesSelector, (currencyValuesMap) => - currencyValuesMap ? currencyValuesMap.get('selectedCurrency') : null, +export const currentCurrencySelector = createSelector( + safeFiatBalancesSelector, + (currencyValuesMap): AVAILABLE_CURRENCIES | null => + currencyValuesMap ? currencyValuesMap.get('selectedCurrency') : null, ) -export const currencyRateSelector = createSelector(safeFiatBalancesSelector, (currencyValuesMap) => +export const currencyRateSelector = createSelector(safeFiatBalancesSelector, (currencyValuesMap): number | null => currencyValuesMap ? currencyValuesMap.get('currencyRate') : null, ) export const safeFiatBalancesTotalSelector = createSelector( safeFiatBalancesListSelector, currencyRateSelector, - (currencyBalances, currencyRate) => { - if (!currencyBalances) return 0 + (currencyBalances, currencyRate): string | null => { + if (!currencyBalances) return '0' if (!currencyRate) return null - const totalInBaseCurrency = currencyBalances - .map((balanceRecord) => balanceRecord.balanceInBaseCurrency) - .reduce((accumulator, currentBalanceInSelectedCurrency) => { - return accumulator + parseFloat(currentBalanceInSelectedCurrency) - }, 0) - return new BigNumber(totalInBaseCurrency).times(currencyRate).toFixed(2) + const totalInBaseCurrency = currencyBalances.reduce((total, balanceCurrencyRecord) => { + return total.plus(balanceCurrencyRecord.balanceInBaseCurrency) + }, new BigNumber(0)) + + return totalInBaseCurrency.times(currencyRate).toFixed(2) }, ) From 698f7083aba9cc2bf42ae9a3eaf27ed5ccbeadb0 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 09:30:38 -0300 Subject: [PATCH 36/52] Remove number as type for formatAmountInUsFormat --- src/logic/tokens/utils/formatAmount.ts | 2 +- src/routes/safe/components/Balances/dataFetcher.ts | 2 +- src/test/logic/token/utils/formatAmount.test.ts | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/logic/tokens/utils/formatAmount.ts b/src/logic/tokens/utils/formatAmount.ts index be158d4f8b..3a3d310787 100644 --- a/src/logic/tokens/utils/formatAmount.ts +++ b/src/logic/tokens/utils/formatAmount.ts @@ -40,7 +40,7 @@ export const formatAmount = (number: string): string => { return numberFloat } -export const formatAmountInUsFormat = (number: number | string): string => { +export const formatAmountInUsFormat = (number: string): string => { const options = { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 8 } const numberFormat = new Intl.NumberFormat('en-US', options) const numberFloat: number = parseFloat(number as string) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index 81d8da34e6..935098ffcc 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -58,7 +58,7 @@ export const getBalanceData = ( symbol: token.symbol, }, assetOrder: token.name, - [BALANCE_TABLE_BALANCE_ID]: `${formatAmountInUsFormat(token.balance)} ${token.symbol}`, + [BALANCE_TABLE_BALANCE_ID]: `${formatAmountInUsFormat(token.balance.toString())} ${token.symbol}`, balanceOrder: Number(token.balance), [FIXED]: token.symbol === 'ETH', [BALANCE_TABLE_VALUE_ID]: getTokenPriceInCurrency(token, currencySelected, currencyValues, currencyRate), diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts index e2dd334b8e..60f0d65d81 100644 --- a/src/test/logic/token/utils/formatAmount.test.ts +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -115,7 +115,7 @@ describe('FormatsAmountsInUsFormat', () => { const resultExpected = '0.00' // when - const result = formatAmountInUsFormat(input) + const result = formatAmountInUsFormat(input.toString()) // then expect(result).toBe(resultExpected) @@ -126,7 +126,7 @@ describe('FormatsAmountsInUsFormat', () => { const resultExpected = '1.00' // when - const result = formatAmountInUsFormat(input) + const result = formatAmountInUsFormat(input.toString()) // then expect(result).toBe(resultExpected) @@ -137,7 +137,7 @@ describe('FormatsAmountsInUsFormat', () => { const resultExpected = '19,797.899' // when - const result = formatAmountInUsFormat(input) + const result = formatAmountInUsFormat(input.toString()) // then expect(result).toBe(resultExpected) @@ -148,7 +148,7 @@ describe('FormatsAmountsInUsFormat', () => { const resultExpected = '19,797,899.479' // when - const result = formatAmountInUsFormat(input) + const result = formatAmountInUsFormat(input.toString()) // then expect(result).toBe(resultExpected) @@ -159,7 +159,7 @@ describe('FormatsAmountsInUsFormat', () => { const resultExpected = '19,797,899,479.999' // when - const result = formatAmountInUsFormat(input) + const result = formatAmountInUsFormat(input.toString()) // then expect(result).toBe(resultExpected) From 2500d73b0306f9a811ce0749b4e58181efb80f74 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 09:33:02 -0300 Subject: [PATCH 37/52] Uses createStyles to remove any types --- src/routes/safe/components/Balances/index.tsx | 2 +- src/routes/safe/components/Balances/style.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/routes/safe/components/Balances/index.tsx b/src/routes/safe/components/Balances/index.tsx index adcbef13f0..391b3d29c3 100644 --- a/src/routes/safe/components/Balances/index.tsx +++ b/src/routes/safe/components/Balances/index.tsx @@ -41,7 +41,7 @@ const INITIAL_STATE = { export const COINS_LOCATION_REGEX = /\/balances\/?$/ export const COLLECTIBLES_LOCATION_REGEX = /\/balances\/collectibles$/ -const useStyles = makeStyles(styles as any) +const useStyles = makeStyles(styles) const Balances = (): React.ReactElement => { const classes = useStyles() diff --git a/src/routes/safe/components/Balances/style.ts b/src/routes/safe/components/Balances/style.ts index 259533a02b..bcdaf7823c 100644 --- a/src/routes/safe/components/Balances/style.ts +++ b/src/routes/safe/components/Balances/style.ts @@ -1,6 +1,7 @@ import { md, screenSm, secondary, xs } from 'src/theme/variables' +import { createStyles } from '@material-ui/core' -export const styles = () => ({ +export const styles = createStyles({ controls: { alignItems: 'center', boxSizing: 'border-box', @@ -10,7 +11,7 @@ export const styles = () => ({ assetTabs: { alignItems: 'center', display: 'flex', - order: '2', + order: 2, [`@media (min-width: ${screenSm}px)`]: { order: '1', @@ -41,7 +42,7 @@ export const styles = () => ({ alignItems: 'center', display: 'flex', justifyContent: 'space-between', - order: '1', + order: 1, padding: '0 0 10px', [`@media (min-width: ${screenSm}px)`]: { From 60a78c458ffe920089fd30e7ad4da87a080f7b48 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 09:37:15 -0300 Subject: [PATCH 38/52] Improve total balances display --- src/routes/safe/components/Layout/Header/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index c2c4205048..b7cb390625 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -41,7 +41,12 @@ const LayoutHeader = (props) => { {name} - {totalBalancesFormatted ? ` | ${totalBalancesFormatted} ${currentCurrency}` : ''} + {totalBalancesFormatted && currentCurrency && ( + + {' '} + | {totalBalancesFormatted} {currentCurrency} + + )} {!granted && Read Only} From 466dc0ee8bb09f63c0b24c32fadd01c00f04974b Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 10:09:25 -0300 Subject: [PATCH 39/52] Fix balances value column --- .../safe/components/Balances/dataFetcher.ts | 2 +- src/test/logic/token/utils/formatAmount.test.ts | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index 935098ffcc..637099a05d 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -41,7 +41,7 @@ const getTokenPriceInCurrency = ( const { balanceInBaseCurrency } = currencyValue const balance = new BigNumber(balanceInBaseCurrency).times(currencyRate).toFixed(2) - return `${balance} ${currencySelected}` + return `${formatAmountInUsFormat(balance)} ${currencySelected}` } export const getBalanceData = ( diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts index 60f0d65d81..26c40f944a 100644 --- a/src/test/logic/token/utils/formatAmount.test.ts +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -24,7 +24,7 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) - it('Given a number between 10000 and 100000 returns a number of format XX,XXX.XXX', () => { + it('Given a number in format XXXXX.XXX returns a number of format XX,XXX.XXX', () => { // given const input = '19797.899' const resultExpected = '19,797.899' @@ -35,6 +35,17 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) + it('Given a number in format XXXXX.XX returns a number of format XXX,XXX.XX', () => { + // given + const input = 311137.30 + const resultExpected = '311,137.30' + + // when + const result = formatAmountInUsFormat(input.toString()) + + // then + expect(result).toBe(resultExpected) + }) it('Given number > 0.001 && < 1000 returns the same number as string', () => { // given const input = 999 @@ -45,7 +56,7 @@ describe('formatAmount', () => { // then expect(result).toBe(resultExpected) }) - it('Given a number between 1000 and 10000 returns a number of format X,XXX', () => { + it('Given a number between 1000 and 10000 returns a number of format XX,XXX', () => { // given const input = 9999 const resultExpected = '9,999' From c21fac2566dc0a0ded5282b5ffdf5a67eb40dc9d Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 10:30:38 -0300 Subject: [PATCH 40/52] formatAmountInUsFormat feedback --- src/logic/tokens/utils/formatAmount.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/tokens/utils/formatAmount.ts b/src/logic/tokens/utils/formatAmount.ts index 3a3d310787..2fbda37fa5 100644 --- a/src/logic/tokens/utils/formatAmount.ts +++ b/src/logic/tokens/utils/formatAmount.ts @@ -40,9 +40,9 @@ export const formatAmount = (number: string): string => { return numberFloat } -export const formatAmountInUsFormat = (number: string): string => { +export const formatAmountInUsFormat = (amount: string): string => { const options = { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 8 } const numberFormat = new Intl.NumberFormat('en-US', options) - const numberFloat: number = parseFloat(number as string) + const numberFloat: number = parseFloat(amount) return numberFormat.format(numberFloat).replace('$', '') } From c8e5ceabdb7fdc6cd192db3c127cf10a01f2fdef Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 11:29:07 -0300 Subject: [PATCH 41/52] Force boolean evaluation --- src/routes/safe/components/Layout/Header/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index b7cb390625..49ea0eb003 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -41,7 +41,7 @@ const LayoutHeader = (props) => { {name} - {totalBalancesFormatted && currentCurrency && ( + {!!totalBalancesFormatted && !!currentCurrency && ( {' '} | {totalBalancesFormatted} {currentCurrency} From 4a661103279e80b6362c8f04fa123d9beccc1c72 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 12:33:11 -0300 Subject: [PATCH 42/52] Fix totalBalance heading styles --- src/routes/safe/components/Layout/Header/index.tsx | 4 ++-- src/routes/safe/components/Layout/Header/style.ts | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index 49ea0eb003..6c7e2f1ff4 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -42,10 +42,10 @@ const LayoutHeader = (props) => { {name} {!!totalBalancesFormatted && !!currentCurrency && ( - + {' '} | {totalBalancesFormatted} {currentCurrency} - + )} {!granted && Read Only} diff --git a/src/routes/safe/components/Layout/Header/style.ts b/src/routes/safe/components/Layout/Header/style.ts index 991952ff8a..7f304ac8f9 100644 --- a/src/routes/safe/components/Layout/Header/style.ts +++ b/src/routes/safe/components/Layout/Header/style.ts @@ -1,4 +1,4 @@ -import { screenSm, secondaryText, sm, smallFontSize, xs } from 'src/theme/variables' +import { screenSm, secondaryText, sm, smallFontSize, xs, disabled, fontSizeHeadingSm } from 'src/theme/variables' export const styles = () => ({ container: { @@ -90,4 +90,8 @@ export const styles = () => ({ wordBreak: 'break-word', whiteSpace: 'normal', }, + totalBalance: { + color: disabled, + fontSize: fontSizeHeadingSm, + }, }) From 8c2563f2848c1ccbab7271e0f6184d42d8338c98 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 12:38:59 -0300 Subject: [PATCH 43/52] Add types --- .../safe/components/Layout/Header/index.tsx | 16 ++++++++++++---- .../safe/components/Layout/Header/style.ts | 3 ++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index 6c7e2f1ff4..7384cfe40c 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -1,4 +1,4 @@ -import { withStyles } from '@material-ui/core/styles' +import { makeStyles } from '@material-ui/core/styles' import CallMade from '@material-ui/icons/CallMade' import CallReceived from '@material-ui/icons/CallReceived' import classNames from 'classnames/bind' @@ -22,8 +22,16 @@ import { safeNameSelector, safeParamAddressFromStateSelector } from 'src/routes/ import { currentCurrencySelector, safeFiatBalancesTotalSelector } from 'src/logic/currencyValues/store/selectors/index' import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' -const LayoutHeader = (props) => { - const { classes, onShow, showSendFunds } = props +const useStyles = makeStyles(styles) + +type Props = { + onShow: (modalName: string) => void + showSendFunds: (modalName: string) => void +} + +const LayoutHeader = (props: Props): React.ReactElement => { + const { onShow, showSendFunds } = props + const classes = useStyles(styles) const address = useSelector(safeParamAddressFromStateSelector) const granted = useSelector(grantedSelector) const name = useSelector(safeNameSelector) @@ -100,4 +108,4 @@ const LayoutHeader = (props) => {
) } -export default withStyles(styles as any)(LayoutHeader) +export default LayoutHeader diff --git a/src/routes/safe/components/Layout/Header/style.ts b/src/routes/safe/components/Layout/Header/style.ts index 7f304ac8f9..a3a300b16f 100644 --- a/src/routes/safe/components/Layout/Header/style.ts +++ b/src/routes/safe/components/Layout/Header/style.ts @@ -1,6 +1,7 @@ import { screenSm, secondaryText, sm, smallFontSize, xs, disabled, fontSizeHeadingSm } from 'src/theme/variables' +import { createStyles } from '@material-ui/core/styles' -export const styles = () => ({ +export const styles = createStyles({ container: { alignItems: 'center', display: 'flex', From 2bfc415eb056f98c7c579886f6f390eb83d5db65 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 17:54:29 -0300 Subject: [PATCH 44/52] Add types to fetchTokenCurrenciesBalances endpoint --- .../api/fetchTokenCurrenciesBalances.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts b/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts index fe4a293fd5..a3301560b6 100644 --- a/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts +++ b/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts @@ -1,8 +1,21 @@ -import axios from 'axios' +import axios, { AxiosResponse } from 'axios' import { getTxServiceHost } from 'src/config' +import { TokenProps } from '../../tokens/store/model/token' -const fetchTokenCurrenciesBalances = (safeAddress) => { +type BalanceEndpoint = { + balance: string + balanceUsd: string + tokenAddress?: string + token?: TokenProps + usdConversion: string +} + +interface ResponseData extends AxiosResponse { + data: BalanceEndpoint[] +} + +const fetchTokenCurrenciesBalances = (safeAddress?: string): Promise => { if (!safeAddress) { return null } From ecf3ed992a5f6ee82cdfdbdf6e10c7c357206b82 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Wed, 22 Jul 2020 18:31:09 -0300 Subject: [PATCH 45/52] Replaces coinbase dependency by backend for ETH price in USD --- .../api/fetchCurrenciesRates.ts | 30 +++++++++++-------- .../store/actions/fetchCurrencyRate.ts | 1 + 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/logic/currencyValues/api/fetchCurrenciesRates.ts b/src/logic/currencyValues/api/fetchCurrenciesRates.ts index a368fb449b..d0688e62fc 100644 --- a/src/logic/currencyValues/api/fetchCurrenciesRates.ts +++ b/src/logic/currencyValues/api/fetchCurrenciesRates.ts @@ -1,17 +1,31 @@ import axios from 'axios' -import { getExchangeRatesUrl, getExchangeRatesUrlFallback } from 'src/config' +import { getExchangeRatesUrl } from 'src/config' import { AVAILABLE_CURRENCIES } from '../store/model/currencyValues' +import fetchTokenCurrenciesBalances from './fetchTokenCurrenciesBalances' +import BigNumber from 'bignumber.js' const fetchCurrenciesRates = async ( baseCurrency: AVAILABLE_CURRENCIES, targetCurrencyValue: AVAILABLE_CURRENCIES, + safeAddress: string, ): Promise => { let rate = 0 - const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}` - const fallbackUrl = `${getExchangeRatesUrlFallback()}?currency=${baseCurrency}` + + if (targetCurrencyValue === AVAILABLE_CURRENCIES.ETH) { + try { + const result = await fetchTokenCurrenciesBalances(safeAddress) + if (result?.data && result?.data.length > 0) { + rate = new BigNumber(1).div(new BigNumber(result.data[0].usdConversion)).toNumber() + } + } catch (error) { + console.error('Fetching ETH data from the relayer errored', error) + } + return rate + } try { + const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}` const result = await axios.get(url) if (result?.data) { const { rates } = result.data @@ -19,17 +33,7 @@ const fetchCurrenciesRates = async ( } } catch (error) { console.error('Fetching data from getExchangeRatesUrl errored', error) - try { - const result = await axios.get(fallbackUrl) - if (result?.data) { - const { rates } = result.data.data - rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0 - } - } catch (error) { - console.error('Fetching data from exchangesRatesApiFallback errored', error) - } } - return rate } diff --git a/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts b/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts index d14979961f..72f668c6cb 100644 --- a/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts +++ b/src/logic/currencyValues/store/actions/fetchCurrencyRate.ts @@ -13,6 +13,7 @@ const fetchCurrencyRate = (safeAddress: string, selectedCurrency: AVAILABLE_CURR const selectedCurrencyRateInBaseCurrency: number = await fetchCurrenciesRates( AVAILABLE_CURRENCIES.USD, selectedCurrency, + safeAddress, ) dispatch(setCurrencyRate(safeAddress, selectedCurrencyRateInBaseCurrency)) From b1d6ae3f99991120158d4a284f2c304484588061 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Thu, 23 Jul 2020 09:58:57 -0300 Subject: [PATCH 46/52] Absolute paths --- src/routes/safe/components/Balances/dataFetcher.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index 637099a05d..b8c4f3b07c 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -5,11 +5,8 @@ import { FIXED } from 'src/components/Table/sorting' import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' import { ETH_ADDRESS } from 'src/logic/tokens/utils/tokenHelpers' import { TableColumn } from 'src/components/Table/types' -import { - AVAILABLE_CURRENCIES, - BalanceCurrencyRecord, -} from '../../../../logic/currencyValues/store/model/currencyValues' -import { TokenProps } from '../../../../logic/tokens/store/model/token' +import { AVAILABLE_CURRENCIES, BalanceCurrencyRecord } from 'src/logic/currencyValues/store/model/currencyValues' +import { TokenProps } from 'src/logic/tokens/store/model/token' import { BalanceDataRow } from './Coins' export const BALANCE_TABLE_ASSET_ID = 'asset' From 00f24e3f598d5a53da87c30b6bff8a27f8bc28b9 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Thu, 23 Jul 2020 10:00:55 -0300 Subject: [PATCH 47/52] Replaces RecordOf with Token --- src/routes/safe/components/Balances/dataFetcher.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index b8c4f3b07c..5578176132 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -6,7 +6,7 @@ import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' import { ETH_ADDRESS } from 'src/logic/tokens/utils/tokenHelpers' import { TableColumn } from 'src/components/Table/types' import { AVAILABLE_CURRENCIES, BalanceCurrencyRecord } from 'src/logic/currencyValues/store/model/currencyValues' -import { TokenProps } from 'src/logic/tokens/store/model/token' +import { Token, TokenProps } from 'src/logic/tokens/store/model/token' import { BalanceDataRow } from './Coins' export const BALANCE_TABLE_ASSET_ID = 'asset' @@ -42,7 +42,7 @@ const getTokenPriceInCurrency = ( } export const getBalanceData = ( - activeTokens: List>, + activeTokens: List, currencySelected: AVAILABLE_CURRENCIES, currencyValues: List, currencyRate: number, From 8625248c50d15bf4d56bfc5acb3125d6cee31135 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Thu, 23 Jul 2020 10:16:24 -0300 Subject: [PATCH 48/52] Feedback --- src/logic/currencyValues/api/fetchCurrenciesRates.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/currencyValues/api/fetchCurrenciesRates.ts b/src/logic/currencyValues/api/fetchCurrenciesRates.ts index d0688e62fc..00e2c48a1d 100644 --- a/src/logic/currencyValues/api/fetchCurrenciesRates.ts +++ b/src/logic/currencyValues/api/fetchCurrenciesRates.ts @@ -15,8 +15,8 @@ const fetchCurrenciesRates = async ( if (targetCurrencyValue === AVAILABLE_CURRENCIES.ETH) { try { const result = await fetchTokenCurrenciesBalances(safeAddress) - if (result?.data && result?.data.length > 0) { - rate = new BigNumber(1).div(new BigNumber(result.data[0].usdConversion)).toNumber() + if (result?.data?.length) { + rate = new BigNumber(1).div(result.data[0].usdConversion).toNumber() } } catch (error) { console.error('Fetching ETH data from the relayer errored', error) From 91cd4e4dc9792805f4a69f42deecf180c4a987b6 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Fri, 24 Jul 2020 11:33:36 -0300 Subject: [PATCH 49/52] Trigger buid From d9b6b6e8c324364fa2e34f9cbfe93183669535d1 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 28 Jul 2020 10:17:32 -0300 Subject: [PATCH 50/52] Types --- .../api/fetchTokenCurrenciesBalances.ts | 6 +- src/logic/tokens/utils/formatAmount.ts | 5 +- .../safe/components/Balances/dataFetcher.ts | 6 +- .../safe/components/Layout/Header/index.tsx | 6 +- .../logic/token/utils/formatAmount.test.ts | 66 +++++++++---------- 5 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts b/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts index a3301560b6..5c4fc5418d 100644 --- a/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts +++ b/src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts @@ -11,11 +11,7 @@ type BalanceEndpoint = { usdConversion: string } -interface ResponseData extends AxiosResponse { - data: BalanceEndpoint[] -} - -const fetchTokenCurrenciesBalances = (safeAddress?: string): Promise => { +const fetchTokenCurrenciesBalances = (safeAddress?: string): Promise> => { if (!safeAddress) { return null } diff --git a/src/logic/tokens/utils/formatAmount.ts b/src/logic/tokens/utils/formatAmount.ts index 2fbda37fa5..e6111f2c02 100644 --- a/src/logic/tokens/utils/formatAmount.ts +++ b/src/logic/tokens/utils/formatAmount.ts @@ -40,9 +40,10 @@ export const formatAmount = (number: string): string => { return numberFloat } +const options = { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 8 } +const numberFormat = new Intl.NumberFormat('en-US', options) + export const formatAmountInUsFormat = (amount: string): string => { - const options = { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 8 } - const numberFormat = new Intl.NumberFormat('en-US', options) const numberFloat: number = parseFloat(amount) return numberFormat.format(numberFloat).replace('$', '') } diff --git a/src/routes/safe/components/Balances/dataFetcher.ts b/src/routes/safe/components/Balances/dataFetcher.ts index 5578176132..fb0e311e15 100644 --- a/src/routes/safe/components/Balances/dataFetcher.ts +++ b/src/routes/safe/components/Balances/dataFetcher.ts @@ -1,12 +1,12 @@ import { BigNumber } from 'bignumber.js' -import { List, RecordOf } from 'immutable' +import { List } from 'immutable' import { FIXED } from 'src/components/Table/sorting' import { formatAmountInUsFormat } from 'src/logic/tokens/utils/formatAmount' import { ETH_ADDRESS } from 'src/logic/tokens/utils/tokenHelpers' import { TableColumn } from 'src/components/Table/types' import { AVAILABLE_CURRENCIES, BalanceCurrencyRecord } from 'src/logic/currencyValues/store/model/currencyValues' -import { Token, TokenProps } from 'src/logic/tokens/store/model/token' +import { Token } from 'src/logic/tokens/store/model/token' import { BalanceDataRow } from './Coins' export const BALANCE_TABLE_ASSET_ID = 'asset' @@ -14,7 +14,7 @@ export const BALANCE_TABLE_BALANCE_ID = 'balance' export const BALANCE_TABLE_VALUE_ID = 'value' const getTokenPriceInCurrency = ( - token: RecordOf, + token: Token, currencySelected: AVAILABLE_CURRENCIES, currencyValues: List, currencyRate: number | null, diff --git a/src/routes/safe/components/Layout/Header/index.tsx b/src/routes/safe/components/Layout/Header/index.tsx index 7384cfe40c..5d0c07bc0b 100644 --- a/src/routes/safe/components/Layout/Header/index.tsx +++ b/src/routes/safe/components/Layout/Header/index.tsx @@ -39,7 +39,7 @@ const LayoutHeader = (props: Props): React.ReactElement => { const currentCurrency = useSelector(currentCurrencySelector) if (!address) return null - const totalBalancesFormatted = currentSafeBalance ? formatAmountInUsFormat(currentSafeBalance) : '' + const formattedTotalBalance = currentSafeBalance ? formatAmountInUsFormat(currentSafeBalance) : '' return ( @@ -49,10 +49,10 @@ const LayoutHeader = (props: Props): React.ReactElement => { {name} - {!!totalBalancesFormatted && !!currentCurrency && ( + {!!formattedTotalBalance && !!currentCurrency && ( {' '} - | {totalBalancesFormatted} {currentCurrency} + | {formattedTotalBalance} {currentCurrency} )} diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts index 26c40f944a..261ab0aa16 100644 --- a/src/test/logic/token/utils/formatAmount.test.ts +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -5,117 +5,117 @@ describe('formatAmount', () => { it('Given 0 returns 0', () => { // given const input = '0' - const resultExpected = '0' + const expectedResult = '0' // when const result = formatAmount(input) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given 1 returns 1', () => { // given const input = '1' - const resultExpected = '1' + const expectedResult = '1' // when const result = formatAmount(input) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) - it('Given a number in format XXXXX.XXX returns a number of format XX,XXX.XXX', () => { + it('Given a string in format XXXXX.XXX returns a number of format XX,XXX.XXX', () => { // given const input = '19797.899' - const resultExpected = '19,797.899' + const expectedResult = '19,797.899' // when const result = formatAmount(input) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number in format XXXXX.XX returns a number of format XXX,XXX.XX', () => { // given const input = 311137.30 - const resultExpected = '311,137.30' + const expectedResult = '311,137.30' // when const result = formatAmountInUsFormat(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given number > 0.001 && < 1000 returns the same number as string', () => { // given const input = 999 - const resultExpected = '999' + const expectedResult = '999' // when const result = formatAmount(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number between 1000 and 10000 returns a number of format XX,XXX', () => { // given const input = 9999 - const resultExpected = '9,999' + const expectedResult = '9,999' // when const result = formatAmount(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number between 10000 and 100000 returns a number of format XX,XXX', () => { // given const input = 99999 - const resultExpected = '99,999' + const expectedResult = '99,999' // when const result = formatAmount(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number between 100000 and 1000000 returns a number of format XXX,XXX', () => { // given const input = 999999 - const resultExpected = '999,999' + const expectedResult = '999,999' // when const result = formatAmount(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number between 10000000 and 100000000 returns a number of format X,XXX,XXX', () => { // given const input = 9999999 - const resultExpected = '9,999,999' + const expectedResult = '9,999,999' // when const result = formatAmount(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given number < 0.001 returns < 0.001', () => { // given const input = 0.000001 - const resultExpected = '< 0.001' + const expectedResult = '< 0.001' // when const result = formatAmount(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given number > 10 ** 15 returns > 1000T', () => { // given const input = 10 ** 15 * 2 - const resultExpected = '> 1000T' + const expectedResult = '> 1000T' // when const result = formatAmount(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) }) @@ -123,57 +123,57 @@ describe('FormatsAmountsInUsFormat', () => { it('Given 0 returns 0.00', () => { // given const input = 0 - const resultExpected = '0.00' + const expectedResult = '0.00' // when const result = formatAmountInUsFormat(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given 1 returns 1.00', () => { // given const input = 1 - const resultExpected = '1.00' + const expectedResult = '1.00' // when const result = formatAmountInUsFormat(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number in format XXXXX.XXX returns a number of format XX,XXX.XXX', () => { // given const input = 19797.899 - const resultExpected = '19,797.899' + const expectedResult = '19,797.899' // when const result = formatAmountInUsFormat(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number in format XXXXXXXX.XXX returns a number of format XX,XXX,XXX.XXX', () => { // given const input = 19797899.479 - const resultExpected = '19,797,899.479' + const expectedResult = '19,797,899.479' // when const result = formatAmountInUsFormat(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) it('Given a number in format XXXXXXXXXXX.XXX returns a number of format XX,XXX,XXX,XXX.XXX', () => { // given const input = 19797899479.999 - const resultExpected = '19,797,899,479.999' + const expectedResult = '19,797,899,479.999' // when const result = formatAmountInUsFormat(input.toString()) // then - expect(result).toBe(resultExpected) + expect(result).toBe(expectedResult) }) }) From 539108310f5f0978f958219ef6950c9303b3b5fb Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 28 Jul 2020 10:19:21 -0300 Subject: [PATCH 51/52] Fix tests order --- .../logic/token/utils/formatAmount.test.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/test/logic/token/utils/formatAmount.test.ts b/src/test/logic/token/utils/formatAmount.test.ts index 261ab0aa16..94fc60c90d 100644 --- a/src/test/logic/token/utils/formatAmount.test.ts +++ b/src/test/logic/token/utils/formatAmount.test.ts @@ -35,17 +35,6 @@ describe('formatAmount', () => { // then expect(result).toBe(expectedResult) }) - it('Given a number in format XXXXX.XX returns a number of format XXX,XXX.XX', () => { - // given - const input = 311137.30 - const expectedResult = '311,137.30' - - // when - const result = formatAmountInUsFormat(input.toString()) - - // then - expect(result).toBe(expectedResult) - }) it('Given number > 0.001 && < 1000 returns the same number as string', () => { // given const input = 999 @@ -142,6 +131,17 @@ describe('FormatsAmountsInUsFormat', () => { // then expect(result).toBe(expectedResult) }) + it('Given a number in format XXXXX.XX returns a number of format XXX,XXX.XX', () => { + // given + const input = 311137.30 + const expectedResult = '311,137.30' + + // when + const result = formatAmountInUsFormat(input.toString()) + + // then + expect(result).toBe(expectedResult) + }) it('Given a number in format XXXXX.XXX returns a number of format XX,XXX.XXX', () => { // given const input = 19797.899 From 1efec3a95600bb650b26867ac65969e2aa90a4b1 Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 28 Jul 2020 12:15:53 -0300 Subject: [PATCH 52/52] Renames numberFormat to usNumberFormatter --- src/logic/tokens/utils/formatAmount.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logic/tokens/utils/formatAmount.ts b/src/logic/tokens/utils/formatAmount.ts index e6111f2c02..77ba6091b6 100644 --- a/src/logic/tokens/utils/formatAmount.ts +++ b/src/logic/tokens/utils/formatAmount.ts @@ -41,9 +41,9 @@ export const formatAmount = (number: string): string => { } const options = { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 8 } -const numberFormat = new Intl.NumberFormat('en-US', options) +const usNumberFormatter = new Intl.NumberFormat('en-US', options) export const formatAmountInUsFormat = (amount: string): string => { const numberFloat: number = parseFloat(amount) - return numberFormat.format(numberFloat).replace('$', '') + return usNumberFormatter.format(numberFloat).replace('$', '') }