Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add token statistics #277

Merged
merged 3 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- Migrate orderbook to gecko API #255
- Add 24 hr changes to validator list view #263
- Add chain params to network dropdown #144
- Add token statistics to network dropdown #258

## 2.5.0

Expand Down
2 changes: 2 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
Params,
Proposal,
Proposals,
TokenStats,
Tx,
Txs,
Upgrades,
Expand Down Expand Up @@ -67,6 +68,7 @@ const App = () => {
<Route path="/nfts/:addr" component={Nfts} />
<Route path="/proposal/:proposalId" component={Proposal} />
<Route path="/proposals" component={Proposals} />
<Route path="/network/token-stats" component={TokenStats} />
<Route path="/network/upgrades" component={Upgrades} />
<Route path="/network/params" component={Params} />
<Route path="/tx/:txHash" component={Tx} />
Expand Down
1 change: 1 addition & 0 deletions src/Components/Navigation/Components/NavStandard.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const DropdownUL = styled.ul`
position: absolute;
max-height: 0;
overflow: hidden;
white-space: nowrap;
transition-delay: 300ms;
flex-direction: column;
list-style: none;
Expand Down
16 changes: 12 additions & 4 deletions src/Components/Table/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ const TableData = styled.td`
display: ${({ copy }) => (copy ? 'flex' : '')};
align-items: ${({ copy }) => (copy ? 'center' : '')};
border: none;
text-decoration: ${({ skipped }) => skipped && 'line-through'};
font-style: ${({ skipped }) => skipped && 'italic'};
text-decoration: ${({ skipped, scheduled }) => skipped && !scheduled && 'line-through'};
font-style: ${({ skipped, scheduled }) => (skipped || scheduled) && 'italic'};
color: ${({ color }) => color && color};
`;
const Pagination = styled(BasePagination)`
Expand Down Expand Up @@ -186,10 +186,12 @@ const Table = ({

const {
link = false,
externalLink = '',
value = '--',
hover = false,
icon,
skipped = false,
scheduled = false,
iconColor = theme.FONT_LINK,
color = '',
size = '1.4rem',
Expand All @@ -209,7 +211,8 @@ const Table = ({
<TableData
title={hover || value}
key={displayName}
skipped={skipped}
skipped={skipped && !scheduled}
scheduled={scheduled}
copy={copy || (!isEmpty(blockImage) && displayName === 'Moniker')}
center={center}
color={color}
Expand All @@ -236,7 +239,12 @@ const Table = ({
</Link>
) : (
<>
{value}
{externalLink && (
<a href={externalLink} target="_blank" rel="noreferrer">
{value}
</a>
)}
{!externalLink && value}
{icon && <Sprite icon={icon} size={size} color={iconColor} />}
{copy && <CopyValue value={raw} title={`Copy ${hover}`} />}
</>
Expand Down
32 changes: 32 additions & 0 deletions src/Pages/TokenStats/Components/AssetsDist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useEffect } from 'react';
import { Table } from 'Components';
import { useAssets } from 'redux/hooks';

const AssetsDist = () => {
const {
assetsDist: tableData,
assetsDistLoading: tableLoading,
getAssetsDist: getTableData,
} = useAssets();

useEffect(() => {
getTableData();
}, [getTableData]);

const tableHeaders = [
{ displayName: 'Range', dataName: 'range' },
{ displayName: 'Amount', dataName: 'amountHash' },
{ displayName: 'Percent', dataName: 'percentTotal' },
];

return (
<Table
tableHeaders={tableHeaders}
tableData={tableData}
isLoading={tableLoading}
title="Asset Distribution"
/>
);
};

export default AssetsDist;
151 changes: 151 additions & 0 deletions src/Pages/TokenStats/Components/TokenStatsChart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import React, { useState, useRef, useEffect, useCallback } from 'react';
import styled, { useTheme } from 'styled-components';
import * as echarts from 'echarts';
import { useNetwork } from 'redux/hooks';
import { Content, Header } from 'Components';
import { isEmpty, formatDenom } from 'utils';

const StyledChart = styled.div`
height: 600px;
width: 100%;
`;
const StyledMessage = styled.div`
width: 100%;
margin-top: 20px;
`;

// Chart constants
const chartData = {
tooltip: {
trigger: 'item',
},
legend: {
top: '5%',
left: 'center',
},
series: [
{
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderWidth: 2,
},
label: {
show: false,
position: 'center',
},
emphasis: {
label: {
show: true,
fontSize: '20',
fontWeight: 'bold',
},
},
labelLine: {
show: false,
},
},
],
};

// Format token data to value:, name: array
const getDataArray = data => [
{
value: (parseFloat(data.circulation.amount) / 1e9).toFixed(0),
name: 'Circulation',
},
{
value: (parseFloat(data.communityPool.amount) / 1e9).toFixed(0),
name: 'Community Pool',
},
{
value: (parseFloat(data.bonded.amount) / 1e9).toFixed(0),
name: 'Bonded',
},
{
value: (
(parseFloat(data.currentSupply.amount) -
(parseFloat(data.circulation.amount) +
parseFloat(data.communityPool.amount) +
parseFloat(data.bonded.amount))) /
1e9
).toFixed(0),
name: 'Remaining Total',
},
];

const TokenStatsChart = () => {
const [chart, setChart] = useState(null);
const chartElementRef = useRef(null);
const theme = useTheme();
const { networkTokenStats, getNetworkTokenStats } = useNetwork();

// Build dynamic chart data
const buildChartData = useCallback(
(data, totalHash) => {
// Build dynamic chart items
chartData.color = [
theme.CHART_PIE_M,
theme.CHART_PIE_L,
theme.CHART_PIE_N,
theme.CHART_PIE_C,
];
chartData.series[0].data = data;
chartData.series[0].itemStyle.borderColor = theme.BACKGROUND_LIGHT;
chartData.legend.textStyle = {
color: theme.FONT_PRIMARY,
};
chartData.tooltip.formatter = params => {
const percent = (params.data.value / totalHash) * 100;
return `${params.data.name} Hash<br />
Amount: ${formatDenom(params.data.value, 'hash', { decimal: 0 })}<br />
Percent: ${percent < 0.01 ? percent.toFixed(5) : percent.toFixed(2)}%`;
};
},
[theme]
);

// Get token statistics
useEffect(() => {
getNetworkTokenStats();
}, [getNetworkTokenStats]);

// Build Chart with data
useEffect(() => {
if (!isEmpty(networkTokenStats)) {
// Calculate total Hash
const totalHash = parseFloat(networkTokenStats.currentSupply.amount) / (1e9).toFixed(0);
// On load, chartElementRef should get set and we can update the chart to be an echart
// first try to get the initialized instance
let echart = echarts.getInstanceByDom(chartElementRef.current);
// if it isn't initialized then init
if (!echart) echart = echarts.init(chartElementRef.current);
window.allCharts.push(echart);
setChart(echart);
// Update the chart with the data
buildChartData(getDataArray(networkTokenStats), totalHash);
chart && chart.setOption(chartData);
}
}, [setChart, chart, networkTokenStats, buildChartData]);

const totalHash =
!isEmpty(networkTokenStats) &&
formatDenom(networkTokenStats.currentSupply.amount, networkTokenStats.currentSupply.denom, {
decimal: 0,
});

return !isEmpty(networkTokenStats) ? (
<>
<Header title="Token Statistics" value={`Total: ${totalHash}`} />
<StyledChart ref={chartElementRef} />
</>
) : (
<Content>
<StyledMessage>No token statistics available. Refresh to retry</StyledMessage>
</Content>
);
};

export default TokenStatsChart;
2 changes: 2 additions & 0 deletions src/Pages/TokenStats/Components/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as TokenStatsChart } from './TokenStatsChart';
export { default as AssetsDist } from './AssetsDist';
36 changes: 36 additions & 0 deletions src/Pages/TokenStats/TokenStats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React, { useEffect } from 'react';
import { Wrapper } from 'Components';
import { TokenStatsChart, AssetsDist } from './Components';

const handleResize = chartArray => {
chartArray.forEach(chart => {
chart.resize();
});
};

const TokenStats = () => {
useEffect(() => {
// Resize all charts in the dashboard component by building window.allCharts array.
// Note that each component with echarts pushes to window.allCharts, defined here.
window.allCharts = [];
window.onresize = () => {
handleResize(window.allCharts);
};

return () => {
// Delete the allCharts array
window.allCharts.length = 0;
// Remove the event listener
window.removeEventListener('resize', handleResize(window.allCharts));
};
});

return (
<Wrapper>
<TokenStatsChart />
<AssetsDist />
</Wrapper>
);
};

export default TokenStats;
1 change: 1 addition & 0 deletions src/Pages/TokenStats/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './TokenStats';
2 changes: 1 addition & 1 deletion src/Pages/Upgrades/Components/UpgradesList.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const Upgrades = () => {
}, [getTableData]);

// Only display skipped notes if something is skipped
const skipped = tableData.find(v => v.skipped) ? 'skipped' : '';
const skipped = tableData.find(v => v.skipped && !v.scheduled) ? 'skipped' : '';

// Table header values in order
const tableHeaders = [
Expand Down
1 change: 1 addition & 0 deletions src/Pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export { default as NoMatch404 } from './NoMatch404';
export { default as Params } from './Params';
export { default as Proposal } from './Proposal';
export { default as Proposals } from './Proposals';
export { default as TokenStats } from './TokenStats';
export { default as Tx } from './Tx';
export { default as Txs } from './Txs';
export { default as Upgrades } from './Upgrades';
Expand Down
4 changes: 4 additions & 0 deletions src/consts/links.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export const Links = {
url: Path.PARAMS_URL,
title: 'Params',
},
token_stats: {
url: Path.TOKEN_STATS_URL,
title: 'Token Statistics',
},
},
},
};
1 change: 1 addition & 0 deletions src/consts/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export const Path = {
TRANSFER_URL: '/txs',
// Network dropdown menu items
PARAMS_URL: '/network/params',
TOKEN_STATS_URL: '/network/token-stats',
UPGRADES_URL: '/network/upgrades',
};
3 changes: 2 additions & 1 deletion src/consts/urls.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const ACCOUNT_INFO_URL = `${BASE_URL}/accounts`;
// -- Assets
export const ASSET_DETAIL_URL = `${BASE_URL}/assets`;
export const ASSETS_LIST_URL = `${BASE_URL}/assets/all`;
export const ASSETS_DIST_URL = `${BASE_URL}/assets/distribution`;
// -- Blocks
export const BLOCK_HEIGHT_URL = `${BASE_URL}/blocks/height`;
export const BLOCK_INFO_URL = `${BASE_URL}/blocks/height`;
Expand Down Expand Up @@ -67,7 +68,7 @@ export const NETWORK_GAS_STATS_URL = `${BASE_URL}/gas/stats`;
export const NETWORK_GAS_VOL_URL = `${BASE_URL}/gas/volume`;
export const NETWORK_PARAMS_URL = `${BASE_URL}/params`;
export const NETWORK_SPOTLIGHT_URL = `${BASE_URL}/spotlight`;
export const NETWORK_TOKEN_URL = `${BASE_URL}/token/stats`;
export const NETWORK_TOKEN_STATS_URL = `${BASE_URL}/token/stats`;
// -- Txs
export const TX_INFO_URL = `${BASE_URL}/txs`;
export const TXS_RECENT_URL = `${BASE_URL}/txs/recent`;
Expand Down
Loading