Fix: make percentage chart work properly

Fix: code review

Fix: rework components according to PR requested changes

Fix: fix repeated code buildRatesNoCommission

Also renames id to deviceId in transactions quer

Fix: pr requested changes

Chore: move inline styles to classes

Chore: remove comment

Fix: bad equality !process.env.NODE_ENV === 'production'
This commit is contained in:
Cesar 2020-12-07 19:58:20 +00:00 committed by Josh Harvey
parent 5572fb0eb1
commit ae7eaca10c
43 changed files with 818 additions and 1578 deletions

View file

@ -1,10 +1,11 @@
import { useQuery } from '@apollo/react-hooks'
import Grid from '@material-ui/core/Grid'
import { makeStyles } from '@material-ui/core/styles'
import BigNumber from 'bignumber.js'
import gql from 'graphql-tag'
import moment from 'moment'
import * as R from 'ramda'
import React, { useState, useEffect } from 'react'
import React, { useState } from 'react'
import { Label2 } from 'src/components/typography/index'
import { ReactComponent as TriangleDown } from 'src/styling/icons/arrow/triangle_down.svg'
@ -18,18 +19,31 @@ import InfoWithLabel from './InfoWithLabel'
import Nav from './Nav'
import styles from './SystemPerformance.styles'
const isNotProp = R.curry(R.compose(R.isNil, R.prop))
BigNumber.config({ ROUNDING_MODE: BigNumber.ROUND_HALF_UP })
const getFiats = R.map(R.prop('fiat'))
const getProps = propName => R.map(R.prop(propName))
const useStyles = makeStyles(styles)
const mapToFee = R.map(R.prop('cashInFee'))
const getDateSecondsAgo = (seconds = 0, startDate = null) => {
if (startDate) {
return moment(startDate).subtract(seconds, 'second')
}
return moment().subtract(seconds, 'second')
const date = startDate ? moment(startDate) : moment()
return date.subtract(seconds, 'second')
}
// const now = moment()
const ranges = {
Day: {
left: getDateSecondsAgo(2 * 24 * 3600, moment()),
right: getDateSecondsAgo(24 * 3600, moment())
},
Week: {
left: getDateSecondsAgo(14 * 24 * 3600, moment()),
right: getDateSecondsAgo(7 * 24 * 3600, moment())
},
Month: {
left: getDateSecondsAgo(60 * 24 * 3600, moment()),
right: getDateSecondsAgo(30 * 24 * 3600, moment())
}
}
const GET_DATA = gql`
query getData {
@ -42,7 +56,7 @@ const GET_DATA = gql`
txClass
error
}
btcRates {
fiatRates {
code
name
rate
@ -51,134 +65,72 @@ const GET_DATA = gql`
}
`
const reducer = (acc, it) =>
(acc +=
Number.parseFloat(it.commissionPercentage) * Number.parseFloat(it.fiat))
const SystemPerformance = () => {
const classes = useStyles()
const [selectedRange, setSelectedRange] = useState('Day')
const [transactionsToShow, setTransactionsToShow] = useState([])
const [transactionsLastTimePeriod, setTransactionsLastTimePeriod] = useState(
[]
)
const { data, loading } = useQuery(GET_DATA)
const fiatLocale = fromNamespace('locale')(data?.config).fiatCurrency
useEffect(() => {
const isInRange = (getLastTimePeriod = false) => t => {
const now = moment()
switch (selectedRange) {
case 'Day':
if (getLastTimePeriod) {
return (
t.error === null &&
moment(t.created).isBetween(
getDateSecondsAgo(2 * 24 * 3600, now),
getDateSecondsAgo(24 * 3600, now)
)
)
}
return (
t.error === null &&
moment(t.created).isBetween(getDateSecondsAgo(24 * 3600, now), now)
)
case 'Week':
if (getLastTimePeriod) {
return (
t.error === null &&
moment(t.created).isBetween(
getDateSecondsAgo(14 * 24 * 3600, now),
getDateSecondsAgo(7 * 24 * 3600, now)
)
)
}
return (
t.error === null &&
moment(t.created).isBetween(
getDateSecondsAgo(7 * 24 * 3600, now),
now
)
)
case 'Month':
if (getLastTimePeriod) {
return (
t.error === null &&
moment(t.created).isBetween(
getDateSecondsAgo(60 * 24 * 3600, now),
getDateSecondsAgo(30 * 24 * 3600, now)
)
)
}
return (
t.error === null &&
moment(t.created).isBetween(
getDateSecondsAgo(30 * 24 * 3600, now),
now
)
)
default:
return t.error === null && true
}
const isInRangeAndNoError = getLastTimePeriod => t => {
if (t.error !== null) return false
if (!getLastTimePeriod) {
return (
t.error === null &&
moment(t.created).isBetween(ranges[selectedRange].right, moment())
)
}
const convertFiatToLocale = item => {
if (item.fiatCode === fiatLocale) return item
const itemRate = R.find(R.propEq('code', item.fiatCode))(data.btcRates)
const localeRate = R.find(R.propEq('code', fiatLocale))(data.btcRates)
const multiplier = localeRate.rate / itemRate.rate
return { ...item, fiat: parseFloat(item.fiat) * multiplier }
}
setTransactionsToShow(
R.map(convertFiatToLocale)(
R.filter(isInRange(false), data?.transactions ?? [])
return (
t.error === null &&
moment(t.created).isBetween(
ranges[selectedRange].left,
ranges[selectedRange].right
)
)
setTransactionsLastTimePeriod(
R.map(convertFiatToLocale)(
R.filter(isInRange(true), data?.transactions ?? [])
)
)
}, [data, fiatLocale, selectedRange])
const handleSetRange = range => {
setSelectedRange(range)
}
const convertFiatToLocale = item => {
if (item.fiatCode === fiatLocale) return item
const itemRate = R.find(R.propEq('code', item.fiatCode))(data.fiatRates)
const localeRate = R.find(R.propEq('code', fiatLocale))(data.fiatRates)
const multiplier = localeRate.rate / itemRate.rate
return { ...item, fiat: parseFloat(item.fiat) * multiplier }
}
const transactionsToShow = R.map(convertFiatToLocale)(
R.filter(isInRangeAndNoError(false), data?.transactions ?? [])
)
const transactionsLastTimePeriod = R.map(convertFiatToLocale)(
R.filter(isInRangeAndNoError(true), data?.transactions ?? [])
)
const getNumTransactions = () => {
return R.length(R.filter(isNotProp('error'), transactionsToShow))
return R.length(transactionsToShow)
}
const getFiatVolume = () => {
// for explanation check https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
return +(
Math.round(
R.sum(getFiats(R.filter(isNotProp('error'), transactionsToShow))) +
'e+2'
) + 'e-2'
)
}
const getFiatVolume = () =>
new BigNumber(R.sum(getFiats(transactionsToShow)))
.decimalPlaces(2)
.toNumber()
const getProfit = (transactions = transactionsToShow) => {
const cashInFees = R.sum(
getProps('cashInFee')(R.filter(isNotProp('error'), transactions))
)
let commissionFees = 0
transactions.forEach(t => {
if (t.error === null) {
commissionFees +=
Number.parseFloat(t.commissionPercentage) * Number.parseFloat(t.fiat)
}
})
return +(Math.round(commissionFees + cashInFees + 'e+2') + 'e-2')
const getProfit = transactions => {
const cashInFees = R.sum(mapToFee(transactions))
const commissionFees = R.reduce(reducer, 0, transactions)
return new BigNumber(commissionFees + cashInFees)
.decimalPlaces(2)
.toNumber()
}
const getPercentChange = () => {
const thisTimePeriodProfit = getProfit(transactionsToShow)
const previousTimePeriodProfit = getProfit(transactionsLastTimePeriod)
if (previousTimePeriodProfit === 0) {
return 100
}
if (previousTimePeriodProfit === 0) return 100
return Math.round(
(100 * (thisTimePeriodProfit - previousTimePeriodProfit)) /
Math.abs(previousTimePeriodProfit)
@ -186,36 +138,17 @@ const SystemPerformance = () => {
}
const getDirectionPercent = () => {
const directions = {
cashIn: 0,
cashOut: 0,
length: 0
const [cashIn, cashOut] = R.partition(R.propEq('txClass', 'cashIn'))(
transactionsToShow
)
const totalLength = cashIn.length + cashOut.length
if (totalLength === 0) {
return { cashIn: 0, cashOut: 0 }
}
transactionsToShow.forEach(t => {
if (t.error === null) {
switch (t.txClass) {
case 'cashIn':
directions.cashIn += 1
directions.length += 1
break
case 'cashOut':
directions.cashOut += 1
directions.length += 1
break
default:
break
}
}
})
return {
cashIn:
directions.length > 0
? Math.round((directions.cashIn / directions.length) * 100)
: 0,
cashOut:
directions.length > 0
? Math.round((directions.cashOut / directions.length) * 100)
: 0
cashIn: Math.round((cashIn.length / totalLength) * 100),
cashOut: Math.round((cashOut.length / totalLength) * 100)
}
}
@ -223,7 +156,7 @@ const SystemPerformance = () => {
return (
<>
<Nav handleSetRange={handleSetRange} />
<Nav handleSetRange={setSelectedRange} />
{!loading && (
<>
<Grid container spacing={2}>
@ -241,7 +174,7 @@ const SystemPerformance = () => {
</Grid>
{/* todo new customers */}
</Grid>
<Grid container style={{ marginTop: 30 }}>
<Grid container className={classes.gridContainer}>
<Grid item xs={12}>
<Label2>Transactions</Label2>
<Scatterplot
@ -250,27 +183,23 @@ const SystemPerformance = () => {
/>
</Grid>
</Grid>
<Grid container style={{ marginTop: 30 }}>
<Grid container className={classes.gridContainer}>
<Grid item xs={8}>
<Label2>Profit from commissions</Label2>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
margin: '0 26px -30px 16px',
position: 'relative'
}}>
<div className={classes.profitContainer}>
<div className={classes.profitLabel}>
{`${getProfit()} ${data?.config.locale_fiatCurrency}`}
{`${getProfit(transactionsToShow)} ${
data?.config.locale_fiatCurrency
}`}
</div>
<div
className={
percentChange <= 0 ? classes.percentDown : classes.percentUp
}>
{percentChange <= 0 ? (
<TriangleDown style={{ height: 13 }} />
<TriangleDown className={classes.percentDown} />
) : (
<TriangleUp style={{ height: 10 }} />
<TriangleUp className={classes.percentUp} />
)}{' '}
{`${percentChange}%`}
</div>
@ -281,7 +210,10 @@ const SystemPerformance = () => {
<Label2>Direction</Label2>
<Grid container>
<Grid item xs>
<PercentageChart data={getDirectionPercent()} />
<PercentageChart
cashIn={getDirectionPercent().cashIn}
cashOut={getDirectionPercent().cashOut}
/>
</Grid>
</Grid>
</Grid>