155 lines
3.9 KiB
TypeScript
155 lines
3.9 KiB
TypeScript
import { FC } from "react";
|
||
import { Box, Paper, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||
import { PieChart } from "@mui/x-charts";
|
||
|
||
import type { DevicesResponse } from "@api/statistic";
|
||
|
||
type DeviceProps = {
|
||
title: string;
|
||
devices: Record<string, number> | null;
|
||
};
|
||
|
||
type DevicesProps = {
|
||
data: DevicesResponse | null;
|
||
};
|
||
|
||
const COLORS: Record<number, string> = {
|
||
0: "#7E2AEA",
|
||
1: "#FA7738",
|
||
2: "#62BB1C",
|
||
3: "#0886FB",
|
||
};
|
||
|
||
const Device = ({ title, devices }: DeviceProps) => {
|
||
const theme = useTheme();
|
||
if (!devices || !Object.keys(devices ?? {}).length) {
|
||
return <Typography>{title} - нет данных</Typography>;
|
||
}
|
||
|
||
const data = Object.entries(devices).map(([id, value], index) => ({
|
||
id,
|
||
value,
|
||
color: COLORS[index],
|
||
}));
|
||
|
||
return (
|
||
<Paper
|
||
sx={{
|
||
overflow: "hidden",
|
||
minHeight: "500px",
|
||
display: "flex",
|
||
flexDirection: "column",
|
||
gap: "30px",
|
||
borderRadius: "12px",
|
||
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
|
||
}}
|
||
>
|
||
<Typography sx={{ margin: "20px" }}>{title}</Typography>
|
||
<Box sx={{ flexGrow: 1 }}>
|
||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||
<PieChart
|
||
height={245}
|
||
width={245}
|
||
margin={{ right: 0 }}
|
||
series={[{ data, innerRadius: 50 }]}
|
||
/>
|
||
</Box>
|
||
</Box>
|
||
<Box
|
||
sx={{ background: theme.palette.background.default, padding: "20px" }}
|
||
>
|
||
{data.map(({ id, value, color }) => (
|
||
<Box
|
||
key={id}
|
||
sx={{
|
||
display: "flex",
|
||
marginBottom: "10px",
|
||
"&:last-child": { margin: 0 },
|
||
}}
|
||
>
|
||
<Typography
|
||
sx={{
|
||
flexGrow: 1,
|
||
position: "relative",
|
||
paddingLeft: "30px",
|
||
"&::before": {
|
||
content: "''",
|
||
display: "block",
|
||
position: "absolute",
|
||
left: "0",
|
||
background: color,
|
||
height: "20px",
|
||
width: "20px",
|
||
borderRadius: "6px",
|
||
},
|
||
}}
|
||
>
|
||
{id ? id : "Неопределено"}
|
||
</Typography>
|
||
<Typography>{value.toFixed(1)} %</Typography>
|
||
</Box>
|
||
))}
|
||
</Box>
|
||
</Paper>
|
||
);
|
||
};
|
||
|
||
export const Devices: FC<DevicesProps> = ({ data }) => {
|
||
const theme = useTheme();
|
||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||
const isMobile = useMediaQuery(theme.breakpoints.down(700));
|
||
|
||
// useEffect(() => {
|
||
// const requestDevices = async () => {
|
||
// const [devicesResponse, devicesError] = await getDevices("14761");
|
||
|
||
// if (devicesError) {
|
||
// enqueueSnackbar(devicesError);
|
||
|
||
// return;
|
||
// }
|
||
|
||
// if (!devicesResponse) {
|
||
// enqueueSnackbar("Список девайсов пуст.");
|
||
|
||
// return;
|
||
// }
|
||
|
||
// setDevices(devicesResponse);
|
||
// };
|
||
|
||
// // requestDevices();
|
||
// }, []);
|
||
|
||
return (
|
||
<Box sx={{ marginTop: "120px" }}>
|
||
<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: "30px",
|
||
}}
|
||
>
|
||
<Device title="Устройства" devices={data?.Device || null} />
|
||
<Device title="Операционные системы" devices={data?.OS || null} />
|
||
<Device title="Браузеры" devices={data?.Browser || null} />
|
||
</Box>
|
||
</Box>
|
||
);
|
||
};
|