верстка статистики воронки

This commit is contained in:
Tamara 2024-06-30 18:18:51 +03:00
parent 5974125cbe
commit def873967d
4 changed files with 279 additions and 146 deletions

@ -3,7 +3,7 @@ import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
import { Answers } from "./Answers";
import { QuestionsResponse } from "@api/statistic";
import { FC } from "react";
import { Funnel } from "./Funnel";
import { Funnel } from "./FunnelAnswers/Funnel";
import { Results } from "./Results";
type AnswersStatisticsProps = {

@ -1,145 +0,0 @@
import {
Box,
LinearProgress,
Paper,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import type { FC } from "react";
type FunnelItemProps = {
title: string;
percent: number;
index: number;
funnel: number;
};
type FunnelProps = {
data: number[];
funnelData: number[];
};
const FUNNEL_MOCK: Record<string, number> = {
"Стартовая страница": 100,
"Воронка квиза": 0,
Заявки: 0,
Результаты: 0,
};
const FunnelItem = ({ title, percent, index, funnel }: 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",
}}
>
{funnel}
</Box>
<Box sx={{ display: "flex", alignItems: "center", flexGrow: 1 }}>
<LinearProgress
variant="determinate"
value={percent * 100 > 100 ? 100 : percent * 100}
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,
}}
>
{index === 0 ? "100%" : `${(percent * 100).toFixed(1)}%`}
</Typography>
</Box>
</Box>
</Box>
</Box>
);
};
export const Funnel: FC<FunnelProps> = ({ data, funnelData }) => {
const theme = useTheme();
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1150));
const isMobile = useMediaQuery(theme.breakpoints.down(850));
if (!data)
return (
<Typography textAlign="center" m="10px 0">
нет данных о разделах
</Typography>
);
return (
<Paper
sx={{
borderRadius: "12px",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
marginTop: isSmallMonitor && !isMobile ? 0 : "60px",
width: "100%",
maxWidth: isSmallMonitor && !isMobile ? "366px" : "none",
}}
>
{Object.entries(FUNNEL_MOCK).map(([title, percent], index) => (
<FunnelItem
key={title}
title={title}
index={index}
percent={index > 0 ? data[index - 1] : percent}
funnel={funnelData[index]}
/>
))}
</Paper>
);
};

@ -0,0 +1,191 @@
import {
Box, IconButton,
LinearProgress,
Paper,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import type { FC } from "react";
import {ArrowDownIcon} from "@icons/questionsPage/ArrowDownIcon";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import {useState} from "react";
import FunnelDetals from "@/pages/Analytics/Answers/FunnelAnswers/funnelDetals";
type FunnelItemProps = {
title: string;
percent: number;
index: number;
funnel: number;
};
type FunnelProps = {
data: number[];
funnelData: number[];
};
const FUNNEL_MOCK: Record<string, number> = {
"Стартовая страница": 100,
"Воронка квиза": 0,
Заявки: 0,
Результаты: 0,
};
const FunnelItem = ({ title, percent, index, funnel }: FunnelItemProps) => {
const theme = useTheme();
const [isExpanded, setIsExpanded] = useState<boolean>(false);
const expandedHC = (bool: boolean) => {
setIsExpanded(bool);
};
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%",
background: "#9A9AAF80",
},
}}
>
<IconButton
sx={{ padding: "0", margin: "5px" }}
onClick={() => expandedHC(!isExpanded)}
>
<ArrowDownIcon
style={{
width: "18px",
color: "#4D4D4D",
rotate: isExpanded ? "180deg" : undefined
}}
/>
</IconButton>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "30px",
height: "30px",
border: "1px solid black",
borderRadius: "8px",
fontSize: "14px",
}}
>
{funnel}
</Box>
<Box sx={{ display: "flex", alignItems: "center", flexGrow: 1 }}>
<LinearProgress
variant="determinate"
value={percent * 100 > 100 ? 100 : percent * 100}
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,
}}
>
{index === 0 ? "100%" : `${(percent * 100).toFixed(1)}%`}
</Typography>
</Box>
</Box>
</Box>
</Box>
{isExpanded &&
<>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
borderRadius: "0 0 12px 12px",
padding: "20px",
background: "white",
position: "relative",
color: "#9A9AAF"
}}
>
<Typography>Воронки</Typography>
<Typography>Дошли до этапа</Typography>
</Box>
<Box
sx={{backgroundColor: "#F1F2F6", marginTop: "-15px", padding: "30px 20px 20px"}}
>
<FunnelDetals/>
</Box>
</>
}
</>
);
};
export const Funnel: FC<FunnelProps> = ({ data, funnelData }) => {
const theme = useTheme();
const isSmallMonitor = useMediaQuery(theme.breakpoints.down(1150));
const isMobile = useMediaQuery(theme.breakpoints.down(850));
if (!data)
return (
<Typography textAlign="center" m="10px 0">
нет данных о разделах
</Typography>
);
return (
<Paper
sx={{
borderRadius: "12px",
boxShadow: "0 0 20px rgba(0, 0, 0, 0.15)",
marginTop: isSmallMonitor && !isMobile ? 0 : "60px",
width: "100%",
maxWidth: isSmallMonitor && !isMobile ? "366px" : "none",
}}
>
{Object.entries(FUNNEL_MOCK).map(([title, percent], index) => (
<FunnelItem
key={title}
title={title}
index={index}
percent={index > 0 ? data[index - 1] : percent}
funnel={funnelData[index]}
/>
))}
</Paper>
);
};

@ -0,0 +1,87 @@
import {Box, IconButton, Typography, useTheme} from "@mui/material";
import {ArrowDownIcon} from "@icons/questionsPage/ArrowDownIcon";
import {useState} from "react";
export default function FunnelDetals () {
const theme = useTheme();
const [isExpanded, setIsExpanded] = useState<boolean>(false);
const expandedHC = (bool: boolean) => {
setIsExpanded(bool);
};
return(
<Box sx={{
display: "flex",
flexDirection: "column",
gap: "14px",
}}>
<Box
sx={{display: "flex",
justifyContent: "space-between",}}
>
<Typography fontSize={"16px"}>Воронка 1</Typography>
<IconButton
sx={{ padding: "0", margin: "5px" }}
onClick={() => expandedHC(!isExpanded)}
>
<ArrowDownIcon
style={{
width: "18px",
color: theme.palette.brightPurple.main,
rotate: isExpanded ? "180deg" : undefined
}}
/>
</IconButton>
</Box>
{isExpanded &&
<Box sx={{
display: "flex",
flexDirection: "column",
gap: "40px",
}}>
<DetalItem/>
<DetalItem/>
<DetalItem/>
<DetalItem/>
</Box>
}
</Box>
)
}
const DetalItem = () => {
return(
<Box sx={{"&:last-child div::after": { display: "none" },}}>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
position: "relative",
"&::after": {
content: "''",
position: "absolute",
left: 0,
bottom: "-20px",
height: "1px",
width: "100%",
background: "#9A9AAF80",
},
}}
>
<Box
sx={{
display: "flex",
gap: "15px",
}}
>
<Typography> 1. </Typography>
<Typography>Вы немного опоздали, как поступите?</Typography>
</Box>
<Typography> 20%</Typography>
</Box>
</Box>
)
}