From f22387ecd60142f0a11a46b37026d66e0c2a4d9d Mon Sep 17 00:00:00 2001
From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com>
Date: Fri, 19 Jan 2024 17:19:32 +0100
Subject: [PATCH] active users tooltip
---
.../executiveDashboard/ExecutiveDashboard.tsx | 25 ++-
.../UsersChart/UsersChartComponent.tsx | 144 +++++++++++++++---
2 files changed, 144 insertions(+), 25 deletions(-)
diff --git a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
index 1576b1ebe93f..f623492e07cf 100644
--- a/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
+++ b/frontend/src/component/executiveDashboard/ExecutiveDashboard.tsx
@@ -1,10 +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 (
<>
-
+ ({ paddingBottom: theme.spacing(4) })}>
+
+ Dashboard
+
+ }
+ // subtitle='Succesfully synchronized: 01 Sep 2023 - 07:05:07'
+ />
+
+ {/* Dashboard */}
+
+ Stats
+
+
>
);
};
diff --git a/frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx b/frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx
index 1ee325e9172f..c006bfe516bb 100644
--- a/frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx
+++ b/frontend/src/component/executiveDashboard/UsersChart/UsersChartComponent.tsx
@@ -8,58 +8,153 @@ import {
Title,
Tooltip,
Legend,
+ TimeScale,
} from 'chart.js';
import { Line } from 'react-chartjs-2';
+import 'chartjs-adapter-date-fns';
import faker from 'faker';
import { Paper, Theme, useTheme } from '@mui/material';
import {
useLocationSettings,
type ILocationSettings,
} from 'hooks/useLocationSettings';
+import { formatDateYMD } from 'utils/formatDate';
-const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
+type Data = {
+ date: string | Date;
+ total?: number;
+ active?: number;
+ inactive?: number;
+}[];
+
+const now = new Date();
+const yearAgo = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
+const mockStart = new Date(
+ yearAgo.getFullYear(),
+ yearAgo.getMonth() + 3,
+ yearAgo.getDate(),
+);
+const mockLabels = Array.from({ length: 52 }, (_, i) => {
+ const date = new Date(yearAgo.getTime() + i * 7 * 24 * 60 * 60 * 1000);
+
+ return date.toISOString();
+});
+
+const mockData: Data = mockLabels.reduce((prev, curr) => {
+ const date = new Date(curr);
+ const key = date.toISOString().slice(0, 10);
+ const lastValues = prev[prev.length - 1];
+
+ if (date < mockStart) {
+ return [...prev, { date: key }];
+ }
+
+ if (lastValues.total === undefined) {
+ return [
+ ...prev,
+ {
+ date: key,
+ total: faker.datatype.number({ min: 15, max: 50 }),
+ active: 0,
+ inactive: 0,
+ },
+ ];
+ }
+
+ const total =
+ lastValues.total + faker.datatype.number({ min: -10, max: 20 });
+
+ const inactive =
+ date < new Date(mockStart.getTime() + 2 * 30 * 24 * 60 * 60 * 1000)
+ ? 0
+ : Math.max(
+ 0,
+ (lastValues.inactive || 0) +
+ faker.datatype.number({ min: -3, max: 5 }),
+ );
+
+ const active = total - inactive;
+
+ return [...prev, { date: key, total, active, inactive }];
+}, [] as Data);
const createData = (theme: Theme) => ({
- labels,
+ labels: mockData.map((item) => item.date),
datasets: [
{
label: 'Active users',
- data: labels.map(() =>
- faker.datatype.number({ min: 150, max: 200 }),
- ),
+ data: mockData.map((item) => item.total),
borderColor: theme.palette.primary.main,
backgroundColor: theme.palette.primary.main,
fill: true,
},
{
label: 'Inactive users',
- data: labels.map(() => faker.datatype.number({ min: 10, max: 50 })),
+ 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' as const,
+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)
+ : '';
+ },
+ },
+ },
},
- // title: {
- // display: true,
- // text: 'Chart.js Line Chart',
- // },
- },
- locale: locationSettings.locale,
- // maintainAspectRatio: false,
- // interaction: {
- // mode: 'index',
- // intersect: false,
- // },
- color: theme.palette.text.secondary,
-});
+ 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();
@@ -80,6 +175,7 @@ ChartJS.register(
LinearScale,
PointElement,
LineElement,
+ TimeScale,
Title,
Tooltip,
Legend,