From 26025874dc942196a79ca205b65b6e385aad7260 Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Mon, 16 Jan 2023 14:53:28 -0600 Subject: [PATCH 01/16] perf(webapp): componetization pieChart --- .../PieChartReport/custom-pieChart.js | 142 ++++++++++++++++++ webapp/src/components/PieChartReport/index.js | 126 ++-------------- webapp/src/gql/eden-expense.gql.js | 6 +- 3 files changed, 156 insertions(+), 118 deletions(-) create mode 100644 webapp/src/components/PieChartReport/custom-pieChart.js diff --git a/webapp/src/components/PieChartReport/custom-pieChart.js b/webapp/src/components/PieChartReport/custom-pieChart.js new file mode 100644 index 00000000..b14e70be --- /dev/null +++ b/webapp/src/components/PieChartReport/custom-pieChart.js @@ -0,0 +1,142 @@ +import React, { useEffect, useState, memo } from 'react' +import PropTypes from 'prop-types' +import { PieChart, Pie, Sector, ResponsiveContainer, Cell } from 'recharts' + +import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' + +const capitalizeFirstLetter = string => { + const newString = string.replace(/\s/g, '') + return newString.charAt(0).toUpperCase() + newString.slice(1) +} + +const renderActiveShape = props => { + const { + cx, + cy, + startAngle, + endAngle, + payload, + percent, + value, + coin, + innerRadius, + outerRadius + } = props + + return ( + + + {payload.name + ? capitalizeFirstLetter(payload.name) + : capitalizeFirstLetter(payload.category)} + + + {formatWithThousandSeparator(value, 2)} {coin} + + + {`${(percent * 100).toFixed(2)}%`} + + + + ) +} + +const CustomPieChart = ({ + data, + coinType, + typeData, + pieRef, + innerRadius, + outerRadius +}) => { + const [activeIndex, setActiveIndex] = useState(0) + const [category, setCategory] = useState('') + + const onPieEnter = (_, index) => { + setActiveIndex(index) + } + + const newData = data.map(info => { + return { ...info, coin: coinType } + }) + + useEffect(() => { + if (typeData === 'income') { + setCategory('CLAIMED') + } else { + setCategory('CATEGORIZED') + } + }, [typeData]) + + return ( + + + + {data.map(data => ( + + ))} + + + + ) +} + +CustomPieChart.propTypes = { + data: PropTypes.array, + coinType: PropTypes.string, + typeData: PropTypes.string, + pieRef: PropTypes.object, + innerRadius: PropTypes.number, + outerRadius: PropTypes.number +} + +CustomPieChart.defaultProps = { + innerRadius: 60, + outerRadius: 150 +} + +export default memo(CustomPieChart) diff --git a/webapp/src/components/PieChartReport/index.js b/webapp/src/components/PieChartReport/index.js index b95dde26..8b2cd012 100644 --- a/webapp/src/components/PieChartReport/index.js +++ b/webapp/src/components/PieChartReport/index.js @@ -1,7 +1,6 @@ import React, { memo, useState, useCallback, useEffect } from 'react' import PropTypes from 'prop-types' import FileSaver from 'file-saver' -import { PieChart, Pie, Sector, ResponsiveContainer, Cell } from 'recharts' import { useCurrentPng } from 'recharts-to-png' import { useTranslation } from 'react-i18next' import { makeStyles } from '@mui/styles' @@ -16,106 +15,27 @@ import { import DownloadOutlined from '@mui/icons-material/DownloadOutlined' import TooltipDownload from '@mui/material/Tooltip' -import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' - import styles from './styles' +import CustomPieChart from './custom-pieChart' const useStyles = makeStyles(styles) -const capitalizeFirstLetter = string => { - const newString = string.replace(/\s/g, '') - return newString.charAt(0).toUpperCase() + newString.slice(1) -} - -const renderActiveShape = props => { - const { - cx, - cy, - startAngle, - endAngle, - payload, - percent, - value, - coin, - innerRadius, - outerRadius - } = props - - return ( - - - {payload.name - ? capitalizeFirstLetter(payload.name) - : capitalizeFirstLetter(payload.category)} - - - {formatWithThousandSeparator(value, 2)} {coin} - - - {`${(percent * 100).toFixed(2)}%`} - - - - ) -} - const PieChartReport = ({ data, keyTranslation, pathTranslation, - typeData, - innerRadius = 60, - outerRadius = 150 + typeData }) => { const classes = useStyles() - const [activeIndex, setActiveIndex] = useState(0) const [getPiePng, { ref: pieRef }] = useCurrentPng() const { t } = useTranslation() const [selectedUSD, setSelected] = useState(false) const [coinType, setCoinType] = useState('EOS') - const [category, setCategory] = useState('') const handleChange = event => { setSelected(event.target.checked) } - const newData = data.map(info => { - return { ...info, coin: coinType } - }) - - const onPieEnter = (_, index) => { - setActiveIndex(index) - } - const handlePieDownload = useCallback(async () => { const png = await getPiePng() @@ -124,14 +44,6 @@ const PieChartReport = ({ } }, [getPiePng]) - useEffect(() => { - if (typeData === 'income') { - setCategory('CLAIMED') - } else { - setCategory('CATEGORIZED') - } - }, [typeData]) - useEffect(() => { selectedUSD ? setCoinType('USD') : setCoinType('EOS') }, [selectedUSD]) @@ -160,30 +72,12 @@ const PieChartReport = ({ {typeData === 'expense' && } - - - - {data.map(data => ( - - ))} - - - + ) } @@ -192,9 +86,7 @@ PieChartReport.propTypes = { data: PropTypes.array, keyTranslation: PropTypes.string, pathTranslation: PropTypes.string, - typeData: PropTypes.string, - innerRadius: PropTypes.number, - outerRadius: PropTypes.number + typeData: PropTypes.string } export default memo(PieChartReport) diff --git a/webapp/src/gql/eden-expense.gql.js b/webapp/src/gql/eden-expense.gql.js index 529e10a7..4d0bebcb 100644 --- a/webapp/src/gql/eden-expense.gql.js +++ b/webapp/src/gql/eden-expense.gql.js @@ -43,7 +43,11 @@ export const GET_DELEGATES_EXPENSE_BY_ELECTION = gql` export const GET_TOTAL_EXPENSE_BY_CATEGORY_AND_ELECTION = gql` query getTotalClaimedAndUnclaimedByElection($election: Int) { total_by_category_and_election( - where: { election: { _eq: $election }, type: { _eq: "expense" } } + where: { + election: { _eq: $election } + category: { _neq: "uncategorized" } + type: { _eq: "expense" } + } ) { amount category From 4775ade9d15901c0a12a071c37c6576086071fa9 Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Mon, 16 Jan 2023 15:32:57 -0600 Subject: [PATCH 02/16] perf(webapp): componetization barChart --- .../BarChartReport/custom-barchart.js | 182 ++++++++++++++++++ webapp/src/components/BarChartReport/index.js | 173 ++--------------- 2 files changed, 195 insertions(+), 160 deletions(-) create mode 100644 webapp/src/components/BarChartReport/custom-barchart.js diff --git a/webapp/src/components/BarChartReport/custom-barchart.js b/webapp/src/components/BarChartReport/custom-barchart.js new file mode 100644 index 00000000..ba87963a --- /dev/null +++ b/webapp/src/components/BarChartReport/custom-barchart.js @@ -0,0 +1,182 @@ +import React, { memo, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' +import PropTypes from 'prop-types' +import { Box } from '@mui/system' +import { + ComposedChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, + Cell +} from 'recharts' + +import styles from './styles' +import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' + +const useStyles = makeStyles(styles) + +const RenderChartLegend = ({ data }) => { + const classes = useStyles() + const { t } = useTranslation() + + return ( +
+ + + {t(`un${data.toLocaleLowerCase()}`, { ns: 'generalForm' })} + + + + {t(`${data.toLocaleLowerCase()}`, { ns: 'generalForm' })} + + + + {t('total', { ns: 'generalForm' })} + +
+ ) +} + +RenderChartLegend.propTypes = { + data: PropTypes.string +} + +const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { + const { t } = useTranslation() + label = label + '' + const arrayLabel = label.split(' ') + + return ( +
+ + {`${t(arrayLabel[0].toLocaleLowerCase(), { ns: 'generalForm' })} ${ + arrayLabel[1] + }`} + + {payload && + payload.map((data, i) => ( +
+
+ {i === 0 && + data.payload?.date && + `${ + data.payload.date ? t('date', { ns: 'generalForm' }) : '' + }: ${ + data.payload.date ? data.payload.date.split('T')[0] : '' + } `} +
+
+ {`${t( + data.payload.category + ? `${data.dataKey + .split('_')[1] + .toLocaleLowerCase()}${data.payload.category.toLocaleLowerCase()}` + : data.dataKey.split('_')[1].toLocaleLowerCase(), + { ns: 'generalForm' } + )}: ${formatWithThousandSeparator( + data.payload[data.dataKey], + 4 + )} ${coinType}`} +
+
+ ))} +
+ ) +} + +CustomTooltip.propTypes = { + payload: PropTypes.array, + label: PropTypes.any, + coinType: PropTypes.string +} + +const width = window.innerWidth + +const CustomBarChart = ({ + typeData, + selectedUSD, + data, + barRef, + showLegend +}) => { + const [category, setCategory] = useState('') + const [coinType, setCoinType] = useState('EOS') + + useEffect(() => { + if (typeData === 'income') setCategory('Claimed') + else setCategory('Categorized') + }, [typeData]) + + useEffect(() => { + selectedUSD ? setCoinType('USD') : setCoinType('EOS') + }, [selectedUSD]) + + return ( + + + + + + } + /> + {showLegend && ( + } /> + )} + 600 ? 35 : 15} + fill="#f4d35e" + > + {data.map(({ election }) => ( + + ))} + + 600 ? 35 : 15} + fill="#ee964b" + > + {data.map(({ election }) => ( + + ))} + + 600 ? 35 : 15} + fill="#19647e" + > + {data.map(({ election }) => ( + + ))} + + + + ) +} + +CustomBarChart.propTypes = { + typeData: PropTypes.string, + selectedUSD: PropTypes.string, + data: PropTypes.array, + barRef: PropTypes.object, + showLegend: PropTypes.bool +} + +export default memo(CustomBarChart) diff --git a/webapp/src/components/BarChartReport/index.js b/webapp/src/components/BarChartReport/index.js index f9d98139..abc750bc 100644 --- a/webapp/src/components/BarChartReport/index.js +++ b/webapp/src/components/BarChartReport/index.js @@ -1,8 +1,11 @@ -import React, { memo, useCallback, useState, useEffect } from 'react' +import React, { memo, useCallback, useState } from 'react' +import DownloadOutlined from '@mui/icons-material/DownloadOutlined' +import TooltipDownload from '@mui/material/Tooltip' +import { useCurrentPng } from 'recharts-to-png' +import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' import PropTypes from 'prop-types' import FileSaver from 'file-saver' -import { Box } from '@mui/system' -import { makeStyles } from '@mui/styles' import { IconButton, Typography, @@ -10,103 +13,12 @@ import { Switch, FormGroup } from '@mui/material' -import TooltipDownload from '@mui/material/Tooltip' -import DownloadOutlined from '@mui/icons-material/DownloadOutlined' -import { useTranslation } from 'react-i18next' -import { useCurrentPng } from 'recharts-to-png' -import { - ComposedChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - Legend, - ResponsiveContainer, - Cell -} from 'recharts' - -import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' +import CustomBarchart from './custom-barchart' import styles from './styles' const useStyles = makeStyles(styles) -const RenderChartLegend = ({ data }) => { - const classes = useStyles() - const { t } = useTranslation() - - return ( -
- - - {t(`un${data.toLocaleLowerCase()}`, { ns: 'generalForm' })} - - - - {t(`${data.toLocaleLowerCase()}`, { ns: 'generalForm' })} - - - - {t('total', { ns: 'generalForm' })} - -
- ) -} - -RenderChartLegend.propTypes = { - data: PropTypes.string -} - -const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { - const { t } = useTranslation() - label = label + '' - const arrayLabel = label.split(' ') - - return ( -
- - {`${t(arrayLabel[0].toLocaleLowerCase(), { ns: 'generalForm' })} ${ - arrayLabel[1] - }`} - - {payload && - payload.map((data, i) => ( -
-
- {i === 0 && - data.payload?.date && - `${ - data.payload.date ? t('date', { ns: 'generalForm' }) : '' - }: ${ - data.payload.date ? data.payload.date.split('T')[0] : '' - } `} -
-
- {`${t( - data.payload.category - ? `${data.dataKey - .split('_')[1] - .toLocaleLowerCase()}${data.payload.category.toLocaleLowerCase()}` - : data.dataKey.split('_')[1].toLocaleLowerCase(), - { ns: 'generalForm' } - )}: ${formatWithThousandSeparator( - data.payload[data.dataKey], - 4 - )} ${coinType}`} -
-
- ))} -
- ) -} - -CustomTooltip.propTypes = { - payload: PropTypes.array, - label: PropTypes.any, - coinType: PropTypes.string -} - const BarChartReport = ({ data, keyTranslation, @@ -116,11 +28,8 @@ const BarChartReport = ({ }) => { const classes = useStyles() const [getBarPng, { ref: barRef }] = useCurrentPng() - const [category, setCategory] = useState('') const { t } = useTranslation() const [selectedUSD, setSelected] = useState(false) - const [coinType, setCoinType] = useState('EOS') - const width = window.innerWidth const handleChange = event => { setSelected(event.target.checked) @@ -134,15 +43,6 @@ const BarChartReport = ({ } }, [getBarPng]) - useEffect(() => { - if (typeData === 'income') setCategory('Claimed') - else setCategory('Categorized') - }, [typeData]) - - useEffect(() => { - selectedUSD ? setCoinType('USD') : setCoinType('EOS') - }, [selectedUSD]) - return (
@@ -167,59 +67,12 @@ const BarChartReport = ({
- - - - - - } - /> - {showLegend && ( - } /> - )} - 600 ? 35 : 15} - fill="#f4d35e" - > - {data.map(({ election }) => ( - - ))} - - 600 ? 35 : 15} - fill="#ee964b" - > - {data.map(({ election }) => ( - - ))} - - 600 ? 35 : 15} - fill="#19647e" - > - {data.map(({ election }) => ( - - ))} - - - +
) From 67b251d77c8d72c385495a8b727ac00031d72b74 Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Mon, 16 Jan 2023 19:19:51 -0600 Subject: [PATCH 03/16] perf(webapp): componetization income view and lineChart --- ...{custom-barchart.js => custom-barChart.js} | 0 webapp/src/components/BarChartReport/index.js | 5 +- .../LineChartReport/custom-lineChart.js | 117 +++++++++++++++ .../src/components/LineChartReport/index.js | 142 ++---------------- .../IncomeReport/income-table-report.js | 83 ++++++++++ webapp/src/routes/IncomeReport/index.js | 67 +-------- 6 files changed, 219 insertions(+), 195 deletions(-) rename webapp/src/components/BarChartReport/{custom-barchart.js => custom-barChart.js} (100%) create mode 100644 webapp/src/components/LineChartReport/custom-lineChart.js create mode 100644 webapp/src/routes/IncomeReport/income-table-report.js diff --git a/webapp/src/components/BarChartReport/custom-barchart.js b/webapp/src/components/BarChartReport/custom-barChart.js similarity index 100% rename from webapp/src/components/BarChartReport/custom-barchart.js rename to webapp/src/components/BarChartReport/custom-barChart.js diff --git a/webapp/src/components/BarChartReport/index.js b/webapp/src/components/BarChartReport/index.js index abc750bc..67682cbe 100644 --- a/webapp/src/components/BarChartReport/index.js +++ b/webapp/src/components/BarChartReport/index.js @@ -14,7 +14,7 @@ import { FormGroup } from '@mui/material' -import CustomBarchart from './custom-barchart' +import CustomBarChart from './custom-barChart' import styles from './styles' const useStyles = makeStyles(styles) @@ -67,11 +67,12 @@ const BarChartReport = ({
-
diff --git a/webapp/src/components/LineChartReport/custom-lineChart.js b/webapp/src/components/LineChartReport/custom-lineChart.js new file mode 100644 index 00000000..16607127 --- /dev/null +++ b/webapp/src/components/LineChartReport/custom-lineChart.js @@ -0,0 +1,117 @@ +import React, { memo, useEffect, useState } from 'react' +import PropTypes from 'prop-types' +import { useTranslation } from 'react-i18next' +import { + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, + LineChart, + Line, + Brush +} from 'recharts' + +import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' + +const width = window.innerWidth + +const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { + const { t } = useTranslation() + label = label + '' + + return ( +
+ {payload && + payload.map((data, i) => ( +
+
+ {i === 0 && + `${t('date', { ns: 'generalForm' })}: ${ + data.payload.date.split('T')[0] + } `} +
+
+ {`${t('balance', { + ns: 'incomeRoute' + })}: ${formatWithThousandSeparator( + data.payload[data.dataKey], + 4 + )} ${coinType}`} +
+
+ ))} +
+ ) +} + +CustomTooltip.propTypes = { + payload: PropTypes.array, + label: PropTypes.any, + coinType: PropTypes.string +} + +const CustomLineChart = ({ selectedUSD, data, lineRef }) => { + const [coinType, setCoinType] = useState('EOS') + const [dataKey, setDataKey] = useState('balance') + + useEffect(() => { + if (selectedUSD) { + setCoinType('USD') + setDataKey('usd_total') + } else { + setDataKey('balance') + setCoinType('EOS') + } + }, [selectedUSD]) + + return ( + + + + 600 ? 40 : 80} + allowDataOverflow={false} + /> + + } + /> + + 600 ? width * 0.4 : 100} + height={20} + x={width > 600 ? width * 0.2 : 150} + /> + + + ) +} + +CustomLineChart.propTypes = { + selectedUSD: PropTypes.bool, + data: PropTypes.array, + lineRef: PropTypes.object +} + +export default memo(CustomLineChart) diff --git a/webapp/src/components/LineChartReport/index.js b/webapp/src/components/LineChartReport/index.js index 5232c2f1..9080916d 100644 --- a/webapp/src/components/LineChartReport/index.js +++ b/webapp/src/components/LineChartReport/index.js @@ -1,8 +1,11 @@ -import React, { memo, useCallback, useState, useEffect } from 'react' +import React, { memo, useCallback, useState } from 'react' import PropTypes from 'prop-types' import FileSaver from 'file-saver' -import { Box } from '@mui/system' import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import { useCurrentPng } from 'recharts-to-png' +import TooltipDownload from '@mui/material/Tooltip' +import DownloadOutlined from '@mui/icons-material/DownloadOutlined' import { IconButton, Typography, @@ -10,96 +13,17 @@ import { Switch, FormGroup } from '@mui/material' -import TooltipDownload from '@mui/material/Tooltip' -import DownloadOutlined from '@mui/icons-material/DownloadOutlined' -import { useTranslation } from 'react-i18next' -import { useCurrentPng } from 'recharts-to-png' -import { - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - LineChart, - Line, - Brush -} from 'recharts' - -import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' import styles from './styles' +import CustomLineChart from './custom-lineChart' const useStyles = makeStyles(styles) -const RenderChartLegend = ({ data }) => { - const classes = useStyles() - const { t } = useTranslation() - - return ( - - ) -} - -RenderChartLegend.propTypes = { - data: PropTypes.string -} - -const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { - const { t } = useTranslation() - label = label + '' - - return ( -
- {payload && - payload.map((data, i) => ( -
-
- {i === 0 && - `${t('date', { ns: 'generalForm' })}: ${ - data.payload.date.split('T')[0] - } `} -
-
- {`${t('balance', { - ns: 'incomeRoute' - })}: ${formatWithThousandSeparator( - data.payload[data.dataKey], - 4 - )} ${coinType}`} -
-
- ))} -
- ) -} - -CustomTooltip.propTypes = { - payload: PropTypes.array, - label: PropTypes.any, - coinType: PropTypes.string -} - const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { const classes = useStyles() const [getBarPng, { ref: lineRef }] = useCurrentPng() const { t } = useTranslation() const [selectedUSD, setSelected] = useState(false) - const [coinType, setCoinType] = useState('EOS') - const [dataKey, setDataKey] = useState('balance') - const width = window.innerWidth const handleChange = event => { setSelected(event.target.checked) @@ -113,16 +37,6 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { } }, [getBarPng]) - useEffect(() => { - if (selectedUSD) { - setCoinType('USD') - setDataKey('usd_total') - } else { - setDataKey('balance') - setCoinType('EOS') - } - }, [selectedUSD]) - return (
@@ -147,45 +61,11 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => {
- - - - 600 ? 40 : 80} - allowDataOverflow={false} - /> - - } - /> - - 600 ? width * 0.4 : 100} - height={20} - x={width > 600 ? width * 0.2 : 150} - /> - - +
) diff --git a/webapp/src/routes/IncomeReport/income-table-report.js b/webapp/src/routes/IncomeReport/income-table-report.js new file mode 100644 index 00000000..00c5ea2f --- /dev/null +++ b/webapp/src/routes/IncomeReport/income-table-report.js @@ -0,0 +1,83 @@ +import React, { memo } from 'react' +import PropTypes from 'prop-types' +import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' + +import { formatWithThousandSeparator } from '../../utils' + +import styles from './styles' +import { Typography } from '@mui/material' +import TableReport from '../../components/TableReport' + +const useStyles = makeStyles(styles) +const rowsCenter = { flex: 1, align: 'center', headerAlign: 'center' } + +const IncomeTableReport = ({ tableData, showElectionRadio }) => { + const classes = useStyles() + const { t } = useTranslation() + const columns = [ + { + field: tableData[0]?.name ? 'name' : 'election', + headerName: tableData[0]?.name + ? t('tableHeader1', { ns: 'incomeRoute' }) + : t('tableElectionHeader', { ns: 'incomeRoute' }), + cellClassName: classes.links, + renderCell: param => ( + + {param.value} + + ), + ...rowsCenter + }, + { + field: tableData[0]?.election ? 'EOS_TOTAL' : 'EOS_CLAIMED', + headerName: 'EOS', + renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, + type: 'number', + ...rowsCenter + }, + { + field: tableData[0]?.election ? 'USD_TOTAL' : 'USD_CLAIMED', + headerName: 'USD', + renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, + type: 'number', + ...rowsCenter + }, + { + field: 'EOS_CLAIMED_PERCENT', + headerName: t('tableHeader7', { ns: 'incomeRoute' }), + type: 'number', + ...rowsCenter + }, + { + field: 'EOS_UNCLAIMED_PERCENT', + headerName: t('tableHeader8', { ns: 'incomeRoute' }), + type: 'number', + ...rowsCenter + } + ] + + return ( +
+
+ + {showElectionRadio === 'allElections' + ? t('titleTable2', { ns: 'incomeRoute' }) + : t('titleTable', { ns: 'incomeRoute' })} + +
+ +
+
+
+ ) +} + +IncomeTableReport.propTypes = { + tableData: PropTypes.array, + showElectionRadio: PropTypes.string +} +export default memo(IncomeTableReport) diff --git a/webapp/src/routes/IncomeReport/index.js b/webapp/src/routes/IncomeReport/index.js index bcdcec8e..960f76d8 100644 --- a/webapp/src/routes/IncomeReport/index.js +++ b/webapp/src/routes/IncomeReport/index.js @@ -4,7 +4,6 @@ import { useTranslation } from 'react-i18next' import { FormControl, FormControlLabel, - Typography, RadioGroup, Radio, Divider @@ -15,17 +14,14 @@ import BarChartReport from '../../components/BarChartReport' import LineChartReport from '../../components/LineChartReport' import TreasuryBalance from '../../components/TreasuryBalance' import PieChartReport from '../../components/PieChartReport' -import { formatWithThousandSeparator } from '../../utils' -import TableReport from '../../components/TableReport' import SelectComponent from '../../components/Select' import TreasuryDisbursementsInfo from './treasury-disbursements-info' import styles from './styles' +import IncomeTableReport from './income-table-report' const useStyles = makeStyles(styles) -const rowsCenter = { flex: 1, align: 'center', headerAlign: 'center' } - const IncomeReport = () => { const classes = useStyles() @@ -52,51 +48,6 @@ const IncomeReport = () => { const tableData = showElectionRadio === 'allElections' ? incomeByElectionsList : delegatesList - const columns = [ - { - field: tableData[0]?.name ? 'name' : 'election', - headerName: tableData[0]?.name - ? t('tableHeader1', { ns: 'incomeRoute' }) - : t('tableElectionHeader', { ns: 'incomeRoute' }), - cellClassName: classes.links, - renderCell: param => ( - - {param.value} - - ), - ...rowsCenter - }, - { - field: tableData[0]?.election ? 'EOS_TOTAL' : 'EOS_CLAIMED', - headerName: 'EOS', - renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, - type: 'number', - ...rowsCenter - }, - { - field: tableData[0]?.election ? 'USD_TOTAL' : 'USD_CLAIMED', - headerName: 'USD', - renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, - type: 'number', - ...rowsCenter - }, - { - field: 'EOS_CLAIMED_PERCENT', - headerName: t('tableHeader7', { ns: 'incomeRoute' }), - type: 'number', - ...rowsCenter - }, - { - field: 'EOS_UNCLAIMED_PERCENT', - headerName: t('tableHeader8', { ns: 'incomeRoute' }), - type: 'number', - ...rowsCenter - } - ] - return (
@@ -163,18 +114,10 @@ const IncomeReport = () => { typeData={'income'} /> -
-
- - {showElectionRadio === 'allElections' - ? t('titleTable2', { ns: 'incomeRoute' }) - : t('titleTable', { ns: 'incomeRoute' })} - -
- -
-
-
+
) } From a53ccddb82360e974483b7383bc68c1639955b3a Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Tue, 17 Jan 2023 09:34:35 -0600 Subject: [PATCH 04/16] perf(webapp): componetization of expense table view --- .../ExpenseReport/expense-table-report.js | 92 +++++++++++++++++++ webapp/src/routes/ExpenseReport/index.js | 76 ++------------- webapp/src/routes/IncomeReport/index.js | 6 +- 3 files changed, 101 insertions(+), 73 deletions(-) create mode 100644 webapp/src/routes/ExpenseReport/expense-table-report.js diff --git a/webapp/src/routes/ExpenseReport/expense-table-report.js b/webapp/src/routes/ExpenseReport/expense-table-report.js new file mode 100644 index 00000000..02561106 --- /dev/null +++ b/webapp/src/routes/ExpenseReport/expense-table-report.js @@ -0,0 +1,92 @@ +import React, { memo } from 'react' +import PropTypes from 'prop-types' +import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' + +import { formatWithThousandSeparator } from '../../utils' + +import styles from './styles' +import { Typography } from '@mui/material' +import TableReport from '../../components/TableReport' + +const useStyles = makeStyles(styles) +const rowsCenter = { flex: 1, align: 'center', headerAlign: 'center' } + +const ExpenseTableReport = ({ tableData, showElectionRadio }) => { + const classes = useStyles() + const { t } = useTranslation() + + const columns = [ + { + field: 'election', + hide: !tableData[0]?.election, + headerName: t('tableElectionHeader', { ns: 'expenseRoute' }), + cellClassName: classes.links, + ...rowsCenter + }, + { + field: 'name', + hide: !tableData[0]?.color, + headerName: tableData[0]?.name + ? t('tableHeader1', { ns: 'expenseRoute' }) + : t('tableElectionHeader', { ns: 'expenseRoute' }), + cellClassName: classes.links, + renderCell: param => ( + + {param.value} + + ), + ...rowsCenter + }, + { + field: tableData[0]?.election ? 'EOS_TOTAL' : 'EOS_CATEGORIZED', + headerName: 'EOS', + renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, + type: 'number', + ...rowsCenter + }, + { + field: tableData[0]?.election ? 'USD_TOTAL' : 'USD_CATEGORIZED', + headerName: 'USD', + renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, + type: 'number', + ...rowsCenter + }, + { + field: 'EOS_CATEGORIZED_PERCENT', + headerName: t('tableHeader7', { ns: 'expenseRoute' }), + type: 'number', + ...rowsCenter + }, + { + field: 'EOS_UNCATEGORIZED_PERCENT', + headerName: t('tableHeader8', { ns: 'expenseRoute' }), + type: 'number', + ...rowsCenter + } + ] + + return ( +
+
+ + {showElectionRadio === 'allElections' + ? t('titleTable2', { ns: 'expenseRoute' }) + : t('titleTable', { ns: 'expenseRoute' })} + +
+ +
+
+
+ ) +} + +ExpenseTableReport.propTypes = { + tableData: PropTypes.array, + showElectionRadio: PropTypes.string +} +export default memo(ExpenseTableReport) diff --git a/webapp/src/routes/ExpenseReport/index.js b/webapp/src/routes/ExpenseReport/index.js index 8fa17414..5c27a465 100644 --- a/webapp/src/routes/ExpenseReport/index.js +++ b/webapp/src/routes/ExpenseReport/index.js @@ -5,8 +5,7 @@ import { FormControlLabel, RadioGroup, Radio, - Divider, - Typography + Divider } from '@mui/material' import { useTranslation } from 'react-i18next' @@ -14,14 +13,12 @@ import useExpenseReportState from '../../hooks/customHooks/useExpenseReportState import TreasuryBalance from '../../components/TreasuryBalance' import BarChartReport from '../../components/BarChartReport' import PieChartReport from '../../components/PieChartReport' -import { formatWithThousandSeparator } from '../../utils' -import TableReport from '../../components/TableReport' import SelectComponent from '../../components/Select' import styles from './styles' +import ExpenseTableReport from './expense-table-report' const useStyles = makeStyles(styles) -const rowsCenter = { flex: 1, align: 'center', headerAlign: 'center' } const ExpenseReport = () => { const classes = useStyles() @@ -44,59 +41,6 @@ const ExpenseReport = () => { ? expenseByElectionsList : delegatesList - const columns = [ - { - field: 'election', - hide: !tableData[0]?.election, - headerName: t('tableElectionHeader', { ns: 'expenseRoute' }), - cellClassName: classes.links, - ...rowsCenter - }, - { - field: 'name', - hide: !tableData[0]?.color, - headerName: tableData[0]?.name - ? t('tableHeader1', { ns: 'expenseRoute' }) - : t('tableElectionHeader', { ns: 'expenseRoute' }), - cellClassName: classes.links, - renderCell: param => ( - - {param.value} - - ), - ...rowsCenter - }, - { - field: tableData[0]?.election ? 'EOS_TOTAL' : 'EOS_CATEGORIZED', - headerName: 'EOS', - renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, - type: 'number', - ...rowsCenter - }, - { - field: tableData[0]?.election ? 'USD_TOTAL' : 'USD_CATEGORIZED', - headerName: 'USD', - renderCell: param => <>{formatWithThousandSeparator(param.value, 2)}, - type: 'number', - ...rowsCenter - }, - { - field: 'EOS_CATEGORIZED_PERCENT', - headerName: t('tableHeader7', { ns: 'expenseRoute' }), - type: 'number', - ...rowsCenter - }, - { - field: 'EOS_UNCATEGORIZED_PERCENT', - headerName: t('tableHeader8', { ns: 'expenseRoute' }), - type: 'number', - ...rowsCenter - } - ] - return (
@@ -164,18 +108,10 @@ const ExpenseReport = () => {
-
-
- - {showElectionRadio === 'allElections' - ? t('titleTable2', { ns: 'expenseRoute' }) - : t('titleTable', { ns: 'expenseRoute' })} - -
- -
-
-
+
) } diff --git a/webapp/src/routes/IncomeReport/index.js b/webapp/src/routes/IncomeReport/index.js index 960f76d8..98d242ce 100644 --- a/webapp/src/routes/IncomeReport/index.js +++ b/webapp/src/routes/IncomeReport/index.js @@ -1,6 +1,6 @@ import React, { memo, useEffect } from 'react' -import { makeStyles } from '@mui/styles' import { useTranslation } from 'react-i18next' +import { makeStyles } from '@mui/styles' import { FormControl, FormControlLabel, @@ -10,15 +10,15 @@ import { } from '@mui/material' import useIncomeReportState from '../../hooks/customHooks/useIncomeReportState' -import BarChartReport from '../../components/BarChartReport' import LineChartReport from '../../components/LineChartReport' import TreasuryBalance from '../../components/TreasuryBalance' +import BarChartReport from '../../components/BarChartReport' import PieChartReport from '../../components/PieChartReport' import SelectComponent from '../../components/Select' import TreasuryDisbursementsInfo from './treasury-disbursements-info' -import styles from './styles' import IncomeTableReport from './income-table-report' +import styles from './styles' const useStyles = makeStyles(styles) From 05c90251640271a0df6049fd13263013bcd8ee76 Mon Sep 17 00:00:00 2001 From: JAMares Date: Tue, 17 Jan 2023 16:35:44 -0600 Subject: [PATCH 05/16] feat(webapp): add estimated treasury to the lineChart --- .../src/components/LineChartReport/index.js | 50 +++++++++-------- .../hooks/customHooks/useIncomeReportState.js | 54 +++++++++++++++++-- .../customHooks/useTresuryBalanceState.js | 4 +- webapp/src/language/en.json | 3 +- webapp/src/language/es.json | 3 +- webapp/src/utils/new-format-objects.js | 35 ++++++++++-- 6 files changed, 112 insertions(+), 37 deletions(-) diff --git a/webapp/src/components/LineChartReport/index.js b/webapp/src/components/LineChartReport/index.js index 5232c2f1..740d6687 100644 --- a/webapp/src/components/LineChartReport/index.js +++ b/webapp/src/components/LineChartReport/index.js @@ -60,28 +60,29 @@ RenderChartLegend.propTypes = { const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { const { t } = useTranslation() label = label + '' + let textBalance = '' + + if (payload !== null) + textBalance = payload[0]?.payload?.isValued ? 'estimated' : 'balance' return (
- {payload && - payload.map((data, i) => ( -
-
- {i === 0 && - `${t('date', { ns: 'generalForm' })}: ${ - data.payload.date.split('T')[0] - } `} -
-
- {`${t('balance', { - ns: 'incomeRoute' - })}: ${formatWithThousandSeparator( - data.payload[data.dataKey], - 4 - )} ${coinType}`} -
+ {payload && ( +
+
+ {t('date', { ns: 'generalForm' })}: + {payload[0]?.payload.date.split('T')[0]} +
+
+ {`${t(textBalance, { + ns: 'incomeRoute' + })}: ${formatWithThousandSeparator( + payload[0]?.payload[payload[0]?.dataKey], + 4 + )} ${coinType}`}
- ))} +
+ )}
) } @@ -98,7 +99,6 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { const { t } = useTranslation() const [selectedUSD, setSelected] = useState(false) const [coinType, setCoinType] = useState('EOS') - const [dataKey, setDataKey] = useState('balance') const width = window.innerWidth const handleChange = event => { @@ -116,9 +116,7 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { useEffect(() => { if (selectedUSD) { setCoinType('USD') - setDataKey('usd_total') } else { - setDataKey('balance') setCoinType('EOS') } }, [selectedUSD]) @@ -173,10 +171,18 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { /> + { + try { + const response = await eosApi.getTableRows({ + json: true, + code: mainConfig.edenContract, + scope: 0, + table: 'distribution' + }) + const date = new Date(response?.rows[0][1]?.distribution_time) + + return date + } catch (error) { + console.log(error) + await sleep(10) + getNextEdenDisbursement() + } +} const useIncomeReportState = () => { + const [state] = useSharedState() const [electionRoundSelect, setElectionRoundSelect] = useState(0) const [showElectionRadio, setShowElectionRadio] = useState('allElections') const [incomeByElectionsList, setIncomeByElectionsList] = useState([]) @@ -64,10 +87,6 @@ const useIncomeReportState = () => { setRanksList(ranksLevelElectionData.eden_election) - const { data: treasuryData } = await loadTreasuryBalance() - - setTreasuryList(newDataFormatByTreasuryList(treasuryData.eden_treasury)) - setElectionRoundSelect(electionsData.eden_election[0]?.election) setelectionsList(electionsData.eden_election || []) @@ -77,6 +96,31 @@ const useIncomeReportState = () => { ) }, []) + useEffect(async () => { + const { data: treasuryData } = await loadTreasuryBalance() + + const nextEdenDisbursement = await getNextEdenDisbursement() + + const { eosRate } = state.eosTrasuryBalance + const treasuryBalance = Number( + state?.eosTrasuryBalance?.currencyBalance.split(' ')[0] + ) + const totalNextMonthDistribution = treasuryBalance * 0.11 || 0 + const estimatedTreasury = treasuryBalance - totalNextMonthDistribution + + const usdEstimatedTreasury = + (treasuryBalance - totalNextMonthDistribution) * eosRate + + setTreasuryList( + newDataFormatByTreasuryList( + treasuryData.eden_treasury, + nextEdenDisbursement, + estimatedTreasury, + usdEstimatedTreasury + ) + ) + }, [state.eosTrasuryBalance.currencyBalance]) + useEffect(async () => { if (showElectionRadio === 'allElections') { const totalIncomeByDelegateData = await loadIncomesByDelegate() diff --git a/webapp/src/hooks/customHooks/useTresuryBalanceState.js b/webapp/src/hooks/customHooks/useTresuryBalanceState.js index 972af4d0..3a9430ba 100644 --- a/webapp/src/hooks/customHooks/useTresuryBalanceState.js +++ b/webapp/src/hooks/customHooks/useTresuryBalanceState.js @@ -63,9 +63,7 @@ const useTresuryBalanceState = () => { scope: 0, table: 'distribution' }) - const date = new Date( - response?.rows[0][1]?.distribution_time - ).toLocaleDateString() + const date = new Date(response?.rows[0][1]?.distribution_time) setNextEdenDisbursement(date) } catch (error) { diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json index 08e3ed00..9aa9587d 100644 --- a/webapp/src/language/en.json +++ b/webapp/src/language/en.json @@ -93,7 +93,8 @@ "perHeadChief": "Per Head Chief", "trasury": "Projected Treasury Balance", "delegate": "Delegate", - "balance": "Treasury Balance" + "balance": "Treasury Balance", + "estimated": "Estimated Treasury Balance" }, "expenseRoute": { "titleBarChart": "Expense per Election", diff --git a/webapp/src/language/es.json b/webapp/src/language/es.json index 68fd6a91..b546bc2f 100644 --- a/webapp/src/language/es.json +++ b/webapp/src/language/es.json @@ -88,7 +88,8 @@ "perHeadChief": "Por Head Chief", "trasury": "Balance de tesorería proyectado", "delegate": "Delegate", - "balance": "Saldo de Tesorería" + "balance": "Saldo de Tesorería", + "estimated": "Balance de Tesorería Estimado" }, "expenseRoute": { "titleBarChart": "Gasto por Elección", diff --git a/webapp/src/utils/new-format-objects.js b/webapp/src/utils/new-format-objects.js index 26a5ecac..c5095409 100644 --- a/webapp/src/utils/new-format-objects.js +++ b/webapp/src/utils/new-format-objects.js @@ -27,20 +27,45 @@ export const newDataFormatByDelegatesIncome = transactionsList => color: generateColor() })) -export const newDataFormatByTreasuryList = treasuryList => { +export const newDataFormatByTreasuryList = ( + treasuryList, + nextEdenDisbursement, + estimatedTreasury, + usdEstimatedTreasury +) => { const newTreasuryList = [] - for (let index = 0; index < treasuryList.length; index++) { + for (let index = 0; index < treasuryList.length - 1; index++) { const curDate = treasuryList[index].date.split('T')[0] if ( !newTreasuryList.find(element => element.date.split('T')[0] === curDate) ) newTreasuryList.push({ - balance: treasuryList[index].balance, - usd_total: treasuryList[index].usd_total, - date: treasuryList[index].date.split('T')[0] + EOS_BALANCE: treasuryList[index].balance, + USD_BALANCE: treasuryList[index].usd_total, + date: treasuryList[index].date.split('T')[0], + isValued: false }) } + const curDate = treasuryList.at(-1).date.split('T')[0] + if (!newTreasuryList.find(element => element.date.split('T')[0] === curDate)) + newTreasuryList.push({ + EOS_BALANCE: treasuryList.at(-1).balance, + USD_BALANCE: treasuryList.at(-1).usd_total, + EOS_VALUED: treasuryList.at(-1).balance, + USD_VALUED: treasuryList.at(-1).usd_total, + date: treasuryList.at(-1).date.split('T')[0], + isValued: false + }) + + const dateFormat = new Date(nextEdenDisbursement)?.toISOString() + newTreasuryList.push({ + EOS_VALUED: estimatedTreasury, + date: dateFormat, + USD_VALUED: usdEstimatedTreasury, + isValued: true + }) + return newTreasuryList } From 8d575f236daf6cb224fe958ac9e719ce2f3f6d03 Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Tue, 17 Jan 2023 16:42:46 -0600 Subject: [PATCH 06/16] perf(webapp): componetization spendTool view --- .../BarChartReport/custom-barChart.js | 2 +- webapp/src/components/TableReport/styles.js | 2 +- .../hooks/customHooks/useSpendToolsState.js | 223 ++++++++------ webapp/src/routes/IncomeReport/index.js | 6 +- webapp/src/routes/SpendTools/index.js | 286 ++---------------- .../SpendTools/spendTool-form-report.js | 153 ++++++++++ .../SpendTools/spendTool-modal-report.js | 150 +++++++++ webapp/src/routes/SpendTools/styles.js | 3 +- 8 files changed, 466 insertions(+), 359 deletions(-) create mode 100644 webapp/src/routes/SpendTools/spendTool-form-report.js create mode 100644 webapp/src/routes/SpendTools/spendTool-modal-report.js diff --git a/webapp/src/components/BarChartReport/custom-barChart.js b/webapp/src/components/BarChartReport/custom-barChart.js index ba87963a..d3ff645a 100644 --- a/webapp/src/components/BarChartReport/custom-barChart.js +++ b/webapp/src/components/BarChartReport/custom-barChart.js @@ -173,7 +173,7 @@ const CustomBarChart = ({ CustomBarChart.propTypes = { typeData: PropTypes.string, - selectedUSD: PropTypes.string, + selectedUSD: PropTypes.any, data: PropTypes.array, barRef: PropTypes.object, showLegend: PropTypes.bool diff --git a/webapp/src/components/TableReport/styles.js b/webapp/src/components/TableReport/styles.js index 46dd9239..69e92a57 100644 --- a/webapp/src/components/TableReport/styles.js +++ b/webapp/src/components/TableReport/styles.js @@ -5,7 +5,7 @@ export default theme => ({ height: 'auto', '& .MuiDataGrid-root': { border: 'none', - minWidth: '500px' + minWidth: '920px' } } }) diff --git a/webapp/src/hooks/customHooks/useSpendToolsState.js b/webapp/src/hooks/customHooks/useSpendToolsState.js index 0c55d78a..cf378cc5 100644 --- a/webapp/src/hooks/customHooks/useSpendToolsState.js +++ b/webapp/src/hooks/customHooks/useSpendToolsState.js @@ -1,6 +1,6 @@ -import { useEffect, useState } from 'react' -import { useMutation } from '@apollo/client' import ReactGA from 'react-ga' +import { useMutation } from '@apollo/client' +import { useEffect, useState } from 'react' import { useSharedState } from '../../context/state.context' import { useImperativeQuery } from '../../utils' @@ -16,7 +16,7 @@ import useForm from './useForm' const useSpendTools = () => { const [state] = useSharedState() - const { eosRate = 0, delegateBalance } = state.eosTrasuryBalance + const { eosRate = 0 } = state.eosTrasuryBalance const [authenticatedUser, setAuthenticatedUser] = useState('') const [transactionsList, setTransactionsList] = useState([]) const [openSnackbar, setOpenSnackbar] = useState(false) @@ -24,12 +24,14 @@ const useSpendTools = () => { const [openModal, setOpenModal] = useState(false) const [modalData, setModalData] = useState({}) const [loadingSignTransaction, setLoadingSignTransaction] = useState(false) + const [formValues, handleInputChange, reset, errors, validateForm] = useForm({ to: '', amount: '', category: '', description: '' }) + const [ formValuesModal, handleInputChangeModal, @@ -40,8 +42,10 @@ const useSpendTools = () => { newCategory: '', newDescription: '' }) + const [editTransaction] = useMutation(EDIT_TRANSACTION_BY_TXID) const [saveTransaction] = useMutation(SAVE_TRANSACTION) + const getAggregateTransaction = useImperativeQuery(GET_AGGREGATE_TRANSACTION) const getElections = useImperativeQuery(GET_ELECTIONS) const getTransactions = useImperativeQuery(GET_EXPENSES_BY_ACCOUNT) @@ -76,10 +80,10 @@ const useSpendTools = () => { if ( expense?.eden_transaction_aggregate.aggregate.sum.amount + amount <= income?.eden_transaction_aggregate.aggregate.sum.amount - ) { + ) return { idElection: id } - } } + return { idElection: elections?.at(-1).id } @@ -113,90 +117,138 @@ const useSpendTools = () => { } ) + setLoadingSignTransaction(false) + setOpenSnackbar(true) - if (openModal && transactionResult?.status === 'executed') { - const { idElection } = await getElectionWithLessExpense( - modalData?.amount - ) - - ReactGA.event({ - category: 'transaction', - action: 'update transaction', - label: modalData?.txid - }) - - editTransaction({ - variables: { - where: { - txid: { _eq: modalData?.txid }, - digest: { _eq: modalData?.digest } - }, - _set: { + return transactionResult + } catch (error) { + setErrorMessage(error.message) + + setLoadingSignTransaction(false) + } + } + + const handleRecategorizeTx = async e => { + e.preventDefault() + + if (Object.keys(validateFormModal(formValuesModal)).length > 0) return + + const dataAction = { + account: state.user?.accountName, + new_memo: `eden_expense:${formValuesModal.newCategory}/${formValuesModal.newDescription}`, + tx_id: modalData?.txid, + digest: modalData?.digest + } + + if (modalData?.digest === modalData?.txid) { + setErrorMessage( + 'You must wait because the transaction continues without digest' + ) + + return + } + + const txResult = await executeAction( + dataAction, + 'edenexplorer', + 'categorize' + ) + + if (txResult?.status !== 'executed') return + + const { idElection } = await getElectionWithLessExpense(modalData?.amount) + + ReactGA.event({ + category: 'transaction', + action: 'update transaction', + label: modalData?.txid + }) + + editTransaction({ + variables: { + where: { + txid: { _eq: modalData?.txid }, + digest: { _eq: modalData?.digest } + }, + _set: { + category: formValuesModal.newCategory, + description: formValuesModal.newDescription, + id_election: idElection + } + } + }) + + setTransactionsList( + transactionsList.map(transaction => + transaction.txid === modalData?.txid + ? { + ...transaction, category: formValuesModal.newCategory, - description: formValuesModal.newDescription, - id_election: idElection + description: formValuesModal.newDescription } - } - }) - - setTransactionsList( - transactionsList.map(transaction => - transaction.txid === modalData?.txid - ? { - ...transaction, - category: formValuesModal.newCategory, - description: formValuesModal.newDescription - } - : transaction - ) - ) - - setOpenModal(false) - resetModal() - } else { - if (transactionResult?.status === 'executed') { - const amount = Number(formValues.amount.split(' ')[0]) - const { idElection } = await getElectionWithLessExpense(amount) - const payload = { - amount, - category: formValues.category, - date: transactionResult?.transaction.processed.block_time, - description: formValues.description, - eos_exchange: eosRate, - id_election: idElection, - recipient: formValues.to, - txid: transactionResult?.transactionId, - type: 'expense', - usd_total: amount * eosRate, - digest: transactionResult?.transactionId - } - - await saveTransaction({ - variables: { - payload - } - }) + : transaction + ) + ) + + setOpenModal(false) + resetModal() + } - const { data: transactions } = await getTransactions({ - account: state.user?.accountName - }) + const handleEosTransfer = async e => { + e.preventDefault() - setTransactionsList(transactions?.eden_transaction || []) - } + if (Object.keys(validateForm(formValues)).length > 0) return - ReactGA.event({ - category: 'transaction', - action: 'send tokens', - label: `from: ${formValues.to}, to: ${authenticatedUser}`, - value: Number(formValues.amount) - }) - reset() - } - } catch (error) { - setErrorMessage(error.message) + const dataAction = { + from: state.user?.accountName, + to: formValues.to, + quantity: formValues.amount, + memo: `eden_expense:${formValues.category}/${formValues.description}` } - setLoadingSignTransaction(false) + + const txResult = await executeAction(dataAction, 'eosio.token', 'transfer') + + if (txResult?.status !== 'executed') return + + const amount = Number(formValues.amount.split(' ')[0]) + + const { idElection } = await getElectionWithLessExpense(amount) + + const payload = { + amount, + category: formValues.category, + date: txResult?.transaction.processed.block_time, + description: formValues.description, + eos_exchange: eosRate, + id_election: idElection, + recipient: formValues.to, + txid: txResult?.transactionId, + type: 'expense', + usd_total: amount * eosRate, + digest: txResult?.transactionId + } + + await saveTransaction({ + variables: { + payload + } + }) + + const { data: transactions } = await getTransactions({ + account: state.user?.accountName + }) + + setTransactionsList(transactions?.eden_transaction || []) + + ReactGA.event({ + category: 'transaction', + action: 'send tokens', + label: `from: ${formValues.to}, to: ${authenticatedUser}`, + value: Number(formValues.amount) + }) + + reset() } const handleCloseModal = () => { @@ -222,7 +274,6 @@ const useSpendTools = () => { return [ { - delegateBalance, transactionsList, formValues, errors, @@ -236,16 +287,12 @@ const useSpendTools = () => { }, { handleInputChange, - reset, handleInputChangeModal, - resetModal, - validateForm, - validateFormModal, handleCloseModal, handleOpenModal, - executeAction, setOpenSnackbar, - setErrorMessage + handleRecategorizeTx, + handleEosTransfer } ] } diff --git a/webapp/src/routes/IncomeReport/index.js b/webapp/src/routes/IncomeReport/index.js index 98d242ce..60a88c59 100644 --- a/webapp/src/routes/IncomeReport/index.js +++ b/webapp/src/routes/IncomeReport/index.js @@ -1,4 +1,4 @@ -import React, { memo, useEffect } from 'react' +import React, { memo } from 'react' import { useTranslation } from 'react-i18next' import { makeStyles } from '@mui/styles' import { @@ -41,10 +41,6 @@ const IncomeReport = () => { { setElectionRoundSelect, setShowElectionRadio } ] = useIncomeReportState() - useEffect(() => { - setShowElectionRadio('allElections') - }, []) - const tableData = showElectionRadio === 'allElections' ? incomeByElectionsList : delegatesList diff --git a/webapp/src/routes/SpendTools/index.js b/webapp/src/routes/SpendTools/index.js index be80bcc5..56b88dcd 100644 --- a/webapp/src/routes/SpendTools/index.js +++ b/webapp/src/routes/SpendTools/index.js @@ -1,36 +1,22 @@ -import React, { memo, useEffect } from 'react' +import React, { memo } from 'react' import { makeStyles } from '@mui/styles' -import Select from '@mui/material/Select' -import Button from '@mui/material/Button' -import IconButton from '@mui/material/IconButton' -import MenuItem from '@mui/material/MenuItem' -import Modal from '@mui/material/Modal' -import TextField from '@mui/material/TextField' -import Tooltip from '@mui/material/Tooltip' -import InputLabel from '@mui/material/InputLabel' import { useTranslation } from 'react-i18next' -import { Spinner } from '@edenia/ui-kit' -import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' import useSpendTools from '../../hooks/customHooks/useSpendToolsState' -import { CATEGORIES } from '../../constants/income.constants' -import { useSharedState } from '../../context/state.context' import SnackbarComponent from '../../components/Snackbar' import styles from './styles' import SpendToolTableRerport from './spendTool-table-report' +import SpendToolFormReport from './spendTool-form-report' +import SpendToolModalReport from './spendTool-modal-report' const useStyles = makeStyles(styles) -let firstConcat = true const SpendTools = () => { const classes = useStyles() - const [state] = useSharedState() const { t } = useTranslation('spendToolsRoute') - const { eosRate = 0 } = state.eosTrasuryBalance const [ { - delegateBalance, formValues, errors, errorsModal, @@ -45,267 +31,43 @@ const SpendTools = () => { { handleInputChange, handleInputChangeModal, - validateForm, - validateFormModal, handleCloseModal, handleOpenModal, - executeAction, setOpenSnackbar, - setErrorMessage + handleRecategorizeTx, + handleEosTransfer } ] = useSpendTools() - const { to, amount, category, description } = formValues - let { newCategory, newDescription } = formValuesModal - - useEffect(() => { - if (newCategory) { - handleInputChangeModal({ - target: { name: 'newDescription', value: modalData?.description } - }) - } - }, [newCategory]) - - if (firstConcat && modalData?.description) { - newDescription = newDescription.concat(modalData?.description) - firstConcat = false - } - - const handleEosTransfer = async e => { - e.preventDefault() - - if (openModal) { - if (Object.keys(validateFormModal(formValuesModal)).length > 0) return - - const dataAction = { - account: state.user?.accountName, - new_memo: `eden_expense:${newCategory}/${newDescription}`, - tx_id: modalData?.txid, - digest: modalData?.digest - } - - if (modalData?.digest === modalData?.txid) { - setErrorMessage( - 'You must wait because the transaction continues without digest' - ) - } - - await executeAction(dataAction, 'edenexplorer', 'categorize') - } else { - if (Object.keys(validateForm(formValues)).length > 0) return - - const dataAction = { - from: state.user?.accountName, - to, - quantity: amount, - memo: `eden_expense:${category}/${description}` - } - - await executeAction(dataAction, 'eosio.token', 'transfer') - } - } - - const getTotalUSD = () => - `Aprox. $${ - isNaN(Number(amount.split(' ')[0])) - ? 0 - : (Number(amount.split(' ')[0]) * eosRate).toFixed(4) - } @ $${eosRate.toFixed(2)}/EOS` - return (
+ - -
- - - -
- {t('modalTitle')} -
-
- {t('modalAbout')} -
-
- {t('transactionInfo')} - - - -
- {t('blockTime')} {' '} - {new Date(modalData?.date?.split('T')[0]).toLocaleDateString()} -
- {t('action')} transfer{' '} - {t('data')} - {state.user?.accountName} {'->'} {modalData?.recipient} -
- {t('quantity')} - {formatWithThousandSeparator(modalData?.amount, 4)} - /EOS -
- Memo: {modalData?.description || t('memo')} -
-
-
-
-
- {t('categoryLabel')} - -
-
- {t('descriptionLabel')} - -
-
-
-
-
- -
-
- {errorMessage} -
-
-
-
{t('viewAbout')}
{t('transferInformation')}
-
-
-
-
- {t('toLabel')} - -
-
-
- - -
- -
-
-
-
- {t('categoryLabel')} - -
-
- {t('descriptionLabel')} - -
-
-
-
- -
-
- {!openModal && errorMessage} -
-
+ { + const classes = useStyles() + const [state] = useSharedState() + const { t } = useTranslation('spendToolsRoute') + + const { eosRate = 0, delegateBalance } = state.eosTrasuryBalance + const { to, amount, category, description } = formValues + + const getTotalUSD = () => + `Aprox. $${ + isNaN(Number(amount.split(' ')[0])) + ? 0 + : (Number(amount.split(' ')[0]) * eosRate).toFixed(4) + } @ $${eosRate.toFixed(2)}/EOS` + + return ( +
+
+
+
+ {t('toLabel')} + +
+
+
+ + +
+ +
+
+
+
+ {t('categoryLabel')} + +
+
+ {t('descriptionLabel')} + +
+
+
+
+ +
+
+ {errorMessage} +
+
+ ) +} + +SpendToolFormReport.propTypes = { + loadingSignTransaction: PropTypes.bool, + formValues: PropTypes.object, + errorMessage: PropTypes.string, + errors: PropTypes.object, + handleInputChange: PropTypes.func, + handleEosTransfer: PropTypes.func +} + +export default memo(SpendToolFormReport) diff --git a/webapp/src/routes/SpendTools/spendTool-modal-report.js b/webapp/src/routes/SpendTools/spendTool-modal-report.js new file mode 100644 index 00000000..a2161806 --- /dev/null +++ b/webapp/src/routes/SpendTools/spendTool-modal-report.js @@ -0,0 +1,150 @@ +import React, { memo, useEffect } from 'react' +import PropTypes from 'prop-types' +import { makeStyles } from '@mui/styles' +import Select from '@mui/material/Select' +import Button from '@mui/material/Button' +import IconButton from '@mui/material/IconButton' +import MenuItem from '@mui/material/MenuItem' +import Modal from '@mui/material/Modal' +import TextField from '@mui/material/TextField' +import Tooltip from '@mui/material/Tooltip' +import InputLabel from '@mui/material/InputLabel' +import { useTranslation } from 'react-i18next' +import { Spinner } from '@edenia/ui-kit' + +import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' +import { CATEGORIES } from '../../constants/income.constants' +import { useSharedState } from '../../context/state.context' + +import styles from './styles' + +const useStyles = makeStyles(styles) +let firstConcat = true + +const SpendToolModalReport = ({ + openModal, + handleCloseModal, + modalData, + formValuesModal, + handleInputChangeModal, + errorMessage, + handleRecategorizeTx, + loadingSignTransaction, + errorsModal +}) => { + const classes = useStyles() + const [state] = useSharedState() + const { t } = useTranslation('spendToolsRoute') + let { newCategory, newDescription } = formValuesModal + + useEffect(() => { + if (newCategory) { + handleInputChangeModal({ + target: { name: 'newDescription', value: modalData?.description } + }) + } + }, [newCategory]) + + if (firstConcat && modalData?.description) { + newDescription = newDescription.concat(modalData?.description) + firstConcat = false + } + + return ( + +
+ + + +
+ {t('modalTitle')} +
+
+ {t('modalAbout')} +
+
+ {t('transactionInfo')} + + + +
+ {t('blockTime')} {' '} + {new Date(modalData?.date?.split('T')[0]).toLocaleDateString()} +
+ {t('action')} transfer {t('data')} + {state.user?.accountName} {'->'} {modalData?.recipient} +
+ {t('quantity')} + {formatWithThousandSeparator(modalData?.amount, 4)} + /EOS +
+ Memo: {modalData?.description || t('memo')} +
+
+
+
+
+ {t('categoryLabel')} + +
+
+ {t('descriptionLabel')} + +
+
+
+
+
+ +
+
+ {errorMessage} +
+
+
+
+ ) +} + +SpendToolModalReport.propTypes = { + openModal: PropTypes.bool, + handleCloseModal: PropTypes.func, + modalData: PropTypes.object, + formValuesModal: PropTypes.object, + handleInputChangeModal: PropTypes.func, + errorMessage: PropTypes.string, + handleRecategorizeTx: PropTypes.func, + loadingSignTransaction: PropTypes.bool, + errorsModal: PropTypes.object +} + +export default memo(SpendToolModalReport) diff --git a/webapp/src/routes/SpendTools/styles.js b/webapp/src/routes/SpendTools/styles.js index 1698c24a..208826ca 100644 --- a/webapp/src/routes/SpendTools/styles.js +++ b/webapp/src/routes/SpendTools/styles.js @@ -108,7 +108,6 @@ export default theme => ({ } }, tableContainer: { - minWidth: '920px', marginTop: theme.spacing(2), '& .MuiDataGrid-columnHeaderTitle': { fontWeight: 'bold', @@ -158,7 +157,7 @@ export default theme => ({ }, modalDimentions: { width: '723px', - height: '605px', + height: 'auto', padding: '20px 32px', borderRadius: '7px', border: 'solid 1px #667080', From 890def9316c7d023f8cdb8afb135c9f719c9080f Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Tue, 17 Jan 2023 18:37:49 -0600 Subject: [PATCH 07/16] perf(webapp): delelegate accordion and delegate detail componetization --- webapp/src/components/Accordion/styles.js | 26 ---------- .../src/components/DelegateDetails/styles.js | 28 ----------- webapp/src/components/RadioFilter/index.js | 44 ++++++++++++++++ webapp/src/language/en.json | 2 +- .../DelegateReport/delegate-accordion.js} | 22 ++++---- .../DelegateReport/delegate-details.js} | 2 +- webapp/src/routes/DelegateReport/index.js | 11 ++-- webapp/src/routes/DelegateReport/styles.js | 50 +++++++++++++++++++ .../ExpenseReport/expense-table-report.js | 6 +-- webapp/src/routes/ExpenseReport/index.js | 36 ++++--------- webapp/src/routes/IncomeReport/index.js | 36 ++++--------- .../treasury-disbursements-info.js | 2 +- 12 files changed, 135 insertions(+), 130 deletions(-) delete mode 100644 webapp/src/components/Accordion/styles.js delete mode 100644 webapp/src/components/DelegateDetails/styles.js create mode 100644 webapp/src/components/RadioFilter/index.js rename webapp/src/{components/Accordion/index.js => routes/DelegateReport/delegate-accordion.js} (93%) rename webapp/src/{components/DelegateDetails/index.js => routes/DelegateReport/delegate-details.js} (96%) diff --git a/webapp/src/components/Accordion/styles.js b/webapp/src/components/Accordion/styles.js deleted file mode 100644 index d379cf9e..00000000 --- a/webapp/src/components/Accordion/styles.js +++ /dev/null @@ -1,26 +0,0 @@ -export default theme => ({ - accordionContainer: { - '& .MuiPaper-root': { - boxShadow: 'none' - }, - '& .MuiAccordionDetails-root': { - padding: theme.spacing(1, 0, 2) - }, - '& .delegate-bp-item-container': { - width: '100%', - borderBottom: 'none' - }, - '& .hideData': { - [theme.breakpoints.down('sm')]: { - display: 'none' - } - } - }, - alertContainer: { - height: '50vh', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - margin: theme.spacing(4) - } -}) diff --git a/webapp/src/components/DelegateDetails/styles.js b/webapp/src/components/DelegateDetails/styles.js deleted file mode 100644 index 3e109ecb..00000000 --- a/webapp/src/components/DelegateDetails/styles.js +++ /dev/null @@ -1,28 +0,0 @@ -export default theme => ({ - verticalLine: { - borderLeft: '1px solid rgba(225,225,225,.99)', - borderBottom: '1px solid rgba(225,225,225,.99)', - marginBottom: theme.spacing(1) - }, - chartContainer: { - display: 'flex', - justifyContent: 'space-between', - [theme.breakpoints.down('md')]: { - justifyContent: 'center', - flexDirection: 'column' - } - }, - pieChartContainer: { - width: '35vw', - [theme.breakpoints.down('md')]: { - width: '100%' - } - }, - alertContainer: { - height: '100%', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - margin: theme.spacing(4) - } -}) diff --git a/webapp/src/components/RadioFilter/index.js b/webapp/src/components/RadioFilter/index.js new file mode 100644 index 00000000..0885dc7e --- /dev/null +++ b/webapp/src/components/RadioFilter/index.js @@ -0,0 +1,44 @@ +import React, { memo } from 'react' +import PropTypes from 'prop-types' +import { FormControl, FormControlLabel, RadioGroup, Radio } from '@mui/material' + +const RadioFilter = ({ + setValue, + value1, + value2, + label1, + label2, + defaultValue +}) => { + return ( + + setValue(target.value)} + value={defaultValue} + > + } + label={label1} + value={value1} + /> + } + label={label2} + value={value2} + /> + + + ) +} + +RadioFilter.propTypes = { + setValue: PropTypes.func, + value1: PropTypes.string, + value2: PropTypes.string, + label1: PropTypes.string, + label2: PropTypes.string, + defaultValue: PropTypes.string +} +export default memo(RadioFilter) diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json index 08e3ed00..5ee87754 100644 --- a/webapp/src/language/en.json +++ b/webapp/src/language/en.json @@ -86,7 +86,7 @@ "titleDisbursement": "Monthly disbursements", "paragraph1Disbursement": "Eden delegate disbursements occur monthly and are claimed by the delegate from the contract to their personal EOS accounts.", "paragraph2Disbursement": "The overall disbursement is equal to 11% of the Eden treasury at at the time of disbursement. The amount is then divided equally among the representative levels. At each level, the amount is further divided equally among that level's representatives.", - "paragraph3Disbursement": "Next disbursement date", + "paragraph3Disbursement": "Next disbursement date:", "paragraph4Disbursement": "Projected next disbursement amount:", "perLevel": "Per Level", "perChief": "Per Chief", diff --git a/webapp/src/components/Accordion/index.js b/webapp/src/routes/DelegateReport/delegate-accordion.js similarity index 93% rename from webapp/src/components/Accordion/index.js rename to webapp/src/routes/DelegateReport/delegate-accordion.js index d898295f..5a988354 100644 --- a/webapp/src/components/Accordion/index.js +++ b/webapp/src/routes/DelegateReport/delegate-accordion.js @@ -1,22 +1,22 @@ import React, { memo, useEffect } from 'react' -import PropTypes from 'prop-types' -import Accordion from '@mui/material/Accordion' -import { makeStyles } from '@mui/styles' import AccordionDetails from '@mui/material/AccordionDetails' -import { Alert, Divider, Typography } from '@mui/material' import AccordionSummary from '@mui/material/AccordionSummary' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import { DelegateItem } from '@edenia/ui-kit' +import { Alert, Divider, Typography } from '@mui/material' +import Accordion from '@mui/material/Accordion' import { useTranslation } from 'react-i18next' +import { DelegateItem } from '@edenia/ui-kit' +import { makeStyles } from '@mui/styles' +import PropTypes from 'prop-types' import { formatWithThousandSeparator } from '../../utils' -import DelegateDetails from '../DelegateDetails' import styles from './styles' +import DelegateDetails from './delegate-details' const useStyles = makeStyles(styles) -const AccordionComp = ({ +const DelegateAccordion = ({ accordionList, transactionList, categoryList, @@ -41,7 +41,7 @@ const AccordionComp = ({ return (
{accordionList.length < 1 && searchValue.length > 0 ? ( -
+
{t('invalidEdenMember', { ns: 'routes' })} @@ -96,13 +96,13 @@ const AccordionComp = ({ ) } -AccordionComp.propTypes = { +DelegateAccordion.propTypes = { accordionList: PropTypes.array, transactionList: PropTypes.array, categoryList: PropTypes.array, setDelegateSelect: PropTypes.func, searchValue: PropTypes.string, - electionRoundSelect: PropTypes.number + electionRoundSelect: PropTypes.any } -export default memo(AccordionComp) +export default memo(DelegateAccordion) diff --git a/webapp/src/components/DelegateDetails/index.js b/webapp/src/routes/DelegateReport/delegate-details.js similarity index 96% rename from webapp/src/components/DelegateDetails/index.js rename to webapp/src/routes/DelegateReport/delegate-details.js index 1140fe0f..bb1f3bb5 100644 --- a/webapp/src/components/DelegateDetails/index.js +++ b/webapp/src/routes/DelegateReport/delegate-details.js @@ -18,7 +18,7 @@ const DelegateDetails = ({ categoryList, transactionList }) => {
{!categoryList[0] ? ( -
+
{t('noExpense', { ns: 'generalForm' })} diff --git a/webapp/src/routes/DelegateReport/index.js b/webapp/src/routes/DelegateReport/index.js index ac3dd0c4..de257a60 100644 --- a/webapp/src/routes/DelegateReport/index.js +++ b/webapp/src/routes/DelegateReport/index.js @@ -7,10 +7,10 @@ import { useTranslation } from 'react-i18next' import { Spinner } from '@edenia/ui-kit' import useDelegateReportState from '../../hooks/customHooks/useDelegateReportState' -import AccordionComp from '../../components/Accordion' import TreasuryBalance from '../../components/TreasuryBalance' import SelectComponent from '../../components/Select' +import DelegateAccordion from './delegate-accordion' import styles from './styles' const useStyles = makeStyles(styles) @@ -20,6 +20,7 @@ const DelegateReport = () => { const { t } = useTranslation() const { i18n } = useTranslation('translations') const options = { year: 'numeric', month: 'long', day: 'numeric' } + const [ { electionRoundSelect, @@ -40,10 +41,6 @@ const DelegateReport = () => { options ) - const handleChangeSelectedElection = event => { - setElectionRoundSelect(Number(event)) - } - return (
@@ -73,7 +70,7 @@ const DelegateReport = () => { />
`${data.election}`)} actualValue={electionRoundSelect} @@ -86,7 +83,7 @@ const DelegateReport = () => {
) : ( - ({ [theme.breakpoints.up('sm')]: { textAlign: 'center' } + }, + accordionContainer: { + '& .MuiPaper-root': { + boxShadow: 'none' + }, + '& .MuiAccordionDetails-root': { + padding: theme.spacing(1, 0, 2) + }, + '& .delegate-bp-item-container': { + width: '100%', + borderBottom: 'none' + }, + '& .hideData': { + [theme.breakpoints.down('sm')]: { + display: 'none' + } + } + }, + alertAccordionContainer: { + height: '50vh', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + margin: theme.spacing(4) + }, + verticalLine: { + borderLeft: '1px solid rgba(225,225,225,.99)', + borderBottom: '1px solid rgba(225,225,225,.99)', + marginBottom: theme.spacing(1) + }, + chartContainer: { + display: 'flex', + justifyContent: 'space-between', + [theme.breakpoints.down('md')]: { + justifyContent: 'center', + flexDirection: 'column' + } + }, + pieChartContainer: { + width: '35vw', + [theme.breakpoints.down('md')]: { + width: '100%' + } + }, + alertDetailContainer: { + height: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + margin: theme.spacing(4) } }) diff --git a/webapp/src/routes/ExpenseReport/expense-table-report.js b/webapp/src/routes/ExpenseReport/expense-table-report.js index 02561106..37f4abad 100644 --- a/webapp/src/routes/ExpenseReport/expense-table-report.js +++ b/webapp/src/routes/ExpenseReport/expense-table-report.js @@ -1,13 +1,13 @@ import React, { memo } from 'react' import PropTypes from 'prop-types' -import { useTranslation } from 'react-i18next' import { makeStyles } from '@mui/styles' +import { Typography } from '@mui/material' +import { useTranslation } from 'react-i18next' +import TableReport from '../../components/TableReport' import { formatWithThousandSeparator } from '../../utils' import styles from './styles' -import { Typography } from '@mui/material' -import TableReport from '../../components/TableReport' const useStyles = makeStyles(styles) const rowsCenter = { flex: 1, align: 'center', headerAlign: 'center' } diff --git a/webapp/src/routes/ExpenseReport/index.js b/webapp/src/routes/ExpenseReport/index.js index 5c27a465..de016f9f 100644 --- a/webapp/src/routes/ExpenseReport/index.js +++ b/webapp/src/routes/ExpenseReport/index.js @@ -1,18 +1,13 @@ import React, { memo } from 'react' +import { Divider } from '@mui/material' import { makeStyles } from '@mui/styles' -import { - FormControl, - FormControlLabel, - RadioGroup, - Radio, - Divider -} from '@mui/material' import { useTranslation } from 'react-i18next' import useExpenseReportState from '../../hooks/customHooks/useExpenseReportState' import TreasuryBalance from '../../components/TreasuryBalance' import BarChartReport from '../../components/BarChartReport' import PieChartReport from '../../components/PieChartReport' +import RadioFilter from '../../components/RadioFilter' import SelectComponent from '../../components/Select' import styles from './styles' @@ -56,25 +51,14 @@ const ExpenseReport = () => {
- - setShowElectionRadio(target.value)} - value={showElectionRadio} - > - } - label={t('textRadioButton4', { ns: 'generalForm' })} - value="allElections" - /> - } - label={t('textRadioButton3', { ns: 'generalForm' })} - value="oneElection" - /> - - +
{showElectionRadio === 'oneElection' && (
diff --git a/webapp/src/routes/IncomeReport/index.js b/webapp/src/routes/IncomeReport/index.js index 60a88c59..b11bca84 100644 --- a/webapp/src/routes/IncomeReport/index.js +++ b/webapp/src/routes/IncomeReport/index.js @@ -1,19 +1,14 @@ import React, { memo } from 'react' import { useTranslation } from 'react-i18next' import { makeStyles } from '@mui/styles' -import { - FormControl, - FormControlLabel, - RadioGroup, - Radio, - Divider -} from '@mui/material' +import { Divider } from '@mui/material' import useIncomeReportState from '../../hooks/customHooks/useIncomeReportState' import LineChartReport from '../../components/LineChartReport' import TreasuryBalance from '../../components/TreasuryBalance' import BarChartReport from '../../components/BarChartReport' import PieChartReport from '../../components/PieChartReport' +import RadioFilter from '../../components/RadioFilter' import SelectComponent from '../../components/Select' import TreasuryDisbursementsInfo from './treasury-disbursements-info' @@ -68,25 +63,14 @@ const IncomeReport = () => {
- - setShowElectionRadio(target.value)} - value={showElectionRadio} - > - } - label={t('textRadioButton4', { ns: 'generalForm' })} - value="allElections" - /> - } - label={t('textRadioButton3', { ns: 'generalForm' })} - value="oneElection" - /> - - +
{showElectionRadio === 'oneElection' && ( diff --git a/webapp/src/routes/IncomeReport/treasury-disbursements-info.js b/webapp/src/routes/IncomeReport/treasury-disbursements-info.js index 1b39fc82..b62f991b 100644 --- a/webapp/src/routes/IncomeReport/treasury-disbursements-info.js +++ b/webapp/src/routes/IncomeReport/treasury-disbursements-info.js @@ -95,10 +95,10 @@ const TreasuryDisbursementsInfo = ({

{t('titleDisbursement')}

{t('paragraph1Disbursement')}

{t('paragraph2Disbursement')}

+

{t('paragraph3Disbursement')} {dateFormat}

-

{t('paragraph4Disbursement')}

{electedRanks.map(calculateAndRenderRankLevelComponent)} From 50cf15204b8a2a43bbeedc7b66c0821d7e977aa1 Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Wed, 18 Jan 2023 10:41:59 -0600 Subject: [PATCH 08/16] perf(webapp): stackedBarChart componetization --- .../PieChartReport/custom-pieChart.js | 2 +- .../src/components/PieChartReport/styles.js | 6 +- .../custom-stackedBarChart.js | 139 ++++++++++++++++ .../components/StackedBarChartReport/index.js | 154 ++---------------- .../StackedBarChartReport/styles.js | 4 +- .../routes/DelegateReport/delegate-details.js | 5 +- webapp/src/routes/DelegateReport/index.js | 2 +- webapp/src/routes/DelegateReport/styles.js | 2 +- webapp/src/routes/ExpenseReport/styles.js | 8 +- webapp/src/routes/IncomeReport/index.js | 25 ++- webapp/src/routes/IncomeReport/styles.js | 5 +- 11 files changed, 183 insertions(+), 169 deletions(-) create mode 100644 webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js diff --git a/webapp/src/components/PieChartReport/custom-pieChart.js b/webapp/src/components/PieChartReport/custom-pieChart.js index b14e70be..efde0215 100644 --- a/webapp/src/components/PieChartReport/custom-pieChart.js +++ b/webapp/src/components/PieChartReport/custom-pieChart.js @@ -98,7 +98,7 @@ const CustomPieChart = ({ }, [typeData]) return ( - + ({ chartContainer: { - margin: theme.spacing(6, 6, 6, 6), - [theme.breakpoints.down('sm')]: { - margin: theme.spacing(6, 1, 6, 1) - } + width: '100%', + marginTop: theme.spacing(2) }, title: { '& span': { diff --git a/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js b/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js new file mode 100644 index 00000000..2430089a --- /dev/null +++ b/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js @@ -0,0 +1,139 @@ +import React from 'react' +import { Box } from '@mui/system' +import PropTypes from 'prop-types' +import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import { + ComposedChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + Legend, + ResponsiveContainer, + Cell +} from 'recharts' + +import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' + +import styles from './styles' + +const useStyles = makeStyles(styles) +const legendsList = [ + { color: '#19647e', label: 'claimed' }, + { color: '#ee964b', label: 'categorized' }, + { color: '#f4d35e', label: 'unclaimed' }, + { color: '#28afb0', label: 'uncategorized' } +] + +const RenderChartLegend = () => { + const classes = useStyles() + const { t } = useTranslation('generalForm') + + return ( +
+ {legendsList.map(({ color, label }) => ( + + + {t(label)} + + ))} +
+ ) +} + +const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { + const { t } = useTranslation('generalForm') + label = label + '' + const arrayLabel = label.split(' ') + + return ( +
+ {t(arrayLabel[0].toLocaleLowerCase())} + {payload && + payload.map((data, i) => ( +
+ {`${ + data.payload.category + ? t( + ( + data.dataKey.split('_')[1] + data.payload.category + ).toLocaleLowerCase() + ) + : t(data.dataKey.split('_')[1].toLocaleLowerCase()) + }: ${formatWithThousandSeparator( + data.payload[data.dataKey], + 4 + )} ${coinType}`} +
+ ))} +
+ ) +} + +CustomTooltip.propTypes = { + payload: PropTypes.array, + label: PropTypes.any, + coinType: PropTypes.string +} + +const CustomStackedBarChart = ({ data, barRef, coinType, showLegend }) => { + return ( + + + + + + } + /> + {showLegend && } />} + + {data.map(({ type }) => ( + + ))} + + + {data.map(({ type }) => ( + + ))} + + + + ) +} + +CustomStackedBarChart.propTypes = { + data: PropTypes.array, + barRef: PropTypes.object, + coinType: PropTypes.string, + showLegend: PropTypes.bool +} + +export default CustomStackedBarChart diff --git a/webapp/src/components/StackedBarChartReport/index.js b/webapp/src/components/StackedBarChartReport/index.js index 3e3630fa..d786932e 100644 --- a/webapp/src/components/StackedBarChartReport/index.js +++ b/webapp/src/components/StackedBarChartReport/index.js @@ -1,8 +1,11 @@ import React, { memo, useCallback, useState, useEffect } from 'react' import PropTypes from 'prop-types' import FileSaver from 'file-saver' -import { Box } from '@mui/system' import { makeStyles } from '@mui/styles' +import { useTranslation } from 'react-i18next' +import { useCurrentPng } from 'recharts-to-png' +import TooltipDownload from '@mui/material/Tooltip' +import DownloadOutlined from '@mui/icons-material/DownloadOutlined' import { IconButton, Typography, @@ -10,107 +13,12 @@ import { Switch, FormGroup } from '@mui/material' -import TooltipDownload from '@mui/material/Tooltip' -import DownloadOutlined from '@mui/icons-material/DownloadOutlined' -import { useTranslation } from 'react-i18next' -import { useCurrentPng } from 'recharts-to-png' -import { - ComposedChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - Legend, - ResponsiveContainer, - Cell -} from 'recharts' - -import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' import styles from './styles' +import CustomStackedBarChart from './custom-stackedBarChart' const useStyles = makeStyles(styles) -const RenderChartLegend = () => { - const classes = useStyles() - const { t } = useTranslation() - - return ( - - ) -} - -const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { - const { t } = useTranslation() - label = label + '' - const arrayLabel = label.split(' ') - - return ( -
- - {`${t(arrayLabel[0].toLocaleLowerCase(), { ns: 'generalForm' })}`} - - {payload && - payload.map((data, i) => ( -
-
- {`${ - data.payload.category - ? t( - ( - data.dataKey.split('_')[1] + data.payload.category - ).toLocaleLowerCase(), - { - ns: 'generalForm' - } - ) - : t(data.dataKey.split('_')[1].toLocaleLowerCase(), { - ns: 'generalForm' - }) - }: ${formatWithThousandSeparator( - data.payload[data.dataKey], - 4 - )} ${coinType}`} -
-
- {i === 0 && - data.payload?.date && - `${ - data.payload.date ? t('date', { ns: 'generalForm' }) : '' - }: ${ - data.payload.date ? data.payload.date.split('T')[0] : '' - } `} -
-
- ))} -
- ) -} - -CustomTooltip.propTypes = { - payload: PropTypes.array, - label: PropTypes.any, - coinType: PropTypes.string -} - const StackedBarChartReport = ({ data, keyTranslation, @@ -162,52 +70,12 @@ const StackedBarChartReport = ({
- - - - - - - } - /> - {showLegend && } />} - - {data.map(({ type }) => ( - - ))} - - - {data.map(({ type }) => ( - - ))} - - - +
) } diff --git a/webapp/src/components/StackedBarChartReport/styles.js b/webapp/src/components/StackedBarChartReport/styles.js index c14bd6cb..c9b5bf5b 100644 --- a/webapp/src/components/StackedBarChartReport/styles.js +++ b/webapp/src/components/StackedBarChartReport/styles.js @@ -1,6 +1,7 @@ export default theme => ({ chartContainer: { - margin: theme.spacing(2, 0, 2, 0) + marginTop: theme.spacing(2), + width: '100%' }, title: { '& span': { @@ -24,6 +25,7 @@ export default theme => ({ alignItems: 'center' }, chartLegent: { + marginLeft: theme.spacing(3), display: 'flex', justifyContent: 'center', flexWrap: 'wrap', diff --git a/webapp/src/routes/DelegateReport/delegate-details.js b/webapp/src/routes/DelegateReport/delegate-details.js index bb1f3bb5..0a2ba5f5 100644 --- a/webapp/src/routes/DelegateReport/delegate-details.js +++ b/webapp/src/routes/DelegateReport/delegate-details.js @@ -1,11 +1,12 @@ import React, { memo } from 'react' -import PropTypes from 'prop-types' -import { Alert } from '@mui/material' import { useTranslation } from 'react-i18next' import { makeStyles } from '@mui/styles' +import { Alert } from '@mui/material' +import PropTypes from 'prop-types' import StackedBarChartReport from '../../components/StackedBarChartReport' import PieChartReport from '../../components/PieChartReport' + import styles from './styles' const useStyles = makeStyles(styles) diff --git a/webapp/src/routes/DelegateReport/index.js b/webapp/src/routes/DelegateReport/index.js index de257a60..f3427a8d 100644 --- a/webapp/src/routes/DelegateReport/index.js +++ b/webapp/src/routes/DelegateReport/index.js @@ -1,9 +1,9 @@ import React, { memo } from 'react' import Autocomplete from '@mui/material/Autocomplete' import TextField from '@mui/material/TextField' +import { useTranslation } from 'react-i18next' import { Typography } from '@mui/material' import { makeStyles } from '@mui/styles' -import { useTranslation } from 'react-i18next' import { Spinner } from '@edenia/ui-kit' import useDelegateReportState from '../../hooks/customHooks/useDelegateReportState' diff --git a/webapp/src/routes/DelegateReport/styles.js b/webapp/src/routes/DelegateReport/styles.js index cb7daabd..3a73c4ef 100644 --- a/webapp/src/routes/DelegateReport/styles.js +++ b/webapp/src/routes/DelegateReport/styles.js @@ -93,7 +93,7 @@ export default theme => ({ }, chartContainer: { display: 'flex', - justifyContent: 'space-between', + justifyContent: 'space-around', [theme.breakpoints.down('md')]: { justifyContent: 'center', flexDirection: 'column' diff --git a/webapp/src/routes/ExpenseReport/styles.js b/webapp/src/routes/ExpenseReport/styles.js index 6e12a117..3b93253d 100644 --- a/webapp/src/routes/ExpenseReport/styles.js +++ b/webapp/src/routes/ExpenseReport/styles.js @@ -24,10 +24,13 @@ export default theme => ({ marginTop: theme.spacing(2), '& #id-radio-election-container': { display: 'flex', - marginLeft: '12px', justifyContent: 'end', alignItems: 'center' }, + '& .MuiFormControlLabel-root': { + marginRight: 0, + marginLeft: theme.spacing(2) + }, '& span': { fontSize: '12px', fontWeight: 300, @@ -37,7 +40,8 @@ export default theme => ({ }, chartContainer: { display: 'flex', - justifyContent: 'space-between', + justifyContent: 'space-around', + marginBottom: theme.spacing(4), [theme.breakpoints.down('md')]: { justifyContent: 'center', flexDirection: 'column' diff --git a/webapp/src/routes/IncomeReport/index.js b/webapp/src/routes/IncomeReport/index.js index b11bca84..b70b1286 100644 --- a/webapp/src/routes/IncomeReport/index.js +++ b/webapp/src/routes/IncomeReport/index.js @@ -53,6 +53,7 @@ const IncomeReport = () => { keyTranslation={'titleLineChart'} pathTranslation={'incomeRoute'} /> + { defaultValue={showElectionRadio} />
-
- {showElectionRadio === 'oneElection' && ( - <> - `${data.election}`)} - actualValue={electionRoundSelect} - size="small" - /> - - )} -
+ {showElectionRadio === 'oneElection' && ( +
+ `${data.election}`)} + actualValue={electionRoundSelect} + size="small" + /> +
+ )}
({ marginTop: theme.spacing(2), '& #id-radio-election-container': { display: 'flex', - marginLeft: theme.spacing(2), justifyContent: 'end', alignItems: 'center' }, + '& .MuiFormControlLabel-root': { + marginRight: 0, + marginLeft: theme.spacing(2) + }, '& span': { fontSize: '12px', fontWeight: 300, From 644eeecc05b099acc4a1de7bdd17355a3b18203d Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Wed, 18 Jan 2023 14:57:48 -0600 Subject: [PATCH 09/16] perf(webapp): barChart refactor code and componetization --- .../BarChartReport/custom-barChart.js | 139 ++++-------------- .../BarChartReport/custom-tooltip-barChart.js | 43 ++++++ webapp/src/components/BarChartReport/index.js | 3 - webapp/src/gql/eden-expense.gql.js | 2 +- webapp/src/gql/eden-income.gql.js | 2 +- webapp/src/routes/ExpenseReport/index.js | 1 - webapp/src/routes/IncomeReport/index.js | 1 - 7 files changed, 77 insertions(+), 114 deletions(-) create mode 100644 webapp/src/components/BarChartReport/custom-tooltip-barChart.js diff --git a/webapp/src/components/BarChartReport/custom-barChart.js b/webapp/src/components/BarChartReport/custom-barChart.js index d3ff645a..da053824 100644 --- a/webapp/src/components/BarChartReport/custom-barChart.js +++ b/webapp/src/components/BarChartReport/custom-barChart.js @@ -11,33 +11,31 @@ import { CartesianGrid, Tooltip, Legend, - ResponsiveContainer, - Cell + ResponsiveContainer } from 'recharts' +import CustomTooltipBarChart from './custom-tooltip-barChart' import styles from './styles' -import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' const useStyles = makeStyles(styles) +const legentsList = [ + { color: '#f4d35e', label: 'un' }, + { color: '#ee964b', label: '' }, + { color: '#19647e', label: 'total' } +] const RenderChartLegend = ({ data }) => { const classes = useStyles() - const { t } = useTranslation() + const { t } = useTranslation('generalForm') return ( ) } @@ -46,70 +44,15 @@ RenderChartLegend.propTypes = { data: PropTypes.string } -const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { - const { t } = useTranslation() - label = label + '' - const arrayLabel = label.split(' ') - - return ( -
- - {`${t(arrayLabel[0].toLocaleLowerCase(), { ns: 'generalForm' })} ${ - arrayLabel[1] - }`} - - {payload && - payload.map((data, i) => ( -
-
- {i === 0 && - data.payload?.date && - `${ - data.payload.date ? t('date', { ns: 'generalForm' }) : '' - }: ${ - data.payload.date ? data.payload.date.split('T')[0] : '' - } `} -
-
- {`${t( - data.payload.category - ? `${data.dataKey - .split('_')[1] - .toLocaleLowerCase()}${data.payload.category.toLocaleLowerCase()}` - : data.dataKey.split('_')[1].toLocaleLowerCase(), - { ns: 'generalForm' } - )}: ${formatWithThousandSeparator( - data.payload[data.dataKey], - 4 - )} ${coinType}`} -
-
- ))} -
- ) -} - -CustomTooltip.propTypes = { - payload: PropTypes.array, - label: PropTypes.any, - coinType: PropTypes.string -} - const width = window.innerWidth -const CustomBarChart = ({ - typeData, - selectedUSD, - data, - barRef, - showLegend -}) => { +const CustomBarChart = ({ typeData, selectedUSD, data, barRef }) => { const [category, setCategory] = useState('') const [coinType, setCoinType] = useState('EOS') useEffect(() => { - if (typeData === 'income') setCategory('Claimed') - else setCategory('Categorized') + if (typeData === 'income') setCategory('claimed') + else setCategory('categorized') }, [typeData]) useEffect(() => { @@ -134,38 +77,21 @@ const CustomBarChart = ({ fontSize: '14px', padding: '8px' }} - content={} + content={ + + } /> - {showLegend && ( - } /> - )} - 600 ? 35 : 15} - fill="#f4d35e" - > - {data.map(({ election }) => ( - - ))} - - 600 ? 35 : 15} - fill="#ee964b" - > - {data.map(({ election }) => ( - - ))} - - 600 ? 35 : 15} - fill="#19647e" - > - {data.map(({ election }) => ( - - ))} - + } /> + {legentsList.map(({ color, label }) => ( + 600 ? 35 : 15} + fill={color} + /> + ))} ) @@ -175,8 +101,7 @@ CustomBarChart.propTypes = { typeData: PropTypes.string, selectedUSD: PropTypes.any, data: PropTypes.array, - barRef: PropTypes.object, - showLegend: PropTypes.bool + barRef: PropTypes.object } export default memo(CustomBarChart) diff --git a/webapp/src/components/BarChartReport/custom-tooltip-barChart.js b/webapp/src/components/BarChartReport/custom-tooltip-barChart.js new file mode 100644 index 00000000..18bd7811 --- /dev/null +++ b/webapp/src/components/BarChartReport/custom-tooltip-barChart.js @@ -0,0 +1,43 @@ +import React, { memo } from 'react' +import { useTranslation } from 'react-i18next' +import PropTypes from 'prop-types' + +import { formatWithThousandSeparator } from '../../utils' + +const CustomTooltipBarChart = ({ payload = [], label, coinType, category }) => { + const { t } = useTranslation('generalForm') + label = label + '' + const arrayLabel = label.split(' ') + + if (!payload[0]) return null + + return ( + <> + + {`${t(arrayLabel[0].toLocaleLowerCase())} ${arrayLabel[1]}`} + +
{`${t('date')}: ${payload[0]?.payload?.date?.split('T')[0]}`}
+
{`${t(`un${category}`)}: ${formatWithThousandSeparator( + payload[0]?.payload[`${coinType}_UN${category.toLocaleUpperCase()}`], + 4 + )}`}
+
{`${t(category)}: ${formatWithThousandSeparator( + payload[0]?.payload[`${coinType}_${category.toLocaleUpperCase()}`], + 4 + )}`}
+
{`${t('total')}: ${formatWithThousandSeparator( + payload[0]?.payload[`${coinType}_TOTAL`], + 4 + )}`}
+ + ) +} + +CustomTooltipBarChart.propTypes = { + payload: PropTypes.array, + label: PropTypes.any, + coinType: PropTypes.string, + category: PropTypes.string +} + +export default memo(CustomTooltipBarChart) diff --git a/webapp/src/components/BarChartReport/index.js b/webapp/src/components/BarChartReport/index.js index 67682cbe..705ad475 100644 --- a/webapp/src/components/BarChartReport/index.js +++ b/webapp/src/components/BarChartReport/index.js @@ -23,7 +23,6 @@ const BarChartReport = ({ data, keyTranslation, pathTranslation, - showLegend, typeData }) => { const classes = useStyles() @@ -69,7 +68,6 @@ const BarChartReport = ({
{ data={expenseByElectionsList} keyTranslation={'titleBarChart'} pathTranslation={'expenseRoute'} - showLegend={true} typeData={'expense'} /> diff --git a/webapp/src/routes/IncomeReport/index.js b/webapp/src/routes/IncomeReport/index.js index b70b1286..97827f9b 100644 --- a/webapp/src/routes/IncomeReport/index.js +++ b/webapp/src/routes/IncomeReport/index.js @@ -58,7 +58,6 @@ const IncomeReport = () => { data={incomeByElectionsList} keyTranslation={'titleBarChart'} pathTranslation={'incomeRoute'} - showLegend={true} typeData={'income'} /> From 5decfdf3f08172c0cf3e26cbb0269c7adb1dbe0d Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Wed, 18 Jan 2023 15:41:35 -0600 Subject: [PATCH 10/16] perf(webapp) stackedBarChart refactor code and componetization --- .../custom-stackedBarChart.js | 40 +---------------- .../custom-tooltip-stackedBarChart.js | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 webapp/src/components/StackedBarChartReport/custom-tooltip-stackedBarChart.js diff --git a/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js b/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js index 2430089a..25b8feee 100644 --- a/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js +++ b/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js @@ -15,9 +15,8 @@ import { Cell } from 'recharts' -import { formatWithThousandSeparator } from '../../utils/format-with-thousand-separator' - import styles from './styles' +import CustomTooltipStackedBarChart from './custom-tooltip-stackedBarChart' const useStyles = makeStyles(styles) const legendsList = [ @@ -43,41 +42,6 @@ const RenderChartLegend = () => { ) } -const CustomTooltip = ({ payload = [], label = '', coinType = '' }) => { - const { t } = useTranslation('generalForm') - label = label + '' - const arrayLabel = label.split(' ') - - return ( -
- {t(arrayLabel[0].toLocaleLowerCase())} - {payload && - payload.map((data, i) => ( -
- {`${ - data.payload.category - ? t( - ( - data.dataKey.split('_')[1] + data.payload.category - ).toLocaleLowerCase() - ) - : t(data.dataKey.split('_')[1].toLocaleLowerCase()) - }: ${formatWithThousandSeparator( - data.payload[data.dataKey], - 4 - )} ${coinType}`} -
- ))} -
- ) -} - -CustomTooltip.propTypes = { - payload: PropTypes.array, - label: PropTypes.any, - coinType: PropTypes.string -} - const CustomStackedBarChart = ({ data, barRef, coinType, showLegend }) => { return ( @@ -105,7 +69,7 @@ const CustomStackedBarChart = ({ data, barRef, coinType, showLegend }) => { fontSize: '14px', padding: '8px' }} - content={} + content={} /> {showLegend && } />} diff --git a/webapp/src/components/StackedBarChartReport/custom-tooltip-stackedBarChart.js b/webapp/src/components/StackedBarChartReport/custom-tooltip-stackedBarChart.js new file mode 100644 index 00000000..aaf85a39 --- /dev/null +++ b/webapp/src/components/StackedBarChartReport/custom-tooltip-stackedBarChart.js @@ -0,0 +1,43 @@ +import React, { memo } from 'react' +import PropTypes from 'prop-types' +import { useTranslation } from 'react-i18next' + +import { formatWithThousandSeparator } from '../../utils' + +const CustomTooltipStakedBarChart = ({ + payload = [], + label = '', + coinType = '' +}) => { + const { t } = useTranslation('generalForm') + label = label + '' + const arrayLabel = label.split(' ') + + if (!payload[0]) return null + + return ( + <> + {t(arrayLabel[0].toLocaleLowerCase())} +
{`${t( + payload[0]?.payload.category.toLocaleLowerCase() + )}: ${formatWithThousandSeparator( + payload[0]?.payload[`${coinType}_`], + 4 + )} ${coinType}`}
+
{`${t( + `un${payload[0]?.payload.category.toLocaleLowerCase()}` + )}: ${formatWithThousandSeparator( + payload[0]?.payload[`${coinType}_UN`], + 4 + )} ${coinType}`}
+ + ) +} + +CustomTooltipStakedBarChart.propTypes = { + payload: PropTypes.array, + label: PropTypes.any, + coinType: PropTypes.string +} + +export default memo(CustomTooltipStakedBarChart) From affcdcb38145f59e97a1c74bc9f954621e68ae43 Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Wed, 18 Jan 2023 17:01:37 -0600 Subject: [PATCH 11/16] fix(webapp): fix dimentions projected disbursement in mobile --- .../BarChartReport/custom-barChart.js | 7 +++++- .../src/components/BarChartReport/styles.js | 5 +---- .../LineChartReport/custom-lineChart.js | 2 +- .../src/components/LineChartReport/styles.js | 5 +---- webapp/src/routes/IncomeReport/styles.js | 22 ++++++++++++++++--- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/webapp/src/components/BarChartReport/custom-barChart.js b/webapp/src/components/BarChartReport/custom-barChart.js index da053824..88a0dd32 100644 --- a/webapp/src/components/BarChartReport/custom-barChart.js +++ b/webapp/src/components/BarChartReport/custom-barChart.js @@ -61,7 +61,12 @@ const CustomBarChart = ({ typeData, selectedUSD, data, barRef }) => { return ( - + ({ root: { - margin: theme.spacing(6, 6, 6, 6), - [theme.breakpoints.down('sm')]: { - margin: theme.spacing(6, 1, 6, 1) - } + margin: theme.spacing(3, 0, 3, 0) }, chartContainer: { whiteSpace: 'nowrap', diff --git a/webapp/src/components/LineChartReport/custom-lineChart.js b/webapp/src/components/LineChartReport/custom-lineChart.js index 16607127..2f8567d2 100644 --- a/webapp/src/components/LineChartReport/custom-lineChart.js +++ b/webapp/src/components/LineChartReport/custom-lineChart.js @@ -67,7 +67,7 @@ const CustomLineChart = ({ selectedUSD, data, lineRef }) => { return ( - + ({ root: { - margin: theme.spacing(6, 6, 6, 6), - [theme.breakpoints.down('sm')]: { - margin: theme.spacing(6, 1, 6, 1) - } + margin: theme.spacing(3, 0, 3, 0) }, chartContainer: { whiteSpace: 'nowrap', diff --git a/webapp/src/routes/IncomeReport/styles.js b/webapp/src/routes/IncomeReport/styles.js index 1ab77259..62d86300 100644 --- a/webapp/src/routes/IncomeReport/styles.js +++ b/webapp/src/routes/IncomeReport/styles.js @@ -73,14 +73,30 @@ export default theme => ({ disbursementsContainer: { display: 'flex', justifyContent: 'center', - marginBottom: theme.spacing(3) + marginBottom: theme.spacing(3), + [theme.breakpoints.down('sm')]: { + flexDirection: 'column', + alignItems: 'center' + } }, disbursementBox: { - margin: theme.spacing(0, 2, 0, 2) + margin: theme.spacing(0, 2, 0, 2), + textAlign: 'center', + [theme.breakpoints.down('sm')]: { + paddingTop: theme.spacing(2) + } }, rankLevelBox: { margin: theme.spacing(0, 2, 0, 2), borderRight: '1px solid rgba(0, 0, 0, 0.12)', - paddingRight: theme.spacing(3) + paddingRight: theme.spacing(3), + textAlign: 'center', + [theme.breakpoints.down('sm')]: { + width: '100%', + borderBottom: '1px solid rgba(0, 0, 0, 0.12)', + borderRight: 'none', + paddingRight: 0, + paddingTop: theme.spacing(2) + } } }) From 9b8d93aa8f6759edcc50d47a8f061ad74d597f5c Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Wed, 18 Jan 2023 17:29:18 -0600 Subject: [PATCH 12/16] fix(webapp): fix margen --- webapp/src/components/BarChartReport/custom-barChart.js | 4 +--- .../components/BarChartReport/custom-tooltip-barChart.js | 4 ++-- .../StackedBarChartReport/custom-stackedBarChart.js | 2 +- .../custom-tooltip-stackedBarChart.js | 8 ++------ 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/webapp/src/components/BarChartReport/custom-barChart.js b/webapp/src/components/BarChartReport/custom-barChart.js index 88a0dd32..913df831 100644 --- a/webapp/src/components/BarChartReport/custom-barChart.js +++ b/webapp/src/components/BarChartReport/custom-barChart.js @@ -44,8 +44,6 @@ RenderChartLegend.propTypes = { data: PropTypes.string } -const width = window.innerWidth - const CustomBarChart = ({ typeData, selectedUSD, data, barRef }) => { const [category, setCategory] = useState('') const [coinType, setCoinType] = useState('EOS') @@ -93,7 +91,7 @@ const CustomBarChart = ({ typeData, selectedUSD, data, barRef }) => { dataKey={`${coinType}_${label.toLocaleUpperCase()}${ label === 'total' ? '' : category.toLocaleUpperCase() }`} - barSize={width > 600 ? 35 : 15} + barSize={35} fill={color} /> ))} diff --git a/webapp/src/components/BarChartReport/custom-tooltip-barChart.js b/webapp/src/components/BarChartReport/custom-tooltip-barChart.js index 18bd7811..228e8545 100644 --- a/webapp/src/components/BarChartReport/custom-tooltip-barChart.js +++ b/webapp/src/components/BarChartReport/custom-tooltip-barChart.js @@ -4,12 +4,12 @@ import PropTypes from 'prop-types' import { formatWithThousandSeparator } from '../../utils' -const CustomTooltipBarChart = ({ payload = [], label, coinType, category }) => { +const CustomTooltipBarChart = ({ payload, label, coinType, category }) => { const { t } = useTranslation('generalForm') label = label + '' const arrayLabel = label.split(' ') - if (!payload[0]) return null + if (!payload) return null return ( <> diff --git a/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js b/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js index 25b8feee..efca8fc8 100644 --- a/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js +++ b/webapp/src/components/StackedBarChartReport/custom-stackedBarChart.js @@ -80,7 +80,7 @@ const CustomStackedBarChart = ({ data, barRef, coinType, showLegend }) => { /> ))}
- + {data.map(({ type }) => ( { +const CustomTooltipStakedBarChart = ({ payload, label, coinType }) => { const { t } = useTranslation('generalForm') label = label + '' const arrayLabel = label.split(' ') - if (!payload[0]) return null + if (!payload) return null return ( <> From eb6b26914bea280e44874d76b39b622c409e4f0c Mon Sep 17 00:00:00 2001 From: warnerHurtado Date: Mon, 23 Jan 2023 09:57:19 -0600 Subject: [PATCH 13/16] fix(webapp): improve ui ux treasury balance chart --- .../LineChartReport/custom-lineChart.js | 94 +++++++++++++++++-- .../src/components/LineChartReport/index.js | 86 ++++++++++++++++- .../src/components/LineChartReport/styles.js | 11 +++ webapp/src/components/Sidebar/index.js | 27 ++++-- .../hooks/customHooks/useIncomeReportState.js | 6 +- webapp/src/routes/Home/styles.js | 1 - webapp/src/routes/IncomeReport/index.js | 4 +- webapp/src/utils/new-format-objects.js | 2 +- 8 files changed, 205 insertions(+), 26 deletions(-) diff --git a/webapp/src/components/LineChartReport/custom-lineChart.js b/webapp/src/components/LineChartReport/custom-lineChart.js index 891e8254..e7ee57f7 100644 --- a/webapp/src/components/LineChartReport/custom-lineChart.js +++ b/webapp/src/components/LineChartReport/custom-lineChart.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react' +import React, { memo, useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import { XAxis, @@ -13,13 +13,68 @@ import { import CustomTooltipLineChart from './custom-tooltip-lineChart' -const width = window.innerWidth +const renderTraveller = props => { + const { x, y, width } = props + + return ( + + ) +} const CustomLineChart = ({ coinType, data, lineRef }) => { + const widthRef = useRef(null) + const [width, setWidth] = useState(window.innerWidth) + const [countData, setCountData] = useState(data.length) + const [xAxisData, setXAxisData] = useState(width > 600 ? 40 : 80) + + const handleBrushChange = data => { + const count = data.endIndex - data.startIndex + setCountData(count + 1) + } + + useEffect(() => { + setCountData(data.length) + }, [data]) + + useEffect(() => { + if (countData === 0) return + if (countData > 200) setXAxisData(Math.round(countData * 0.25)) + if (width > 600) { + if (countData < 200) setXAxisData(Math.round(countData * 0.1)) + } else { + if (countData < 200) setXAxisData(Math.round(countData * 0.25)) + } + }, [countData, width]) + + useEffect(() => { + setWidth(widthRef.current.current.clientWidth) + const handleResize = () => { + setWidth(widthRef.current.current.clientWidth) + } + + window.addEventListener('resize', handleResize) + + return () => { + window.removeEventListener('resize', handleResize) + } + }) + return ( - + { tick={{ fontSize: 10, stroke: '#000', strokeWidth: 0.5 }} dataKey="date" scale="auto" - interval={width > 600 ? 40 : 80} + interval={xAxisData} allowDataOverflow={false} /> { /> 600 ? width * 0.4 : 100} - height={20} - x={width > 600 ? width * 0.2 : 150} - /> + width={width * 0.7} + height={30} + x={width / 6.2} + traveller={renderTraveller} + travellerWidth={1} + onChange={handleBrushChange} + > + + + + + ) diff --git a/webapp/src/components/LineChartReport/index.js b/webapp/src/components/LineChartReport/index.js index 571ae1bc..332ebffc 100644 --- a/webapp/src/components/LineChartReport/index.js +++ b/webapp/src/components/LineChartReport/index.js @@ -11,20 +11,31 @@ import { Typography, FormControlLabel, Switch, - FormGroup + FormGroup, + Button } from '@mui/material' +import Select from '../Select' + import styles from './styles' import CustomLineChart from './custom-lineChart' const useStyles = makeStyles(styles) -const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { +const LineChartReport = ({ + data, + keyTranslation, + pathTranslation, + historicElections +}) => { const classes = useStyles() const [getBarPng, { ref: lineRef }] = useCurrentPng() const { t } = useTranslation() const [selectedUSD, setSelected] = useState(false) const [coinType, setCoinType] = useState('EOS') + const [viewSelected, setViewSelect] = useState('') + const [dataChart, setDataChart] = useState([]) + const [electionRoundSelect, setElectionRoundSelect] = useState('') const handleChange = event => { setSelected(event.target.checked) @@ -38,6 +49,14 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { } }, [getBarPng]) + const handleSelectElection = e => { + setViewSelect(e.target.value) + } + + useEffect(() => { + setDataChart(data) + }, [data]) + useEffect(() => { if (selectedUSD) { setCoinType('USD') @@ -46,6 +65,31 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => { } }, [selectedUSD]) + useEffect(() => { + if (viewSelected === 'last') { + const count = historicElections.length - 2 || 0 + const date = historicElections?.at(count)?.date_election.split('T')[0] + const subData = data?.filter(obj => obj.date >= date) + setDataChart(subData) + } + if (viewSelected === 'all') setDataChart(data) + }, [viewSelected]) + + useEffect(() => { + if (!electionRoundSelect) return + const index = historicElections.findIndex( + election => Number(election.election) === Number(electionRoundSelect) + ) + const subData = data?.filter( + objt => + objt.date >= historicElections[index].date_election && + objt.date <= historicElections[index + 1]?.date_election + ) + setViewSelect(electionRoundSelect) + + setDataChart(subData) + }, [electionRoundSelect]) + return (
@@ -69,8 +113,41 @@ const LineChartReport = ({ data, keyTranslation, pathTranslation }) => {
+
+
+ + + +
+ `${data.election}`)} actualValue={electionRoundSelect} width={110} diff --git a/webapp/src/language/en.json b/webapp/src/language/en.json index 0ae14e85..e8878777 100644 --- a/webapp/src/language/en.json +++ b/webapp/src/language/en.json @@ -94,7 +94,7 @@ "trasury": "Projected Treasury Balance", "delegate": "Delegate", "balance": "Treasury Balance", - "estimated": "Estimated Treasury Balance" + "estimated": "Estimated Balance" }, "expenseRoute": { "titleBarChart": "Expense per Election", diff --git a/webapp/src/language/es.json b/webapp/src/language/es.json index 594d86c1..e77ef320 100644 --- a/webapp/src/language/es.json +++ b/webapp/src/language/es.json @@ -95,7 +95,7 @@ "trasury": "Balance de tesorería proyectado", "delegate": "Delegate", "balance": "Saldo de Tesorería", - "estimated": "Balance de Tesorería Estimado" + "estimated": "Balance Estimado" }, "expenseRoute": { "titleBarChart": "Gasto por Elección",