feat: Funnel and Answers

This commit is contained in:
IlyaDoronin 2024-03-22 17:29:51 +03:00
parent 31a8b613bb
commit 16f36cf5d9
5 changed files with 247 additions and 34 deletions

@ -16,6 +16,8 @@ import HeaderFull from "@ui_kit/Header/HeaderFull";
import SectionWrapper from "@ui_kit/SectionWrapper";
import { General } from "./General";
import { Answers } from "./Answers";
import { Funnel } from "./Funnel";
import { Devices } from "./Devices";
import CalendarIcon from "@icons/CalendarIcon";
@ -172,6 +174,8 @@ export default function Analytics() {
</Button>
</Box>
<General />
<Answers />
<Funnel />
<Devices />
</SectionWrapper>
</>

@ -0,0 +1,101 @@
import { useState } from "react";
import {
Box,
Paper,
Typography,
LinearProgress,
useTheme,
} from "@mui/material";
type AnswerProps = {
title: string;
percent: number;
};
const ANSWERS_MOCK: Record<string, number> = {
"Добавьте ответ": 67,
"Вопрос пропущен": 7,
Другое: 27,
};
const Answer = ({ title, percent }: AnswerProps) => {
const theme = useTheme();
return (
<Box sx={{ padding: "15px 25px" }}>
<Box
sx={{
position: "relative",
display: "flex",
gap: "15px",
alignItems: "center",
flexGrow: 1,
}}
>
<LinearProgress
variant="determinate"
title={title}
value={percent}
sx={{
width: "100%",
height: "44px",
background: theme.palette.background.default,
borderRadius: "10px",
border: `1px solid ${theme.palette.grey2.main}`,
"& > span": { background: "#9A9AAF1A" },
"&::before": {
content: `"${title}"`,
position: "absolute",
zIndex: 1,
left: "20px",
top: "50%",
transform: "translateY(-50%)",
color: theme.palette.grey3.main,
},
}}
/>
<Box sx={{ minWidth: 35 }}>
<Typography
sx={{
minWidth: "45px",
color:
percent === 100
? theme.palette.text.secondary
: theme.palette.text.primary,
}}
>{`${percent}%`}</Typography>
</Box>
</Box>
</Box>
);
};
export const Answers = () => {
const [answers, setAnswers] = useState<Record<string, number>>(ANSWERS_MOCK);
const theme = useTheme();
return (
<Paper
sx={{
borderRadius: "12px",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
marginTop: "60px",
}}
>
<Typography
component="h3"
sx={{
padding: "25px",
fontSize: "24px",
fontWeight: "bold",
color: theme.palette.text.primary,
}}
>
Заголовок вопроса. Варианты ответов
</Typography>
{Object.entries(answers).map(([title, percent]) => (
<Answer key={title} title={title} percent={percent} />
))}
</Paper>
);
};

@ -20,20 +20,9 @@ const COLORS: Record<number, string> = {
};
const DEVICES_MOCK: DevicesResponse = {
device: {
PC: 75,
Mobile: 25,
},
os: {
Windows: 44,
AndroidOS: 25,
"OS X": 19,
Linux: 13,
},
browser: {
Chrome: 75,
Firefox: 25,
},
device: { PC: 75, Mobile: 25 },
os: { Windows: 44, AndroidOS: 25, "OS X": 19, Linux: 13 },
browser: { Chrome: 75, Firefox: 25 },
};
const Device = ({ title, devices }: DeviceProps) => {
@ -72,6 +61,7 @@ const Device = ({ title, devices }: DeviceProps) => {
>
{data.map(({ id, value, color }) => (
<Box
key={id}
sx={{
display: "flex",
marginBottom: "10px",

@ -0,0 +1,134 @@
import { useEffect, useState } from "react";
import {
Box,
Paper,
Typography,
LinearProgress,
useTheme,
} from "@mui/material";
import { enqueueSnackbar } from "notistack";
type FunnelItemProps = {
title: string;
percent: number;
};
const FUNNEL_MOCK: Record<string, number> = {
"Стартовая страница": 100,
"Воронка квиза": 69,
Заявки: 56,
Результаты: 56,
};
const FunnelItem = ({ title, percent }: FunnelItemProps) => {
const theme = useTheme();
return (
<Box
sx={{
padding: "15px 25px",
"&:last-child div::after": { display: "none" },
}}
>
<Typography sx={{ marginBottom: "10px", fontWeight: "bold" }}>
{title}
</Typography>
<Box
sx={{
position: "relative",
display: "flex",
gap: "15px",
"&::after": {
content: "''",
position: "absolute",
left: 0,
bottom: "-15px",
height: "1px",
width: "100%",
maxWidth: "300px",
background: "#9A9AAF80",
},
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "30px",
height: "30px",
border: "1px solid black",
borderRadius: "8px",
fontSize: "14px",
}}
>
1
</Box>
<Box sx={{ display: "flex", alignItems: "center", flexGrow: 1 }}>
<LinearProgress
variant="determinate"
value={percent}
sx={{
width: "100%",
marginRight: "15px",
height: "12px",
background: theme.palette.background.default,
borderRadius: "6px",
border:
percent === 100
? `1px solid ${theme.palette.brightPurple.main}`
: null,
"& > span": { background: "#D9C0F9" },
}}
/>
<Box sx={{ minWidth: 35 }}>
<Typography
sx={{
minWidth: "45px",
color:
percent === 100
? theme.palette.text.secondary
: theme.palette.text.primary,
}}
>{`${percent}%`}</Typography>
</Box>
</Box>
</Box>
</Box>
);
};
export const Funnel = () => {
const [funnel, setFunnel] = useState<Record<string, number>>(FUNNEL_MOCK);
useEffect(() => {
// const requestFunnel = async () => {
// const [funnelResponse, funnelError] = await getGeneral("14761");
// if (funnelError) {
// enqueueSnackbar(funnelError);
// return;
// }
// if (!funnelResponse) {
// enqueueSnackbar("Воронка пуста.");
// return;
// }
// setFunnel(funnelResponse);
// };
// requestFunnel();
}, []);
return (
<Paper
sx={{
borderRadius: "12px",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
marginTop: "60px",
}}
>
{Object.entries(funnel).map(([title, percent]) => (
<FunnelItem key={title} title={title} percent={percent} />
))}
</Paper>
);
};

@ -22,26 +22,10 @@ const COLORS: Record<number, string> = {
};
const GENERAL_MOCK: GeneralResponse = {
open: {
100: 20,
50: 10,
60: 5,
},
result: {
100: 90,
10: 3,
50: 48,
},
avtime: {
100: 0,
2000: 550,
60: 0,
},
conversation: {
100: 50,
1000: 50,
10000: 50,
},
open: { 100: 20, 50: 10, 60: 5 },
result: { 100: 90, 10: 3, 50: 48 },
avtime: { 100: 0, 2000: 550, 60: 0 },
conversation: { 100: 50, 1000: 50, 10000: 50 },
};
const GeneralItem = ({ title, general, color, numberType }: GeneralProps) => {