From ec1439e1710caeeb0d90410c099dc03e948b042f Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:07:38 +0100 Subject: [PATCH] Feat: dashboard users chart frontend (#5980) Users chart with tooltip and legend --- .../executiveDashboard/ExecutiveDashboard.tsx | 30 +- .../UsersChart/UsersChart.tsx | 3 + .../UsersChart/UsersChartComponent.tsx | 407 ++++++++++++++++++ 3 files changed, 439 insertions(+), 1 deletion(-) create mode 100644 frontend/src/component/executiveDashboard/UsersChart/UsersChart.tsx create mode 100644 frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx diff --git a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx index 6632407906..f623492e07 100644 --- a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx +++ b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx @@ -1,5 +1,33 @@ +import { Box, Paper, styled, Typography } from '@mui/material'; +import { PageHeader } from 'component/common/PageHeader/PageHeader'; import { VFC } from 'react'; +import { UsersChart } from './UsersChart/UsersChart'; + +const StyledGrid = styled(Box)(({ theme }) => ({ + display: 'grid', + gridTemplateColumns: `repeat(auto-fill, minmax(600px, 1fr))`, + gridAutoRows: '1fr', + gap: theme.spacing(2), +})); export const ExecutiveDashboard: VFC = () => { - return <>test; + return ( + <> + ({ paddingBottom: theme.spacing(4) })}> + + Dashboard + + } + // subtitle='Succesfully synchronized: 01 Sep 2023 - 07:05:07' + /> + + {/* Dashboard */} + + Stats + + + + ); }; diff --git a/frontend/src/component/executiveDashboard/UsersChart/UsersChart.tsx b/frontend/src/component/executiveDashboard/UsersChart/UsersChart.tsx new file mode 100644 index 0000000000..ee5a468d68 --- /dev/null +++ b/frontend/src/component/executiveDashboard/UsersChart/UsersChart.tsx @@ -0,0 +1,3 @@ +import { lazy } from 'react'; + +export const UsersChart = lazy(() => import('./UsersChartComponent')); diff --git a/frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx b/frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx new file mode 100644 index 0000000000..c1ef0659b5 --- /dev/null +++ b/frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx @@ -0,0 +1,407 @@ +import { type VFC } from 'react'; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + Title, + Tooltip, + Legend, + TimeScale, +} from 'chart.js'; +import { Line } from 'react-chartjs-2'; +import 'chartjs-adapter-date-fns'; +import { Paper, Theme, useTheme } from '@mui/material'; +import { + useLocationSettings, + type ILocationSettings, +} from 'hooks/useLocationSettings'; +import { formatDateYMD } from 'utils/formatDate'; + +type Data = { + date: string | Date; + total?: number; + active?: number; + inactive?: number; +}[]; + +const mockData: Data = [ + { + date: '2023-01-21', + }, + { + date: '2023-01-28', + }, + { + date: '2023-02-04', + }, + { + date: '2023-02-11', + }, + { + date: '2023-02-18', + }, + { + date: '2023-02-25', + }, + { + date: '2023-03-04', + }, + { + date: '2023-03-11', + }, + { + date: '2023-03-18', + }, + { + date: '2023-03-25', + }, + { + date: '2023-04-01', + }, + { + date: '2023-04-08', + }, + { + date: '2023-04-15', + }, + { + date: '2023-04-22', + total: 43, + active: 0, + inactive: 0, + }, + { + date: '2023-04-29', + total: 54, + active: 54, + inactive: 0, + }, + { + date: '2023-05-06', + total: 63, + active: 63, + inactive: 0, + }, + { + date: '2023-05-13', + total: 81, + active: 81, + inactive: 0, + }, + { + date: '2023-05-20', + total: 80, + active: 80, + inactive: 0, + }, + { + date: '2023-05-27', + total: 95, + active: 95, + inactive: 0, + }, + { + date: '2023-06-03', + total: 108, + active: 108, + inactive: 0, + }, + { + date: '2023-06-10', + total: 101, + active: 101, + inactive: 0, + }, + { + date: '2023-06-17', + total: 104, + active: 104, + inactive: 0, + }, + { + date: '2023-06-24', + total: 114, + active: 114, + inactive: 0, + }, + { + date: '2023-07-01', + total: 108, + active: 106, + inactive: 2, + }, + { + date: '2023-07-08', + total: 103, + active: 102, + inactive: 1, + }, + { + date: '2023-07-15', + total: 106, + active: 105, + inactive: 1, + }, + { + date: '2023-07-22', + total: 112, + active: 106, + inactive: 6, + }, + { + date: '2023-07-29', + total: 113, + active: 107, + inactive: 6, + }, + { + date: '2023-08-05', + total: 109, + active: 98, + inactive: 11, + }, + { + date: '2023-08-12', + total: 110, + active: 96, + inactive: 14, + }, + { + date: '2023-08-19', + total: 127, + active: 111, + inactive: 16, + }, + { + date: '2023-08-26', + total: 140, + active: 124, + inactive: 16, + }, + { + date: '2023-09-02', + total: 150, + active: 130, + inactive: 20, + }, + { + date: '2023-09-09', + total: 168, + active: 148, + inactive: 20, + }, + { + date: '2023-09-16', + total: 171, + active: 154, + inactive: 17, + }, + { + date: '2023-09-23', + total: 190, + active: 174, + inactive: 16, + }, + { + date: '2023-09-30', + total: 186, + active: 169, + inactive: 17, + }, + { + date: '2023-10-07', + total: 188, + active: 173, + inactive: 15, + }, + { + date: '2023-10-14', + total: 181, + active: 166, + inactive: 15, + }, + { + date: '2023-10-21', + total: 192, + active: 177, + inactive: 15, + }, + { + date: '2023-10-28', + total: 183, + active: 164, + inactive: 19, + }, + { + date: '2023-11-04', + total: 200, + active: 180, + inactive: 20, + }, + { + date: '2023-11-11', + total: 212, + active: 189, + inactive: 23, + }, + { + date: '2023-11-18', + total: 204, + active: 177, + inactive: 27, + }, + { + date: '2023-11-25', + total: 200, + active: 173, + inactive: 27, + }, + { + date: '2023-12-02', + total: 200, + active: 175, + inactive: 25, + }, + { + date: '2023-12-09', + total: 200, + active: 176, + inactive: 24, + }, + { + date: '2023-12-16', + total: 215, + active: 186, + inactive: 29, + }, + { + date: '2023-12-23', + total: 221, + active: 195, + inactive: 26, + }, + { + date: '2023-12-30', + total: 214, + active: 184, + inactive: 30, + }, + { + date: '2024-01-06', + total: 204, + active: 173, + inactive: 31, + }, + { + date: '2024-01-13', + total: 215, + active: 181, + inactive: 34, + }, +]; + +const createData = (theme: Theme) => ({ + labels: mockData.map((item) => item.date), + datasets: [ + { + label: 'Total users', + data: mockData.map((item) => item.total), + borderColor: theme.palette.primary.main, + backgroundColor: theme.palette.primary.main, + fill: true, + }, + { + label: 'Inactive users', + data: mockData.map((item) => item.inactive), + borderColor: theme.palette.error.main, + backgroundColor: theme.palette.error.main, + fill: true, + }, + { + label: 'Active users', + data: mockData.map((item) => item.active), + borderColor: theme.palette.success.main, + backgroundColor: theme.palette.success.main, + fill: true, + }, + ], +}); + +const createOptions = (theme: Theme, locationSettings: ILocationSettings) => + ({ + responsive: true, + plugins: { + legend: { + position: 'bottom', + }, + tooltip: { + callbacks: { + title: (tooltipItems: any) => { + const item = tooltipItems?.[0]; + const date = + item?.chart?.data?.labels?.[item.dataIndex]; + return date + ? formatDateYMD(date, locationSettings.locale) + : ''; + }, + }, + }, + }, + locale: locationSettings.locale, + interaction: { + intersect: false, + axis: 'x', + }, + color: theme.palette.text.secondary, + scales: { + y: { + type: 'linear', + grid: { + color: theme.palette.divider, + borderColor: theme.palette.divider, + }, + ticks: { color: theme.palette.text.secondary }, + }, + x: { + type: 'time', + time: { + unit: 'month', + }, + grid: { + color: theme.palette.divider, + borderColor: theme.palette.divider, + }, + ticks: { + color: theme.palette.text.secondary, + }, + }, + }, + }) as const; + +const UsersChartComponent: VFC = () => { + const theme = useTheme(); + const { locationSettings } = useLocationSettings(); + const data = createData(theme); + const options = createOptions(theme, locationSettings); + + return ( + ({ padding: theme.spacing(4) })}> + + + ); +}; + +ChartJS.register( + CategoryScale, + LinearScale, + PointElement, + LineElement, + TimeScale, + Title, + Tooltip, + Legend, +); + +export default UsersChartComponent;