Skip to content

Commit

Permalink
refactor(webapp): split rewards distribution state
Browse files Browse the repository at this point in the history
  • Loading branch information
Torresmorah committed Jan 18, 2023
1 parent 893ce54 commit 066a7fe
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 274 deletions.
122 changes: 122 additions & 0 deletions webapp/src/hooks/customHooks/useRewardsDistributionState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { useState, useEffect } from 'react'
import { useLazyQuery } from '@apollo/client'

import { countries } from 'utils/countries'
import { PRODUCERS_QUERY, SETTING_QUERY } from '../../gql'

const useRewardsDistributionState = () => {
const [loadSettings, { data: { setting } = {} }] = useLazyQuery(SETTING_QUERY)
const [loadProducers, { loading = true, data: { producers } = {} }] =
useLazyQuery(PRODUCERS_QUERY)
const [summary, setSummary] = useState()
const [items, setItems] = useState([])

useEffect(() => {
loadSettings({})
loadProducers({
variables: {
where: { total_rewards: { _gte: 100 } },
offset: 0,
limit: 2100,
},
})
}, [loadSettings, loadProducers])

useEffect(() => {
if (!producers) return

let stats = {
'N/A': {
code: 'N/A',
name: 'N/A',
quantity: 0,
items: [],
rewards: 0,
},
}
let dailyRewards = 0
const items = producers || []

const handleInvalidCountry = (producer) => {
stats['N/A'].items.push(producer)
stats['N/A'].rewards += producer.total_rewards
stats['N/A'].quantity += 1
}

const handleValidCountry = (producer) => {
if (!stats[producer.bp_json.org.location.country]) {
stats = {
...stats,
[producer.bp_json.org.location.country]: {
code: producer.bp_json.org.location.country,
name: countries[producer.bp_json.org.location.country]?.name,
flag: countries[producer.bp_json.org.location.country]?.flag,
quantity: 1,
coordinates: [
producer.bp_json.org.location.longitude,
producer.bp_json.org.location.latitude,
],
items: [producer],
rewards: producer.total_rewards,
},
}
} else {
stats[producer.bp_json.org.location.country].items.push(producer)
stats[producer.bp_json.org.location.country].rewards +=
producer.total_rewards
stats[producer.bp_json.org.location.country].quantity += 1

if (
producer.bp_json.org.location.longitude &&
producer.bp_json.org.location.latitude
) {
stats[producer.bp_json.org.location.country].coordinates = [
producer.bp_json.org.location.longitude,
producer.bp_json.org.location.latitude,
]
}
}
}

items
.filter((a) => a.total_rewards >= 100)
.forEach((producer) => {
dailyRewards += producer.total_rewards || 0

if (!producer?.bp_json?.org?.location?.country) {
handleInvalidCountry(producer)
return
}

handleValidCountry(producer)
})

const nodes = Object.values(stats)
const topCountryByRewards = nodes.reduce(
(prev, current) => {
return current.rewards > prev.rewards && current.code !== 'N/A'
? current
: prev
},
{ rewards: 0 },
)

setSummary({
dailyRewards,
topCountryByRewards,
producersWithoutProperBpJson: stats['N/A'],
})
setItems(nodes)
}, [producers])

return [
{
loading,
nodes: items,
setting,
summary,
},
]
}

export default useRewardsDistributionState
4 changes: 2 additions & 2 deletions webapp/src/language/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,14 @@
"topCountryDailyRwards": "Top Country By Daily Rewards",
"notAvailable": "Not available",
"paidProducers": "Paid Producers Not Located",
"clickToViewBPs": "Click to view non-compliant BPs",
"lowestRewards": "Lowest Rewards",
"highestRewards": "Highest Rewards",
"exchangeRate": "Exchange Rate",
"country": "Country",
"rewards": "Rewards",
"rewardsPercentage": "Percentage of rewards",
"viewList": "View full list"
"viewList": "View full list",
"paidProducersText": "in daily rewards"
},
"nodesRoute": {},
"nodesDistributionRoute": {},
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/language/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@
"topCountryDailyRwards": "País Superior Por Recompensas Diarias",
"notAvailable": "No Disponible",
"paidProducers": "Productores Pagados No Ubicados",
"clickToViewBPs": "Haga clic para ver los PB no conformes",
"lowestRewards": "Recompensas Más Bajas",
"highestRewards": "Recompensas Más Altas",
"exchangeRate": "Tipo De Cambio",
"country": "País",
"rewards": "Recompensas",
"rewardsPercentage": "Porcentaje de recompensas",
"viewList": "Ver lista completa"
"viewList": "Ver lista completa",
"paidProducersText": "en recompensas diarias"
},
"nodesRoute": {},
"nodesDistributionRoute": {},
Expand Down
188 changes: 188 additions & 0 deletions webapp/src/routes/RewardsDistribution/RewardsDistributionStats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import React from 'react'
import { Link } from 'react-router-dom'
import { makeStyles } from '@mui/styles'
import { useTranslation } from 'react-i18next'
import Button from '@mui/material/Button'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
import Typography from '@mui/material/Typography'
import Skeleton from '@mui/material/Skeleton'

import { formatWithThousandSeparator } from '../../utils'
import CountryFlag from '../../components/CountryFlag'
import { eosConfig } from '../../config'

import styles from './styles'
import TokenToUSD from './TokenToUSD'

const lowestRewardsColor = '#B6EBF3'
const highestRewardsColor = '#265F63'

const useStyles = makeStyles((theme) =>
styles(theme, lowestRewardsColor, highestRewardsColor),
)

const RewardsDistributionStats = ({
summary,
nodes,
setting,
handlePopoverOpen,
}) => {
const classes = useStyles()
const { t } = useTranslation('rewardsDistributionRoute')

return (
<div className={classes.divMargin}>
<div className={classes.cardHeader}>
<Card className={classes.cardShadow}>
<CardContent className={classes.cards}>
<Typography variant="h6">{t('dailyRewards')}</Typography>
<Typography variant="h3">
{!nodes.length > 0 && (
<Skeleton variant="text" width="100%" animation="wave" />
)}
{nodes.length > 0 && (
<span>
{formatWithThousandSeparator(summary.dailyRewards, 2)}{' '}
{eosConfig.tokenSymbol}
</span>
)}
</Typography>
<Typography variant="h3">
{!nodes.length > 0 && (
<Skeleton variant="text" width="100%" animation="wave" />
)}
{nodes.length > 0 && setting?.token_price && (
<span>
$
{formatWithThousandSeparator(
summary.dailyRewards * setting?.token_price,
0,
)}{' '}
USD
</span>
)}
</Typography>
</CardContent>
</Card>
</div>
<div className={classes.cardHeader}>
<Card className={classes.cardShadow}>
<CardContent className={classes.cards}>
<Typography variant="h6">{t('topCountryDailyRwards')}</Typography>
<Typography variant="h3">
{!nodes.length > 0 && (
<Skeleton variant="text" width="100%" animation="wave" />
)}
{nodes.length > 0 && (
<>
{summary.topCountryByRewards.name}
<CountryFlag code={summary.topCountryByRewards.code} />
</>
)}
</Typography>
<div className={`${classes.textMargin} ${classes.spaceBetween}`}>
<Typography variant="subtitle1">
{!nodes?.length > 0 && (
<Skeleton variant="text" width="100%" animation="wave" />
)}
{nodes?.length > 0 && setting?.token_price && (
<TokenToUSD
amount={summary.topCountryByRewards.rewards}
tokenPrice={setting?.token_price}
/>
)}
</Typography>
<ExpandMoreIcon
className={classes.expandIcon}
onClick={handlePopoverOpen(summary?.topCountryByRewards)}
/>
</div>
</CardContent>
</Card>
</div>
<div className={classes.cardHeader}>
<Card className={classes.cardShadow}>
<CardContent className={classes.cards}>
<Typography variant="h6">{t('paidProducers')}</Typography>
<Typography variant="h3">
{!nodes.length > 0 && (
<Skeleton variant="text" width="100%" animation="wave" />
)}
{nodes.length > 0 &&
summary?.producersWithoutProperBpJson.quantity && (
<span className={classes.spaceBetween}>
{summary?.producersWithoutProperBpJson.quantity}
<Button
className={classes.nonCompliantButton}
component={Link}
to="/non-compliant-bps"
variant="contained"
color="secondary"
mt={2}
>
{t('viewList')}
</Button>
</span>
)}
</Typography>
{!!summary?.producersWithoutProperBpJson.quantity && (
<Typography variant="subtitle1" className={classes.textMargin}>
<TokenToUSD
amount={summary?.producersWithoutProperBpJson.rewards}
tokenPrice={setting?.token_price}
/>{' '}
{t('paidProducersText')}
</Typography>
)}
</CardContent>
</Card>
</div>
<div className={classes.cardHeader}>
<Card className={classes.cardShadow}>
<CardContent className={classes.cards}>
<div className={classes.center}>
<Typography
variant="subtitle1"
className={classes.rewardsColorSchema}
>
<span
className={`${classes.squareRewards} ${classes.lowestRewards}`}
/>
<span className={classes.itemLabel}>{t('lowestRewards')}</span>
</Typography>
<Typography
variant="subtitle1"
className={classes.rewardsColorSchema}
>
<span
className={`${classes.squareRewards} ${classes.highestRewards}`}
/>
<span className={classes.itemLabel}>{t('highestRewards')}</span>
</Typography>
</div>
{setting?.token_price && (
<Typography
variant="subtitle1"
className={`${classes.textMargin} ${classes.center}`}
>
<span className={classes.exchangeRateLabel}>
{`${t('exchangeRate')}: `}{' '}
</span>
<span>
{`1 ${eosConfig.tokenSymbol} = $${formatWithThousandSeparator(
setting.token_price,
4,
)}`}
</span>
</Typography>
)}
</CardContent>
</Card>
</div>
</div>
)
}

export default RewardsDistributionStats
19 changes: 19 additions & 0 deletions webapp/src/routes/RewardsDistribution/TokenToUSD.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { memo } from 'react'

import { formatWithThousandSeparator } from '../../utils'
import { eosConfig } from '../../config'

const TokenToUSD = ({ amount, tokenPrice }) => {
return (
<span>
{`${formatWithThousandSeparator(amount, 2)} ${
eosConfig.tokenSymbol
} / $${formatWithThousandSeparator(
amount * tokenPrice,
2,
)} USD`}
</span>
)
}

export default memo(TokenToUSD)
Loading

0 comments on commit 066a7fe

Please sign in to comment.