From 0a9a719d734a4a8da6226469455c72dbd9f0bf55 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 14:27:07 +0300 Subject: [PATCH 1/8] PoC --- GUI/src/components/BarGraph/index.tsx | 40 ++++++++++++++++++- .../components/PieGraph/PieCharLegends.tsx | 30 +++++++------- GUI/src/util/charts-utils.tsx | 20 ++++++++++ 3 files changed, 73 insertions(+), 17 deletions(-) diff --git a/GUI/src/components/BarGraph/index.tsx b/GUI/src/components/BarGraph/index.tsx index e58e632c..614f2a5b 100644 --- a/GUI/src/components/BarGraph/index.tsx +++ b/GUI/src/components/BarGraph/index.tsx @@ -1,8 +1,18 @@ import React, { useEffect, useRef, useState } from 'react'; import { BarChart, CartesianGrid, YAxis, Tooltip, Legend, Bar, Label, XAxis } from 'recharts'; -import { chartDataKey, dateFormatter, formatDate, getColor, getKeys, getTicks, round } from '../../util/charts-utils'; +import { + chartDataKey, + dateFormatter, + formatDate, + getColor, + getKeys, + getPeriodTotalCounts, + getTicks, + round, +} from '../../util/charts-utils'; import { GroupByPeriod } from '../MetricAndPeriodOptions/types'; import { useTranslation } from 'react-i18next'; +import { use } from 'i18next'; type Props = { data: any; @@ -14,6 +24,7 @@ type Props = { const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeriod }) => { const [width, setWidth] = useState(null); + const [totalPeriodCounts, setTotalPeriodCounts] = useState>({}); const ref = useRef(null); const { t } = useTranslation(); @@ -32,6 +43,18 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri minDate = minDate - millisecondInOneDay; } + useEffect(() => { + // todo does not update when changing period + console.log('hook', data.chartData); + const totals = getPeriodTotalCounts(data.chartData); + console.log('totals', totals); + setTotalPeriodCounts(totals); + }, [data.chartData]); + + // console.log('data', data.chartData); + // console.log(unit); + // console.log('PERIOD COUNTS', getPeriodTotalCounts(data.chartData)); + const domain = [minDate, new Date(endDate).getTime()]; const ticks = getTicks(startDate, endDate, new Date(startDate), new Date(endDate), 5); @@ -84,7 +107,20 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri }} cursor={false} /> - + { + // const totals = getPeriodTotalCounts(data.chartData); + console.log('totalPeriodCounts', totalPeriodCounts); + console.log('totalPeriodCounts[value]', totalPeriodCounts[value]); + // console.log('entry', entry); + // console.log('index', index); + return `${value}${totalPeriodCounts[value] ? ` (${totalPeriodCounts[value]})` : ''}`; + + // return `${value}${Object.keys(totalPeriodCounts).includes(value) ? ` (${totalPeriodCounts[value]})` : ''}`; + }} + // accumulate="sum" + /> {data?.chartData?.length > 0 && getKeys(data.chartData).map((k, i) => { const isCount = k === t('chats.totalCount'); diff --git a/GUI/src/components/PieGraph/PieCharLegends.tsx b/GUI/src/components/PieGraph/PieCharLegends.tsx index 8d2951c0..55103993 100644 --- a/GUI/src/components/PieGraph/PieCharLegends.tsx +++ b/GUI/src/components/PieGraph/PieCharLegends.tsx @@ -9,6 +9,9 @@ type Props = { }; const PieCharLegends = ({ data, percentages }: Props) => { + console.log('percentages', percentages); + console.log('data', data); + return ( { isFlex isMultiline > - { - percentages?.map((e: any) => { - const color = getColor(data, e.name); + {percentages?.map((e: any) => { + const color = getColor(data, e.name); - return ( - -
- - - )}) - } + return ( + +
+ + + ); + })} ); }; diff --git a/GUI/src/util/charts-utils.tsx b/GUI/src/util/charts-utils.tsx index 07e3bc9e..906256c0 100644 --- a/GUI/src/util/charts-utils.tsx +++ b/GUI/src/util/charts-utils.tsx @@ -52,3 +52,23 @@ export const chartDataKey = 'dateTime'; export const round = (value: any) => Math.round(Number(value) * 100) / 100; export const getKeys = (data: any[]) => Array.from(new Set(data.flatMap((obj: any) => Object.keys(obj)))); + +export const getPeriodTotalCounts = (chartData: Record[]) => { + const totals: Record = {}; + console.log('chartData in COUNT', chartData); + + // todo handle this and empty array + if (!chartData) return {}; + + chartData.forEach((entry) => { + Object.entries(entry).forEach(([key, value]) => { + if (key !== 'dateTime') { + totals[key] = (totals[key] ?? 0) + value; + } + }); + }); + + console.log('totals', totals); + + return totals; +}; From 452eb8f6ce5117a11a10823624ddf3572201cf98 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 14:38:16 +0300 Subject: [PATCH 2/8] Add condition --- GUI/src/components/BarGraph/index.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/GUI/src/components/BarGraph/index.tsx b/GUI/src/components/BarGraph/index.tsx index 614f2a5b..d5330ac2 100644 --- a/GUI/src/components/BarGraph/index.tsx +++ b/GUI/src/components/BarGraph/index.tsx @@ -44,17 +44,14 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri } useEffect(() => { - // todo does not update when changing period - console.log('hook', data.chartData); + console.log('unit', unit); + // todo use t + if (unit !== 'vestlused') return; + const totals = getPeriodTotalCounts(data.chartData); - console.log('totals', totals); setTotalPeriodCounts(totals); }, [data.chartData]); - // console.log('data', data.chartData); - // console.log(unit); - // console.log('PERIOD COUNTS', getPeriodTotalCounts(data.chartData)); - const domain = [minDate, new Date(endDate).getTime()]; const ticks = getTicks(startDate, endDate, new Date(startDate), new Date(endDate), 5); From f2b3577b030d6ca20bbe6b9ab5b117819aaa6c40 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 14:39:45 +0300 Subject: [PATCH 3/8] Clean up --- GUI/src/components/BarGraph/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GUI/src/components/BarGraph/index.tsx b/GUI/src/components/BarGraph/index.tsx index d5330ac2..a671074b 100644 --- a/GUI/src/components/BarGraph/index.tsx +++ b/GUI/src/components/BarGraph/index.tsx @@ -108,8 +108,8 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri wrapperStyle={{ position: 'relative', marginTop: '20px' }} formatter={(value) => { // const totals = getPeriodTotalCounts(data.chartData); - console.log('totalPeriodCounts', totalPeriodCounts); - console.log('totalPeriodCounts[value]', totalPeriodCounts[value]); + // console.log('totalPeriodCounts', totalPeriodCounts); + // console.log('totalPeriodCounts[value]', totalPeriodCounts[value]); // console.log('entry', entry); // console.log('index', index); return `${value}${totalPeriodCounts[value] ? ` (${totalPeriodCounts[value]})` : ''}`; From de2cbbc1cde713027bfbb61ba58e27d2e561c9c4 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 14:46:50 +0300 Subject: [PATCH 4/8] Use translation --- GUI/src/components/BarGraph/index.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/GUI/src/components/BarGraph/index.tsx b/GUI/src/components/BarGraph/index.tsx index a671074b..b365f9d0 100644 --- a/GUI/src/components/BarGraph/index.tsx +++ b/GUI/src/components/BarGraph/index.tsx @@ -44,12 +44,9 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri } useEffect(() => { - console.log('unit', unit); - // todo use t - if (unit !== 'vestlused') return; + if (unit !== t('units.chats')) return; - const totals = getPeriodTotalCounts(data.chartData); - setTotalPeriodCounts(totals); + setTotalPeriodCounts(getPeriodTotalCounts(data.chartData)); }, [data.chartData]); const domain = [minDate, new Date(endDate).getTime()]; From 7f4f0bb901ba79fb6c92e954a512766a358d1819 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 14:48:34 +0300 Subject: [PATCH 5/8] Create re-usable hook --- GUI/src/components/BarGraph/index.tsx | 10 +++------- GUI/src/hooks/ useTotalPeriodCounts.ts | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 GUI/src/hooks/ useTotalPeriodCounts.ts diff --git a/GUI/src/components/BarGraph/index.tsx b/GUI/src/components/BarGraph/index.tsx index b365f9d0..dc8b6559 100644 --- a/GUI/src/components/BarGraph/index.tsx +++ b/GUI/src/components/BarGraph/index.tsx @@ -13,6 +13,7 @@ import { import { GroupByPeriod } from '../MetricAndPeriodOptions/types'; import { useTranslation } from 'react-i18next'; import { use } from 'i18next'; +import { useTotalPeriodCounts } from '../../hooks/ useTotalPeriodCounts'; type Props = { data: any; @@ -24,7 +25,8 @@ type Props = { const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeriod }) => { const [width, setWidth] = useState(null); - const [totalPeriodCounts, setTotalPeriodCounts] = useState>({}); + const totalPeriodCounts = useTotalPeriodCounts(data.chartData, unit); + const ref = useRef(null); const { t } = useTranslation(); @@ -43,12 +45,6 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri minDate = minDate - millisecondInOneDay; } - useEffect(() => { - if (unit !== t('units.chats')) return; - - setTotalPeriodCounts(getPeriodTotalCounts(data.chartData)); - }, [data.chartData]); - const domain = [minDate, new Date(endDate).getTime()]; const ticks = getTicks(startDate, endDate, new Date(startDate), new Date(endDate), 5); diff --git a/GUI/src/hooks/ useTotalPeriodCounts.ts b/GUI/src/hooks/ useTotalPeriodCounts.ts new file mode 100644 index 00000000..43088d67 --- /dev/null +++ b/GUI/src/hooks/ useTotalPeriodCounts.ts @@ -0,0 +1,17 @@ +import { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { getPeriodTotalCounts } from '../util/charts-utils'; + +export const useTotalPeriodCounts = (chartData: any[], unit: string | undefined) => { + const [totalPeriodCounts, setTotalPeriodCounts] = useState>({}); + const { t } = useTranslation(); + + useEffect(() => { + console.log('HOOK unit', unit); + if (unit !== t('units.chats')) return; + + setTotalPeriodCounts(getPeriodTotalCounts(chartData)); + }, [chartData, unit, t]); + + return totalPeriodCounts; +}; From f9e2bd64cee0f29da7bd4ffdd720444b7e21a040 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 14:55:01 +0300 Subject: [PATCH 6/8] Clean up --- GUI/src/components/BarGraph/index.tsx | 24 ++---------------------- GUI/src/hooks/ useTotalPeriodCounts.ts | 18 ++++++++++++++---- GUI/src/util/charts-utils.tsx | 20 -------------------- 3 files changed, 16 insertions(+), 46 deletions(-) diff --git a/GUI/src/components/BarGraph/index.tsx b/GUI/src/components/BarGraph/index.tsx index dc8b6559..6b219828 100644 --- a/GUI/src/components/BarGraph/index.tsx +++ b/GUI/src/components/BarGraph/index.tsx @@ -1,18 +1,8 @@ import React, { useEffect, useRef, useState } from 'react'; import { BarChart, CartesianGrid, YAxis, Tooltip, Legend, Bar, Label, XAxis } from 'recharts'; -import { - chartDataKey, - dateFormatter, - formatDate, - getColor, - getKeys, - getPeriodTotalCounts, - getTicks, - round, -} from '../../util/charts-utils'; +import { chartDataKey, dateFormatter, formatDate, getColor, getKeys, getTicks, round } from '../../util/charts-utils'; import { GroupByPeriod } from '../MetricAndPeriodOptions/types'; import { useTranslation } from 'react-i18next'; -import { use } from 'i18next'; import { useTotalPeriodCounts } from '../../hooks/ useTotalPeriodCounts'; type Props = { @@ -99,17 +89,7 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri /> { - // const totals = getPeriodTotalCounts(data.chartData); - // console.log('totalPeriodCounts', totalPeriodCounts); - // console.log('totalPeriodCounts[value]', totalPeriodCounts[value]); - // console.log('entry', entry); - // console.log('index', index); - return `${value}${totalPeriodCounts[value] ? ` (${totalPeriodCounts[value]})` : ''}`; - - // return `${value}${Object.keys(totalPeriodCounts).includes(value) ? ` (${totalPeriodCounts[value]})` : ''}`; - }} - // accumulate="sum" + formatter={(value) => `${value}${totalPeriodCounts[value] ? ` (${totalPeriodCounts[value]})` : ''}`} /> {data?.chartData?.length > 0 && getKeys(data.chartData).map((k, i) => { diff --git a/GUI/src/hooks/ useTotalPeriodCounts.ts b/GUI/src/hooks/ useTotalPeriodCounts.ts index 43088d67..1ee1bbda 100644 --- a/GUI/src/hooks/ useTotalPeriodCounts.ts +++ b/GUI/src/hooks/ useTotalPeriodCounts.ts @@ -1,17 +1,27 @@ import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; -import { getPeriodTotalCounts } from '../util/charts-utils'; -export const useTotalPeriodCounts = (chartData: any[], unit: string | undefined) => { +export const useTotalPeriodCounts = (chartData: Record[] | undefined, unit: string | undefined) => { const [totalPeriodCounts, setTotalPeriodCounts] = useState>({}); const { t } = useTranslation(); useEffect(() => { - console.log('HOOK unit', unit); - if (unit !== t('units.chats')) return; + if (!chartData?.length || unit !== t('units.chats')) return; setTotalPeriodCounts(getPeriodTotalCounts(chartData)); }, [chartData, unit, t]); return totalPeriodCounts; }; + +const getPeriodTotalCounts = (chartData: Record[]) => { + const totals: Record = {}; + + chartData.forEach((entry) => { + Object.entries(entry).forEach(([key, value]) => { + if (key !== 'dateTime') totals[key] = (totals[key] ?? 0) + value; + }); + }); + + return totals; +}; diff --git a/GUI/src/util/charts-utils.tsx b/GUI/src/util/charts-utils.tsx index 906256c0..07e3bc9e 100644 --- a/GUI/src/util/charts-utils.tsx +++ b/GUI/src/util/charts-utils.tsx @@ -52,23 +52,3 @@ export const chartDataKey = 'dateTime'; export const round = (value: any) => Math.round(Number(value) * 100) / 100; export const getKeys = (data: any[]) => Array.from(new Set(data.flatMap((obj: any) => Object.keys(obj)))); - -export const getPeriodTotalCounts = (chartData: Record[]) => { - const totals: Record = {}; - console.log('chartData in COUNT', chartData); - - // todo handle this and empty array - if (!chartData) return {}; - - chartData.forEach((entry) => { - Object.entries(entry).forEach(([key, value]) => { - if (key !== 'dateTime') { - totals[key] = (totals[key] ?? 0) + value; - } - }); - }); - - console.log('totals', totals); - - return totals; -}; From 6212281bf60d3aee9d8a0fd453ae1b323be80009 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 15:12:54 +0300 Subject: [PATCH 7/8] Implement for line graph --- GUI/src/components/LineGraph/index.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/GUI/src/components/LineGraph/index.tsx b/GUI/src/components/LineGraph/index.tsx index 6d147ee4..a6e34424 100644 --- a/GUI/src/components/LineGraph/index.tsx +++ b/GUI/src/components/LineGraph/index.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { LineChart, XAxis, Line, CartesianGrid, YAxis, Tooltip, Legend, Label } from 'recharts'; import { chartDataKey, dateFormatter, formatDate, getColor, getKeys, getTicks, round } from '../../util/charts-utils'; +import { useTotalPeriodCounts } from '../../hooks/ useTotalPeriodCounts'; type Props = { data: any; @@ -12,6 +13,7 @@ type Props = { const LineGraph = ({ data, startDate, endDate, unit }: Props) => { const [width, setWidth] = useState(null); const ref = useRef(null); + const totalPeriodCounts = useTotalPeriodCounts(data.chartData, unit); useEffect(() => { const handleResize = () => { @@ -73,7 +75,11 @@ const LineGraph = ({ data, startDate, endDate, unit }: Props) => { value={unit} /> - + `${value}${totalPeriodCounts[value] ? ` (${totalPeriodCounts[value]})` : ''}`} + /> {data?.chartData?.length > 0 && getKeys(data.chartData).map((k, i) => { From 25b5d6b03794c276ef0e87776b0c477876f0e060 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 24 Oct 2024 15:47:47 +0300 Subject: [PATCH 8/8] Implement for pie chart --- GUI/src/components/BarGraph/index.tsx | 13 ++++- GUI/src/components/LineGraph/index.tsx | 14 ++++-- GUI/src/components/MetricsCharts/index.tsx | 7 ++- .../components/PieGraph/PieCharLegends.tsx | 13 +++-- GUI/src/components/PieGraph/index.tsx | 47 ++++++++++--------- GUI/src/util/charts-utils.tsx | 3 ++ 6 files changed, 65 insertions(+), 32 deletions(-) diff --git a/GUI/src/components/BarGraph/index.tsx b/GUI/src/components/BarGraph/index.tsx index 6b219828..e4b061ee 100644 --- a/GUI/src/components/BarGraph/index.tsx +++ b/GUI/src/components/BarGraph/index.tsx @@ -1,6 +1,15 @@ import React, { useEffect, useRef, useState } from 'react'; import { BarChart, CartesianGrid, YAxis, Tooltip, Legend, Bar, Label, XAxis } from 'recharts'; -import { chartDataKey, dateFormatter, formatDate, getColor, getKeys, getTicks, round } from '../../util/charts-utils'; +import { + chartDataKey, + dateFormatter, + formatDate, + formatTotalPeriodCount, + getColor, + getKeys, + getTicks, + round, +} from '../../util/charts-utils'; import { GroupByPeriod } from '../MetricAndPeriodOptions/types'; import { useTranslation } from 'react-i18next'; import { useTotalPeriodCounts } from '../../hooks/ useTotalPeriodCounts'; @@ -89,7 +98,7 @@ const BarGraph: React.FC = ({ startDate, endDate, data, unit, groupByPeri /> `${value}${totalPeriodCounts[value] ? ` (${totalPeriodCounts[value]})` : ''}`} + formatter={(value) => `${value}${formatTotalPeriodCount(totalPeriodCounts, value)}`} /> {data?.chartData?.length > 0 && getKeys(data.chartData).map((k, i) => { diff --git a/GUI/src/components/LineGraph/index.tsx b/GUI/src/components/LineGraph/index.tsx index a6e34424..c4e724aa 100644 --- a/GUI/src/components/LineGraph/index.tsx +++ b/GUI/src/components/LineGraph/index.tsx @@ -1,6 +1,15 @@ import React, { useEffect, useRef, useState } from 'react'; import { LineChart, XAxis, Line, CartesianGrid, YAxis, Tooltip, Legend, Label } from 'recharts'; -import { chartDataKey, dateFormatter, formatDate, getColor, getKeys, getTicks, round } from '../../util/charts-utils'; +import { + chartDataKey, + dateFormatter, + formatDate, + formatTotalPeriodCount, + getColor, + getKeys, + getTicks, + round, +} from '../../util/charts-utils'; import { useTotalPeriodCounts } from '../../hooks/ useTotalPeriodCounts'; type Props = { @@ -76,9 +85,8 @@ const LineGraph = ({ data, startDate, endDate, unit }: Props) => { /> `${value}${totalPeriodCounts[value] ? ` (${totalPeriodCounts[value]})` : ''}`} + formatter={(value) => `${value}${formatTotalPeriodCount(totalPeriodCounts, value)}`} /> {data?.chartData?.length > 0 && diff --git a/GUI/src/components/MetricsCharts/index.tsx b/GUI/src/components/MetricsCharts/index.tsx index 80bedbf4..b42fa1fc 100644 --- a/GUI/src/components/MetricsCharts/index.tsx +++ b/GUI/src/components/MetricsCharts/index.tsx @@ -43,7 +43,12 @@ const MetricsCharts = ({ title, data, startDate, endDate, unit, groupByPeriod }: const buildChart = () => { if (selectedChart === 'pieChart') { - return ; + return ( + + ); } else if (selectedChart === 'lineChart') { return ( { - console.log('percentages', percentages); - console.log('data', data); +const PieCharLegends = ({ data, percentages, unit }: Props) => { + const totalPeriodCounts = useTotalPeriodCounts(data.chartData, unit); return ( { className="legend_circle" style={{ backgroundColor: color }} /> - + ); })} diff --git a/GUI/src/components/PieGraph/index.tsx b/GUI/src/components/PieGraph/index.tsx index 418c4d1a..79e04d6b 100644 --- a/GUI/src/components/PieGraph/index.tsx +++ b/GUI/src/components/PieGraph/index.tsx @@ -11,15 +11,16 @@ import './PieGraph.scss'; type Props = { data: any; + unit?: string; }; -const PieGraph = ({ data }: Props) => { +const PieGraph = ({ data, unit }: Props) => { const [width, setWidth] = useState(null); const ref = useRef(null); const { t } = useTranslation(); const percentages = useMemo(() => calculatePercentagesFromResponse(data?.chartData ?? []), [data?.chartData]); - + useEffect(() => { const handleResize = () => { setWidth(ref.current?.clientWidth ?? 0); @@ -38,28 +39,32 @@ const PieGraph = ({ data }: Props) => { data={data.chartData} margin={{ top: 20, right: 30, left: 20, bottom: 5 }} > - - {percentages.map((e: any) => - - )} - + + {percentages.map((e: any) => ( + + ))} + : } /> {percentages.length === 0 && {t('chart.noDataToPlot')}} - +
); diff --git a/GUI/src/util/charts-utils.tsx b/GUI/src/util/charts-utils.tsx index 07e3bc9e..1d3d1f9a 100644 --- a/GUI/src/util/charts-utils.tsx +++ b/GUI/src/util/charts-utils.tsx @@ -52,3 +52,6 @@ export const chartDataKey = 'dateTime'; export const round = (value: any) => Math.round(Number(value) * 100) / 100; export const getKeys = (data: any[]) => Array.from(new Set(data.flatMap((obj: any) => Object.keys(obj)))); + +export const formatTotalPeriodCount = (totalPeriodCounts: Record, metric: string) => + `${totalPeriodCounts[metric] ? ` (${totalPeriodCounts[metric]})` : ''}`;