Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
5602812
Fix ts error
Agupane Jul 16, 2020
ac742d8
Add skeleton for loading balance value
Agupane Jul 16, 2020
0c7c5aa
Fix texts in uppercase
Agupane Jul 16, 2020
2b8056e
Adds ETH Icon in currencyValues dropdown
Agupane Jul 17, 2020
e7693d2
Adds getExchangeRatesUrlFallback
Agupane Jul 17, 2020
762861d
Alphabetically sort currencies
Agupane Jul 17, 2020
a12b62a
Add types
Agupane Jul 17, 2020
672d8f4
Type formatAmount
Agupane Jul 17, 2020
fc866db
Adds formatAmountInUsFormat util function
Agupane Jul 17, 2020
4676074
Add types
Agupane Jul 17, 2020
3c5e37a
Updates max and min fraction digits on formatAmountInUsFormat
Agupane Jul 17, 2020
5aac964
Updates max and min fraction digits on formatAmountInUsFormat
Agupane Jul 17, 2020
4648ac0
Add types
Agupane Jul 18, 2020
188f8fb
Fix currencyValues types
Agupane Jul 19, 2020
f4ae546
Adds safeFiatBalancesTotalSelector
Agupane Jul 19, 2020
2ec2a6b
Adds total balance to safe header
Agupane Jul 19, 2020
b490b16
Merge branch 'development' of https://github.com/gnosis/safe-react in…
Agupane Jul 20, 2020
91eb070
Fix types
Agupane Jul 20, 2020
931d0ce
Adds currentCurrency on header
Agupane Jul 20, 2020
31f1ce0
Adds types to getTokenPriceInCurrency
Agupane Jul 20, 2020
58168eb
Fix balance currency rate conversion
Agupane Jul 20, 2020
0318452
Add guards for modules
Agupane Jul 20, 2020
dc44932
Merge branch 'fix-add-type-guards' into balances-enhacements
Agupane Jul 20, 2020
f32e606
Add guards for modules
Agupane Jul 20, 2020
039ae42
Merge branch 'fix-add-type-guards' into balances-enhacements
Agupane Jul 20, 2020
753ff66
Uses console error for api
Agupane Jul 20, 2020
302125b
Remove anys
Agupane Jul 20, 2020
c673bc3
Redefine CurrencyRateValue types into CurrencyRateValueRecord
Agupane Jul 20, 2020
a90ecd9
Redefine test texts
Agupane Jul 20, 2020
c7a0be0
Use absolute imports
Agupane Jul 20, 2020
d738355
Merge branch 'development' into balances-enhacements
Agupane Jul 20, 2020
c33621e
Add types to dispatch
Agupane Jul 20, 2020
3aca31e
Merge branch 'development' into balances-enhacements
mmv08 Jul 21, 2020
8e3cd29
Merge branch 'development' into balances-enhacements
mmv08 Jul 21, 2020
5a23d8f
Add guard for no balance value
Agupane Jul 21, 2020
9239ada
Merge remote-tracking branch 'origin/balances-enhacements' into balan…
Agupane Jul 21, 2020
9dc19b3
Fix ESLINT warning
Agupane Jul 21, 2020
5de5096
Add types
Agupane Jul 21, 2020
a2d906f
Merge branch 'development' of https://github.com/gnosis/safe-react in…
Agupane Jul 21, 2020
e38c379
Fix no balance case
Agupane Jul 21, 2020
2b89b22
Use optional chaining
Agupane Jul 22, 2020
b365fb9
Absolute paths
Agupane Jul 22, 2020
a695029
Adds return types
Agupane Jul 22, 2020
698f708
Remove number as type for formatAmountInUsFormat
Agupane Jul 22, 2020
2500d73
Uses createStyles to remove any types
Agupane Jul 22, 2020
60a78c4
Improve total balances display
Agupane Jul 22, 2020
466dc0e
Fix balances value column
Agupane Jul 22, 2020
c21fac2
formatAmountInUsFormat feedback
Agupane Jul 22, 2020
c8e5cea
Force boolean evaluation
Agupane Jul 22, 2020
4a66110
Fix totalBalance heading styles
Agupane Jul 22, 2020
8c2563f
Add types
Agupane Jul 22, 2020
2bfc415
Add types to fetchTokenCurrenciesBalances endpoint
Agupane Jul 22, 2020
ecf3ed9
Replaces coinbase dependency by backend for ETH price in USD
Agupane Jul 22, 2020
e3bf715
Merge branch 'development' into balances-enhacements
mmv08 Jul 23, 2020
b1d6ae3
Absolute paths
Agupane Jul 23, 2020
00f24e3
Replaces RecordOf<TokenProps> with Token
Agupane Jul 23, 2020
be90cf3
Merge remote-tracking branch 'origin/balances-enhacements' into balan…
Agupane Jul 23, 2020
8625248
Feedback
Agupane Jul 23, 2020
5d3b2ac
Merge branch 'development' into balances-enhacements
Agupane Jul 24, 2020
91cd4e4
Trigger buid
Agupane Jul 24, 2020
365b5d3
Merge remote-tracking branch 'origin/balances-enhacements' into balan…
Agupane Jul 24, 2020
30bd83f
Merge branch 'development' into balances-enhacements
mmv08 Jul 28, 2020
d9b6b6e
Types
Agupane Jul 28, 2020
1ef9d4a
Merge remote-tracking branch 'origin/balances-enhacements' into balan…
Agupane Jul 28, 2020
5391083
Fix tests order
Agupane Jul 28, 2020
1efec3a
Renames numberFormat to usNumberFormatter
Agupane Jul 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/components/Table/sorting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
2 changes: 2 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
28 changes: 23 additions & 5 deletions src/logic/currencyValues/api/fetchCurrenciesRates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,38 @@ import axios from 'axios'

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<number> => {
let rate = 0
const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}`

const result = await axios.get(url)
if (result && result.data) {
const { rates } = result.data
rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0
if (targetCurrencyValue === AVAILABLE_CURRENCIES.ETH) {
try {
const result = await fetchTokenCurrenciesBalances(safeAddress)
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)
}
return rate
}

try {
const url = `${getExchangeRatesUrl()}?base=${baseCurrency}&symbols=${targetCurrencyValue}`
const result = await axios.get(url)
if (result?.data) {
const { rates } = result.data
rate = rates[targetCurrencyValue] ? rates[targetCurrencyValue] : 0
}
} catch (error) {
console.error('Fetching data from getExchangeRatesUrl errored', error)
}
return rate
}

Expand Down
13 changes: 11 additions & 2 deletions src/logic/currencyValues/api/fetchTokenCurrenciesBalances.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
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
}

const fetchTokenCurrenciesBalances = (safeAddress?: string): Promise<AxiosResponse<BalanceEndpoint[]>> => {
if (!safeAddress) {
return null
}
Expand Down
6 changes: 5 additions & 1 deletion src/logic/currencyValues/store/actions/fetchCurrencyRate.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
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<typeof setCurrencyRate>,
): Promise<void> => {
if (AVAILABLE_CURRENCIES.USD === selectedCurrency) {
return dispatch(setCurrencyRate(safeAddress, 1))
}

const selectedCurrencyRateInBaseCurrency: number = await fetchCurrenciesRates(
AVAILABLE_CURRENCIES.USD,
selectedCurrency,
safeAddress,
)

dispatch(setCurrencyRate(safeAddress, selectedCurrencyRateInBaseCurrency))
Expand Down
7 changes: 5 additions & 2 deletions src/logic/currencyValues/store/actions/fetchCurrencyValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ 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<typeof setCurrencyBalances | typeof setSelectedCurrency | typeof setCurrencyRate>,
): Promise<void> => {
try {
const storedCurrencies: Map<string, CurrencyRateValue> | any = await loadCurrencyValues()
const storedCurrencies: Map<string, CurrencyRateValue> | unknown = await loadCurrencyValues()
const storedCurrency = storedCurrencies[safeAddress]
if (!storedCurrency) {
return batch(() => {
Expand Down
53 changes: 28 additions & 25 deletions src/logic/currencyValues/store/model/currencyValues.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
import { Record } from 'immutable'
import { List, Record, RecordOf } from 'immutable'

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 = {
export type BalanceCurrencyRecord = {
currencyName?: string
tokenAddress?: string
balanceInBaseCurrency: string
Expand All @@ -46,9 +47,11 @@ type BalanceCurrencyRecord = {
export type CurrencyRateValue = {
currencyRate?: number
selectedCurrency?: AVAILABLE_CURRENCIES
currencyBalances?: BalanceCurrencyRecord[]
currencyBalances?: List<BalanceCurrencyRecord>
}

export type CurrencyRateValueRecord = RecordOf<CurrencyRateValue>

export const makeBalanceCurrency = Record({
currencyName: '',
tokenAddress: '',
Expand Down
49 changes: 39 additions & 10 deletions src/logic/currencyValues/store/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,58 @@
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 'src/store/index'
import {
AVAILABLE_CURRENCIES,
BalanceCurrencyRecord,
CurrencyRateValue,
CurrencyRateValueRecord,
} from 'src/logic/currencyValues/store/model/currencyValues'
import { BigNumber } from 'bignumber.js'

export const currencyValuesSelector = (state) => state[CURRENCY_VALUES_KEY]
export const currencyValuesSelector = (state: AppReduxState): Map<string, RecordOf<CurrencyRateValue>> =>
state[CURRENCY_VALUES_KEY]

export const safeFiatBalancesSelector = createSelector(
currencyValuesSelector,
safeParamAddressFromStateSelector,
(currencyValues, safeAddress) => {
(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<BalanceCurrencyRecord> => {
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): string | null => {
if (!currencyBalances) return '0'
if (!currencyRate) return null

const totalInBaseCurrency = currencyBalances.reduce((total, balanceCurrencyRecord) => {
return total.plus(balanceCurrencyRecord.balanceInBaseCurrency)
}, new BigNumber(0))

return totalInBaseCurrency.times(currencyRate).toFixed(2)
},
)
4 changes: 2 additions & 2 deletions src/logic/currencyValues/store/utils/currencyValuesStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { CurrencyRateValue } from '../model/currencyValues'
import { Map } from 'immutable'

const CURRENCY_VALUES_STORAGE_KEY = 'CURRENCY_VALUES_STORAGE_KEY'
export const saveCurrencyValues = async (currencyValues: Map<string, CurrencyRateValue>) => {
export const saveCurrencyValues = async (currencyValues: Map<string, CurrencyRateValue>): Promise<void> => {
try {
await saveToStorage(CURRENCY_VALUES_STORAGE_KEY, currencyValues)
} catch (err) {
console.error('Error storing currency values info in localstorage', err)
}
}

export const loadCurrencyValues = async (): Promise<Map<string, CurrencyRateValue> | any> => {
export const loadCurrencyValues = async (): Promise<Map<string, CurrencyRateValue> | unknown> => {
return (await loadFromStorage(CURRENCY_VALUES_STORAGE_KEY)) || {}
}
12 changes: 10 additions & 2 deletions src/logic/tokens/utils/formatAmount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -39,3 +39,11 @@ export const formatAmount = (number) => {

return numberFloat
}

const options = { style: 'currency', currency: 'USD', minimumFractionDigits: 2, maximumFractionDigits: 8 }
const usNumberFormatter = new Intl.NumberFormat('en-US', options)

export const formatAmountInUsFormat = (amount: string): string => {
const numberFloat: number = parseFloat(amount)
return usNumberFormatter.format(numberFloat).replace('$', '')
}
39 changes: 32 additions & 7 deletions src/routes/safe/components/Balances/Coins/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -30,10 +27,29 @@ 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)

const Coins = (props) => {
type Props = {
showReceiveFunds: () => void
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()
const columns = generateColumns()
Expand All @@ -43,7 +59,7 @@ const Coins = (props) => {
const activeTokens = useSelector(extendedSafeTokensSelector)
const currencyValues = useSelector(safeFiatBalancesListSelector)
const granted = useSelector(grantedSelector)
const [filteredData, setFilteredData] = React.useState(List())
const [filteredData, setFilteredData] = React.useState<BalanceDataRow>(List())

React.useMemo(() => {
setFilteredData(getBalanceData(activeTokens, selectedCurrency, currencyValues, currencyRate))
Expand All @@ -64,7 +80,7 @@ const Coins = (props) => {
sortedData.map((row, index) => (
<TableRow className={classes.hide} data-testid={BALANCE_ROW_TEST_ID} key={index} tabIndex={-1}>
{autoColumns.map((column) => {
const { align, id, width }: any = column
const { align, id, width } = column
let cellItem
switch (id) {
case BALANCE_TABLE_ASSET_ID: {
Expand All @@ -76,7 +92,16 @@ const Coins = (props) => {
break
}
case BALANCE_TABLE_VALUE_ID: {
cellItem = <div className={classes.currencyValueRow}>{row[id]}</div>
// 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 ? (
<div className={classes.currencyValueRow}>{row[id] ? row[id] : `0.00 ${selectedCurrency}`}</div>
) : (
<Skeleton animation="wave" />
)
break
}
default: {
Expand Down
Loading