frontPanel/src/pages/Analytics/General.tsx
2024-04-26 17:41:36 +03:00

296 lines
7.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import moment from "moment";
import { Box, Paper, Typography, useMediaQuery, useTheme } from "@mui/material";
import { LineChart } from "@mui/x-charts";
import type { FC } from "react";
import type { GeneralResponse } from "@api/statistic";
type GeneralItemsProps = {
title: string;
general: Record<string, number>;
color: string;
numberType: "sum" | "percent" | "time";
calculateTime?: boolean;
conversionValue?: number;
day: boolean;
};
type GeneralProps = {
data: GeneralResponse | null;
day: boolean;
};
const getCalculatedTime = (time: number) => {
const hours = String(Math.floor(time / 3600)).padStart(2, "0");
const minutes = String(Math.floor((time % 3600) / 60)).padStart(2, "0");
const seconds = String(Math.floor((time % 3600) % 60)).padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
};
const GeneralItem = ({
title,
general,
color,
numberType,
calculateTime = false,
conversionValue,
day,
}: GeneralItemsProps) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(700));
const numberValue =
numberType === "sum"
? Object.values(general).reduce((total, item) => total + item, 0)
: title === "Конверсия"
? conversionValue
: 0;
if (
Object.keys(general).length === 0 ||
Object.values(general).every((x) => x === 0)
) {
return (
<Typography textAlign="center">{`${title} - нет данных`}</Typography>
);
}
const getCalculatedTime = (time: number) => {
const hours = String(Math.floor(time / 3600)).padStart(2, "0");
const minutes = String(Math.floor((time % 3600) / 60)).padStart(2, "0");
const seconds = String(Math.floor((time % 3600) % 60)).padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
};
return (
<Paper
sx={{
overflow: "hidden",
borderRadius: "12px",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
}}
>
<Typography sx={{ margin: "20px 20px 0" }}>{title}</Typography>
<Typography sx={{ margin: "10px 20px 0", fontWeight: "bold" }}>
{numberType === "percent" ? `${numberValue?.toFixed(2)}%` : numberValue}
</Typography>
<LineChart
xAxis={[
{
data: Object.keys(general),
valueFormatter: (value) =>
moment.unix(Number(value)).format("DD/MM/YYYY HH") + "ч",
},
]}
series={[
{
data: Object.values(general),
valueFormatter: (value) =>
calculateTime
? getCalculatedTime(value)
: String(value.toFixed(2)),
},
]}
height={220}
colors={[color]}
sx={{
transform: isMobile ? "scale(1.1)" : "scale(1.2)",
"& .MuiChartsAxis-tickContainer": { display: "none" },
}}
/>
</Paper>
);
};
const GeneralItemTimeConv = ({
title,
general,
color,
numberType,
calculateTime = false,
conversionValue,
}: GeneralItemsProps) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(700));
const data = Object.entries(general).sort((a, b) => a[0] - b[0]);
const days = [...data].map((e) => e[0]);
let buffer = 0;
const time = [...data].map((e) => {
if (e[1] > 0) {
buffer = e[1];
}
return buffer;
});
console.log("data", data);
console.log(
"time",
time.reduce((a, b) => Number(a) + Number(b), 0),
);
console.log(
"time",
getCalculatedTime(time.reduce((a, b) => Number(a) + Number(b), 0)),
);
console.log("days", days.length);
const numberValue = calculateTime
? time.reduce((a, b) => Number(a) + Number(b), 0) / days.length || 0
: conversionValue;
if (
Object.keys(general).length === 0 ||
Object.values(general).every((x) => x === 0)
) {
return (
<Typography textAlign="center">{`${title} - нет данных`}</Typography>
);
}
return (
<Paper
sx={{
overflow: "hidden",
borderRadius: "12px",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
}}
>
<Typography sx={{ margin: "20px 20px 0" }}>{title}</Typography>
<Typography sx={{ margin: "10px 20px 0", fontWeight: "bold" }}>
{calculateTime
? `${getCalculatedTime(numberValue)} с`
: `${numberValue.toFixed(2)}%`}
</Typography>
<LineChart
xAxis={[
{
data: days,
valueFormatter: (value) =>
moment.utc(Number(value) * 1000).format("DD/MM/YYYY"),
},
]}
series={[
{
data: Object.values(time),
valueFormatter: (value) => {
console.log("log", value);
return calculateTime
? getCalculatedTime(value)
: String((value * 100).toFixed(2)) + "%";
},
},
]}
height={220}
colors={[color]}
sx={{
transform: isMobile ? "scale(1.1)" : "scale(1.2)",
"& .MuiChartsAxis-tickContainer": { display: "none" },
}}
/>
</Paper>
);
};
export const General: FC<GeneralProps> = ({ data, day }) => {
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(700));
if (!data) {
return (
<Typography textAlign="center" m="10px 0">
нет данных о ключевых метриках
</Typography>
);
}
const currentDate = moment().unix();
const generalResponse = Object.entries(data).reduce(
(total, [fatherKey, values]) => {
const value = Object.keys(values).reduce((totalValue, key) => {
if (Number(key) - currentDate < 0) {
return { ...totalValue, [key]: values[key] };
}
return totalValue;
}, {});
return { ...total, [fatherKey]: value };
},
{} as GeneralResponse,
);
const resultSum = Object.values(generalResponse.Result).reduce(
(total, item) => total + item,
0,
);
const openSum = Object.values(generalResponse.Open).reduce(
(total, item) => total + item,
0,
);
const conversionValue = (resultSum / openSum) * 100;
return (
<Box sx={{ marginTop: "45px" }}>
<Typography
component="h3"
sx={{
fontSize: "24px",
fontWeight: "bold",
color: theme.palette.text.primary,
}}
>
Ключевые метрики
</Typography>
<Box
sx={{
display: "grid",
gridTemplateColumns: isTablet
? isMobile
? "1fr"
: "1fr 1fr"
: "1fr 1fr 1fr",
gap: "20px",
marginTop: "40px",
}}
>
<GeneralItem
title="Открыли квиз"
numberType="sum"
general={generalResponse.Open}
color="#61BB1A"
day={day}
/>
<GeneralItem
title="Получено заявок"
numberType="sum"
general={generalResponse.Result}
color="#7E2AEA"
day={day}
/>
<GeneralItemTimeConv
title="Конверсия"
numberType="percent"
conversionValue={conversionValue}
general={generalResponse.Conversion}
color="#FB5607"
day={day}
/>
<GeneralItemTimeConv
title="Среднее время прохождения квиза"
numberType="time"
calculateTime
general={generalResponse.AvTime}
color="#0886FB"
day={day}
/>
</Box>
</Box>
);
};