diff --git a/api/routes/github/issues.mjs b/api/routes/github/issues.mjs index a3dec788..d4bb1761 100644 --- a/api/routes/github/issues.mjs +++ b/api/routes/github/issues.mjs @@ -8,12 +8,10 @@ router.get('/nano-community', async (req, res) => { const allowed_repos = ['mistakia/nano-community'] if (!allowed_repos.includes(repos)) { - return res - .status(400) - .send({ - error: - 'Invalid repository. Allowed repository is mistakia/nano-community.' - }) + return res.status(400).send({ + error: + 'Invalid repository. Allowed repository is mistakia/nano-community.' + }) } const allowed_states = ['open', 'closed'] diff --git a/src/core/utils/download-csv.js b/src/core/utils/download-csv.js new file mode 100644 index 00000000..2040a6f6 --- /dev/null +++ b/src/core/utils/download-csv.js @@ -0,0 +1,51 @@ +/* global Blob */ + +function convert_to_csv(objArray) { + const array = typeof objArray !== 'object' ? JSON.parse(objArray) : objArray + let str = '' + + for (let i = 0; i < array.length; i++) { + let line = '' + for (const index in array[i]) { + if (line !== '') line += ',' + line += array[i][index] + } + str += line + '\r\n' + } + return str +} + +export function download_csv({ + headers, + data, + file_name = 'nano-community-download' +}) { + const date = new Date() + const timestamp = date.toISOString().replace(/:/g, '-').replace(/\..+/, '') + file_name = `${file_name}-${timestamp}.csv` + if (headers) { + data.unshift(headers) + } + + // Convert Object to JSON + const json_object = JSON.stringify(data) + const csv = convert_to_csv(json_object) + const blob = new Blob([csv], { type: 'text/csvcharset=utf-8' }) + if (navigator.msSaveBlob) { + // IE 10+ + navigator.msSaveBlob(blob, file_name) + } else { + const link = document.createElement('a') + if (link.download !== undefined) { + // feature detection + // Browsers that support HTML5 download attribute + const url = URL.createObjectURL(blob) + link.setAttribute('href', url) + link.setAttribute('download', file_name) + link.style.visibility = 'hidden' + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + } + } +} diff --git a/src/core/utils/download-json.js b/src/core/utils/download-json.js new file mode 100644 index 00000000..a21ddae4 --- /dev/null +++ b/src/core/utils/download-json.js @@ -0,0 +1,24 @@ +export function download_json({ data, file_name = 'nano-community-download' }) { + const date = new Date() + const timestamp = date.toISOString().replace(/:/g, '-').replace(/\..+/, '') + file_name = `${file_name}-${timestamp}.json` + const json_str = JSON.stringify(data) + const blob = new Blob([json_str], { type: 'application/json' }) + if (navigator.msSaveBlob) { + // IE 10+ + navigator.msSaveBlob(blob, file_name) + } else { + const link = document.createElement('a') + if (link.download !== undefined) { + // feature detection + // Browsers that support HTML5 download attribute + const url = URL.createObjectURL(blob) + link.setAttribute('href', url) + link.setAttribute('download', file_name) + link.style.visibility = 'hidden' + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + } + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index edfcebc3..d62094be 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -3,6 +3,8 @@ export { localStorageAdapter } from './local-storage' export { timeago } from './timeago' export { debounce } from './debounce' export { fuzzySearch } from './fuzzy-search' +export { download_csv } from './download-csv' +export { download_json } from './download-json' /* eslint-disable no-extra-semi */ export const groupBy = (xs, key) => diff --git a/src/views/components/ledger-chart-addresses/ledger-chart-addresses.js b/src/views/components/ledger-chart-addresses/ledger-chart-addresses.js index c1371aa0..35bbee8d 100644 --- a/src/views/components/ledger-chart-addresses/ledger-chart-addresses.js +++ b/src/views/components/ledger-chart-addresses/ledger-chart-addresses.js @@ -9,7 +9,9 @@ import { GridComponent } from 'echarts/components' import { CanvasRenderer } from 'echarts/renderers' +import Button from '@mui/material/Button' +import { download_csv, download_json } from '@core/utils' import LedgerChartMetrics from '@components/ledger-chart-metrics' echarts.use([ @@ -20,99 +22,142 @@ echarts.use([ GridComponent ]) -export default class LedgerChartAddresses extends React.Component { - render() { - const { data, isLoading } = this.props - - const option = { - grid: { - containLabel: true - }, - legend: { - show: true, - bottom: 0 - }, - tooltip: { - className: 'echarts-tooltip', - trigger: 'axis' - }, - xAxis: { - type: 'time' - }, - yAxis: { - type: 'log', - name: 'Addresses', - min: 1 +export default function LedgerChartAddresses({ data, isLoading }) { + const option = { + grid: { + containLabel: true + }, + legend: { + show: true, + bottom: 0 + }, + tooltip: { + className: 'echarts-tooltip', + trigger: 'axis' + }, + xAxis: { + type: 'time' + }, + yAxis: { + type: 'log', + name: 'Addresses', + min: 1 + }, + series: [ + { + type: 'line', + showSymbol: false, + name: 'Active', + lineStyle: { + width: 1 + }, + data: data.active_addresses }, - series: [ - { - type: 'line', - showSymbol: false, - name: 'Active', - lineStyle: { - width: 1 - }, - data: data.active_addresses + { + type: 'line', + showSymbol: false, + name: 'Reused', + lineStyle: { + width: 1 }, - { - type: 'line', - showSymbol: false, - name: 'Reused', - lineStyle: { - width: 1 - }, - data: data.reused_addresses + data: data.reused_addresses + }, + { + type: 'line', + showSymbol: false, + name: 'New', + lineStyle: { + width: 1 }, - { - type: 'line', - showSymbol: false, - name: 'New', - lineStyle: { - width: 1 - }, - data: data.open_count - } - ] + data: data.open_count + } + ] + } + + const handle_download_csv = () => { + const download_data = [] + for (let i = 0; i < data.active_addresses.length; i++) { + download_data.push({ + date: data.active_addresses[i][0], + active: data.active_addresses[i][1], + reused: data.reused_addresses[i][1], + new: data.open_count[i][1] + }) } - return ( - <> - -
-
-
- Description -
-
-

- The total number of active, new, and reused addresses used per - day. -

-

- Active shows the number of unique addresses used. New shows the - number of addresses created. Reused shows the number of - addresses used that were created on a previous day. -

-
+ download_csv({ + headers: ['Date', 'Active', 'Reused', 'New'], + data: download_data, + file_name: 'nano-community-ledger-addresses' + }) + } + + const handle_download_json = () => { + const download_data = [] + + for (let i = 0; i < data.active_addresses.length; i++) { + download_data.push({ + date: data.active_addresses[i][0], + active: data.active_addresses[i][1], + reused: data.reused_addresses[i][1], + new: data.open_count[i][1] + }) + } + + download_json({ + data: { + title: 'Nano Community Daily Ledger Address Stats', + timestamp: new Date().toISOString(), + data: download_data + }, + file_name: 'nano-community-ledger-addresses' + }) + } + + return ( + <> + +
+
+
+ Description +
+
+

+ The total number of active, new, and reused addresses used per + day. +

+

+ Active shows the number of unique addresses used. New shows the + number of addresses created. Reused shows the number of addresses + used that were created on a previous day. +

- - + {!isLoading && ( +
+ + +
+ )}
- - ) - } + + +
+ + ) } LedgerChartAddresses.propTypes = { diff --git a/src/views/components/ledger-chart-amounts/ledger-chart-amounts.js b/src/views/components/ledger-chart-amounts/ledger-chart-amounts.js index 061fac9f..979ab297 100644 --- a/src/views/components/ledger-chart-amounts/ledger-chart-amounts.js +++ b/src/views/components/ledger-chart-amounts/ledger-chart-amounts.js @@ -2,102 +2,197 @@ import React from 'react' import PropTypes from 'prop-types' import ReactEChartsCore from 'echarts-for-react/lib/core' import * as echarts from 'echarts/core' -import { LineChart, BarChart, ThemeRiverChart } from 'echarts/charts' +import { LineChart, BarChart } from 'echarts/charts' import { TooltipComponent, LegendComponent, - GridComponent + GridComponent, + DatasetComponent } from 'echarts/components' import { CanvasRenderer } from 'echarts/renderers' +import Button from '@mui/material/Button' + +import { download_csv, download_json } from '@core/utils' echarts.use([ TooltipComponent, - ThemeRiverChart, LegendComponent, LineChart, BarChart, CanvasRenderer, - GridComponent + GridComponent, + DatasetComponent ]) -export default class LedgerChartBlocks extends React.Component { - render() { - const { data, isLoading } = this.props - - const ranges = { - _1000000_count: '>1M', - _100000_count: '100k to 1M', - _10000_count: '10k to 100k', - _1000_count: '1k to 10k', - _100_count: '100 to 1k', - _10_count: '10 to 100', - _1_count: '1 to 10', - _01_count: '0.1 to 1', - _001_count: '0.01 to 0.1', - _0001_count: '0.001 to 0.01', - _00001_count: '0.0001 to 0.001', - _000001_count: '0.00001 to 0.0001', - _000001_below_count: '<0.00001' - } +const color_map = { + // high + _1000000_count: '#ffd700', // Gold + _100000_count: '#f9c74f', // Maize Crayola + _10000_count: '#f4a261', // Sandy Brown + _1000_count: '#e63946', // Red - const option = { - grid: { - containLabel: true, - bottom: 120 - }, - legend: { - show: true, - bottom: 0 + // medium + _100_count: '#0077b6', // Star Command Blue + _10_count: '#023e8a', // Royal Blue Dark + _1_count: '#0096c7', // Pacific Blue + + // low + _01_count: '#6DB65B', // Apple Green + _001_count: '#57A55A', // Medium Sea Green + _0001_count: '#3D8B57', // Jungle Green + _00001_count: '#2C6E49', // Bottle Green + + // micro + _000001_count: '#911eb4', // Purple + _000001_below_count: '#dcbeff' // Lavender Blush +} + +export default function LedgerChartAmounts({ data, isLoading }) { + const ranges = { + _1000000_count: '>1M', + _100000_count: '100k to 1M', + _10000_count: '10k to 100k', + _1000_count: '1k to 10k', + _100_count: '100 to 1k', + _10_count: '10 to 100', + _1_count: '1 to 10', + _01_count: '0.1 to 1', + _001_count: '0.01 to 0.1', + _0001_count: '0.001 to 0.01', + _00001_count: '0.0001 to 0.001', + _000001_count: '0.00001 to 0.0001', + _000001_below_count: '<0.00001' + } + + const series_data = Object.entries(ranges).map(([key, value], index) => { + const color = color_map[key] + + return { + name: value, + type: 'line', + stack: 'total', + color, + lineStyle: { + width: 0 }, - tooltip: { - className: 'echarts-tooltip', - trigger: 'axis' + showSymbol: false, + areaStyle: { + color }, - xAxis: { - type: 'time' + emphasis: { + focus: 'series' }, - yAxis: { + data: data[key].map((item) => [item[0], item[1]]) + } + }) + + const option = { + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross', + label: { + backgroundColor: '#6a7985' + } + } + }, + legend: { + bottom: 0 + }, + grid: { + left: '3%', + right: '4%', + containLabel: true + }, + xAxis: [ + { + type: 'time', + boundaryGap: false + } + ], + yAxis: [ + { type: 'log', - name: 'Blocks', - min: 1 - }, - series: Object.entries(ranges).map((item) => ({ - type: 'line', - name: item[1], - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data[item[0]] - })) + min: 1, + max: 5000000 + } + ], + series: series_data + } + + const handle_download_csv = () => { + const download_data = [] + Object.entries(ranges).forEach(([key, value]) => { + data[key].forEach((item) => { + download_data.push({ + range: value, + date: item[0], + count: item[1] + }) + }) + }) + + download_csv({ + headers: ['Range', 'Date', 'Count'], + data: download_data, + file_name: 'nano-community-ledger-daily-block-counts-by-amount-range' + }) + } + + const handle_download_json = () => { + const download_data = { + title: 'Nano Community Ledger Daily Block Counts by Amount Range', + data: {} } - return ( - <> - -
-
-
- Description -
-
- The number of confirmed send-type blocks per day where the amount - in the block is in a given range (in Nano) -
+ Object.entries(ranges).forEach(([key, value]) => { + download_data.data[value] = data[key].map((item) => ({ + date: item[0], + count: item[1] + })) + }) + + download_json({ + data: download_data, + file_name: 'nano-community-ledger-daily-block-counts-by-amount-range' + }) + } + + return ( + <> + +
+
+
+ Description
+
+ The number of confirmed send-type blocks per day where the amount in + the block is in a given range (in Nano) +
+ {!isLoading && ( +
+ + +
+ )}
- - ) - } +
+ + ) } -LedgerChartBlocks.propTypes = { +LedgerChartAmounts.propTypes = { data: PropTypes.object, isLoading: PropTypes.bool } diff --git a/src/views/components/ledger-chart-blocks/ledger-chart-blocks.js b/src/views/components/ledger-chart-blocks/ledger-chart-blocks.js index f1a858a1..b56fd5c2 100644 --- a/src/views/components/ledger-chart-blocks/ledger-chart-blocks.js +++ b/src/views/components/ledger-chart-blocks/ledger-chart-blocks.js @@ -1,5 +1,6 @@ import React from 'react' import PropTypes from 'prop-types' +import Button from '@mui/material/Button' import ReactEChartsCore from 'echarts-for-react/lib/core' import * as echarts from 'echarts/core' import { LineChart } from 'echarts/charts' @@ -11,6 +12,7 @@ import { import { CanvasRenderer } from 'echarts/renderers' import LedgerChartMetrics from '@components/ledger-chart-metrics' +import { download_csv, download_json } from '@core/utils' echarts.use([ TooltipComponent, @@ -20,126 +22,176 @@ echarts.use([ GridComponent ]) -export default class LedgerChartBlocks extends React.Component { - render() { - const { data, isLoading } = this.props - - const option = { - grid: { - containLabel: true - }, - legend: { - show: true, - bottom: 0 - }, - tooltip: { - className: 'echarts-tooltip', - trigger: 'axis' - }, - xAxis: { - type: 'time' - }, - yAxis: { - type: 'log', - name: 'Blocks', - min: 1 +export default function LedgerChartBlocks({ data, isLoading }) { + const option = { + grid: { + containLabel: true + }, + legend: { + show: true, + bottom: 0 + }, + tooltip: { + className: 'echarts-tooltip', + trigger: 'axis' + }, + xAxis: { + type: 'time' + }, + yAxis: { + type: 'log', + name: 'Blocks', + min: 1 + }, + series: [ + { + type: 'line', + name: 'Total', + showSymbol: false, + lineStyle: { + width: 1 + }, + data: data.blocks }, - series: [ - { - type: 'line', - name: 'Total', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.blocks + { + type: 'line', + name: 'Send', + showSymbol: false, + lineStyle: { + width: 1 }, - { - type: 'line', - name: 'Send', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.send_count + data: data.send_count + }, + { + type: 'line', + name: 'Change', + showSymbol: false, + lineStyle: { + width: 1 }, - { - type: 'line', - name: 'Change', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.change_count + data: data.change_count + }, + { + type: 'line', + name: 'Receive', + showSymbol: false, + lineStyle: { + width: 1 }, - { - type: 'line', - name: 'Receive', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.open_count + data: data.open_count + }, + { + type: 'line', + name: 'Open', + showSymbol: false, + lineStyle: { + width: 1 }, - { - type: 'line', - name: 'Open', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.receive_count - } - ] + data: data.receive_count + } + ] + } + + const handle_download_csv = () => { + const download_data = [] + for (let i = 0; i < data.blocks.length; i++) { + download_data.push({ + date: data.blocks[i][0], + blocks: data.blocks[i][1], + send: data.send_count[i][1], + change: data.change_count[i][1], + receive: data.receive_count[i][1], + open: data.open_count[i][1] + }) } - return ( - <> - -
-
-
- Description -
-
- The number of confirmed blocks (by type) per day. -
+ download_csv({ + headers: ['Date', 'Blocks', 'Send', 'Change', 'Receive', 'Open'], + data: download_data, + file_name: 'nano-community-ledger-blocks' + }) + } + + const handle_download_json = () => { + const download_data = [] + + for (let i = 0; i < data.blocks.length; i++) { + download_data.push({ + date: data.blocks[i][0], + blocks: data.blocks[i][1], + send: data.send_count[i][1], + change: data.change_count[i][1], + receive: data.receive_count[i][1], + open: data.open_count[i][1] + }) + } + + download_json({ + data: { + title: 'Nano Community Daily Ledger Block Counts', + timestamp: new Date().toISOString(), + data: download_data + }, + file_name: 'nano-community-ledger-blocks' + }) + } + + return ( + <> + +
+
+
+ Description +
+
+ The number of confirmed blocks (by type) per day.
- - - - - + {!isLoading && ( +
+ + +
+ )}
- - ) - } + + + + + +
+ + ) } LedgerChartBlocks.propTypes = { diff --git a/src/views/components/ledger-chart-metrics/ledger-chart-metrics.js b/src/views/components/ledger-chart-metrics/ledger-chart-metrics.js index b00a59ee..6f4b843a 100644 --- a/src/views/components/ledger-chart-metrics/ledger-chart-metrics.js +++ b/src/views/components/ledger-chart-metrics/ledger-chart-metrics.js @@ -5,57 +5,58 @@ import BigNumber from 'bignumber.js' import './ledger-chart-metrics.styl' -export default class LedgerChartMetrics extends React.Component { - render() { - const { data, label, show_total = false } = this.props - const values = data.map((d) => d[1]) - const max = values.length ? Math.max(...values) : null - const min = values.length ? Math.min(...values.filter(Boolean)) : null +export default function LedgerChartMetrics({ + data, + label, + show_total = false +}) { + const values = data.map((d) => d[1]) + const max = values.length ? Math.max(...values) : null + const min = values.length ? Math.min(...values.filter(Boolean)) : null - const maxIdx = values.indexOf(max) - const minIdx = values.indexOf(min) - const maxTimestamp = maxIdx !== -1 ? data[maxIdx][0] : null - const minTimestamp = minIdx !== -1 ? data[minIdx][0] : null + const maxIdx = values.indexOf(max) + const minIdx = values.indexOf(min) + const maxTimestamp = maxIdx !== -1 ? data[maxIdx][0] : null + const minTimestamp = minIdx !== -1 ? data[minIdx][0] : null - const total = values.reduce((acc, val) => acc.plus(val || 0), BigNumber(0)) + const total = values.reduce((acc, val) => acc.plus(val || 0), BigNumber(0)) - return ( -
-
- {label} + return ( +
+
+ {label} +
+
+
+
Min
+
+ {min ? BigNumber(min).toFormat(0) : '-'} +
+
+ {minTimestamp ? dayjs(minTimestamp).format('MMM D, YYYY') : '-'} +
-
-
-
Min
-
- {min ? BigNumber(min).toFormat(0) : '-'} -
-
- {minTimestamp ? dayjs(minTimestamp).format('MMM D, YYYY') : '-'} -
+
+
Max
+
+ {max ? BigNumber(max).toFormat(0) : '-'} +
+
+ {maxTimestamp ? dayjs(maxTimestamp).format('MMM D, YYYY') : '-'}
+
+ {show_total && (
-
Max
+
Total
- {max ? BigNumber(max).toFormat(0) : '-'} -
-
- {maxTimestamp ? dayjs(maxTimestamp).format('MMM D, YYYY') : '-'} + {total ? BigNumber(total).toFormat(0) : '-'}
+
- {show_total && ( -
-
Total
-
- {total ? BigNumber(total).toFormat(0) : '-'} -
-
-
- )} -
+ )}
- ) - } +
+ ) } LedgerChartMetrics.propTypes = { diff --git a/src/views/components/ledger-chart-usd-transferred/ledger-chart-usd-transferred.js b/src/views/components/ledger-chart-usd-transferred/ledger-chart-usd-transferred.js index 30d0a799..4a509df3 100644 --- a/src/views/components/ledger-chart-usd-transferred/ledger-chart-usd-transferred.js +++ b/src/views/components/ledger-chart-usd-transferred/ledger-chart-usd-transferred.js @@ -10,8 +10,10 @@ import { GridComponent } from 'echarts/components' import { CanvasRenderer } from 'echarts/renderers' +import Button from '@mui/material/Button' import LedgerChartMetrics from '@components/ledger-chart-metrics' +import { download_csv, download_json } from '@core/utils' echarts.use([ TooltipComponent, @@ -21,92 +23,127 @@ echarts.use([ GridComponent ]) -export default class LedgerUSDTransferred extends React.Component { - render() { - const { data, isLoading } = this.props +export default function LedgerUSDTransferred({ data, isLoading }) { + const span_style = + 'float:right;margin-left:20px;font-size:14px;color:#666;font-weight:900' + const option = { + grid: { + containLabel: true + }, + legend: { + show: true, + bottom: 0 + }, + tooltip: { + className: 'echarts-tooltip', + trigger: 'axis', + formatter: (series) => { + const values = series.map( + (s) => + `${s.marker} ${ + s.seriesName + } $${BigNumber(s.data[1]).toFormat( + 2 + )}` + ) - const spanStyle = - 'float:right;margin-left:20px;font-size:14px;color:#666;font-weight:900' - const option = { - grid: { - containLabel: true - }, - legend: { - show: true, - bottom: 0 - }, - tooltip: { - className: 'echarts-tooltip', - trigger: 'axis', - formatter: (series) => { - const values = series.map( - (s) => - `${s.marker} ${ - s.seriesName - } $${BigNumber(s.data[1]).toFormat( - 2 - )}` - ) + values.unshift(series[0].axisValueLabel) - values.unshift(series[0].axisValueLabel) + return values.join('
') + } + }, + xAxis: { + type: 'time' + }, + yAxis: { + type: 'value', + name: 'Nano', + axisLabel: { + formatter: (value) => `$${value}` + } + }, + series: [ + { + type: 'line', + name: 'USD Transferred', + showSymbol: false, + lineStyle: { + width: 1 + }, + data: data.total_usd_send_value + } + ] + } - return values.join('
') - } - }, - xAxis: { - type: 'time' - }, - yAxis: { - type: 'value', - name: 'Nano', - axisLabel: { - formatter: (value) => `$${value}` - } + const handle_download_csv = () => { + const download_data = data.total_usd_send_value.map((d) => ({ + date: d[0], + value: d[1] + })) + + download_csv({ + headers: ['Date', 'USD Transferred'], + data: download_data, + file_name: 'nano-community-ledger-daily-usd-transferred' + }) + } + + const handle_download_json = () => { + const download_data = data.total_usd_send_value.map((d) => ({ + date: d[0], + value: d[1] + })) + + download_json({ + data: { + title: 'Nano Community Ledger Daily USD Transferred', + timestamp: new Date().toISOString(), + data: download_data }, - series: [ - { - type: 'line', - name: 'USD Transferred', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.total_usd_send_value - } - ] - } + file_name: 'nano-community-ledger-daily-usd-transferred' + }) + } - return ( - <> - -
-
-
- Description -
-
-

The total amount of value transferred (in USD) per day.

-

- Based on the daily closing price of Nano/USD and the total - amount of Nano transferred that day. -

-
+ return ( + <> + +
+
+
+ Description
- [d[0], d[1]])} - label='USD Transferred Stats' - show_total - /> +
+

The total amount of value transferred (in USD) per day.

+

+ Based on the daily closing price of Nano/USD and the total amount + of Nano transferred that day. +

+
+ {!isLoading && ( +
+ + +
+ )}
- - ) - } + [d[0], d[1]])} + label='USD Transferred Stats' + show_total + /> +
+ + ) } LedgerUSDTransferred.propTypes = { diff --git a/src/views/components/ledger-chart-volume/ledger-chart-volume.js b/src/views/components/ledger-chart-volume/ledger-chart-volume.js index 6fef630f..c079d7e6 100644 --- a/src/views/components/ledger-chart-volume/ledger-chart-volume.js +++ b/src/views/components/ledger-chart-volume/ledger-chart-volume.js @@ -10,8 +10,10 @@ import { GridComponent } from 'echarts/components' import { CanvasRenderer } from 'echarts/renderers' +import Button from '@mui/material/Button' import LedgerChartMetrics from '@components/ledger-chart-metrics' +import { download_csv, download_json } from '@core/utils' echarts.use([ TooltipComponent, @@ -21,112 +23,155 @@ echarts.use([ GridComponent ]) -export default class LedgerChartBlocks extends React.Component { - render() { - const { data, isLoading } = this.props +export default function LedgerChartVolume({ data, isLoading }) { + const span_style = + 'float:right;margin-left:20px;font-size:14px;color:#666;font-weight:900' + const option = { + grid: { + containLabel: true + }, + legend: { + show: true, + bottom: 0 + }, + tooltip: { + className: 'echarts-tooltip', + trigger: 'axis', + formatter: (series) => { + const values = series.map( + (s) => + `${s.marker} ${ + s.seriesName + } ${BigNumber(s.data[1]) + .shiftedBy(-30) + .toFormat(0)}` + ) - const spanStyle = - 'float:right;margin-left:20px;font-size:14px;color:#666;font-weight:900' - const option = { - grid: { - containLabel: true - }, - legend: { - show: true, - bottom: 0 + values.unshift(series[0].axisValueLabel) + + return values.join('
') + } + }, + xAxis: { + type: 'time' + }, + yAxis: { + type: 'value', + name: 'Nano', + axisLabel: { + formatter: (value) => `${BigNumber(value).shiftedBy(-30).toFormat(0)}` + } + }, + series: [ + { + type: 'line', + name: 'Send', + showSymbol: false, + lineStyle: { + width: 1 + }, + data: data.send_volume }, - tooltip: { - className: 'echarts-tooltip', - trigger: 'axis', - formatter: (series) => { - const values = series.map( - (s) => - `${s.marker} ${ - s.seriesName - } ${BigNumber(s.data[1]) - .shiftedBy(-30) - .toFormat(0)}` - ) + { + type: 'line', + name: 'Change', + showSymbol: false, + lineStyle: { + width: 1 + }, + data: data.change_volume + } + ] + } - values.unshift(series[0].axisValueLabel) + const handle_download_csv = () => { + const download_data = [] + data.send_volume.forEach((item, index) => { + download_data.push({ + date: item[0], + send_volume: item[1], + change_volume: data.change_volume[index][1] + }) + }) - return values.join('
') - } - }, - xAxis: { - type: 'time' - }, - yAxis: { - type: 'value', - name: 'Nano', - axisLabel: { - formatter: (value) => `${BigNumber(value).shiftedBy(-30).toFormat(0)}` - } + download_csv({ + headers: ['Date', 'Send Volume', 'Change Volume'], + data: download_data, + file_name: 'nano-community-ledger-daily-volume-stats' + }) + } + + const handle_download_json = () => { + const download_data = [] + data.send_volume.forEach((item, index) => { + download_data.push({ + date: item[0], + send_volume: item[1], + change_volume: data.change_volume[index][1] + }) + }) + + download_json({ + data: { + title: 'Nano Community Ledger Daily Volume Stats', + timestamp: new Date().toISOString(), + data: download_data }, - series: [ - { - type: 'line', - name: 'Send', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.send_volume - }, - { - type: 'line', - name: 'Change', - showSymbol: false, - lineStyle: { - width: 1 - }, - data: data.change_volume - } - ] - } + file_name: 'nano-community-ledger-daily-volume-stats' + }) + } - return ( - <> - -
-
-
- Description -
-
- The total amount sent (in Nano) and total amount of voting weight - changed per day. -
+ return ( + <> + +
+
+
+ Description
- [ - d[0], - BigNumber(d[1]).shiftedBy(-30).toNumber() - ])} - label='Send Stats' - show_total - /> - [ - d[0], - BigNumber(d[1]).shiftedBy(-30).toNumber() - ])} - label='Change Stats' - show_total - /> +
+ The total amount sent (in Nano) and total amount of voting weight + changed per day. +
+ {!isLoading && ( +
+ + +
+ )}
- - ) - } + [ + d[0], + BigNumber(d[1]).shiftedBy(-30).toNumber() + ])} + label='Send Stats' + show_total + /> + [ + d[0], + BigNumber(d[1]).shiftedBy(-30).toNumber() + ])} + label='Change Stats' + show_total + /> +
+ + ) } -LedgerChartBlocks.propTypes = { +LedgerChartVolume.propTypes = { data: PropTypes.object, isLoading: PropTypes.bool } diff --git a/src/views/pages/ledger/ledger.styl b/src/views/pages/ledger/ledger.styl index f7db1e98..ecbea07e 100644 --- a/src/views/pages/ledger/ledger.styl +++ b/src/views/pages/ledger/ledger.styl @@ -34,6 +34,14 @@ &.description font-size 14px line-height 18px + + &.download + margin 16px 0 + display flex + justify-content flex-start + + button:not(:first-child) + margin-left 16px p margin-bottom 16px