frontPanel/src/pages/ResultPage/cards/ResultCard.tsx
2024-04-26 17:41:36 +03:00

489 lines
15 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 { useState, useEffect } from "react";
import {
getQuestionByContentId,
updateQuestion,
} from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
import CustomTextField from "@ui_kit/CustomTextField";
import {
Box,
IconButton,
Paper,
Button,
Typography,
TextField,
useMediaQuery,
useTheme,
FormControl,
Popover,
} from "@mui/material";
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
import ExpandLessIconBG from "@icons/ExpandLessIconBG";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import Trash from "@icons/trash";
import Info from "@icons/Info";
import SettingIcon from "@icons/questionsPage/settingIcon";
import { MediaSelectionAndDisplay } from "@ui_kit/MediaSelectionAndDisplay";
import type { MouseEvent } from "react";
import type { QuizQuestionResult } from "@model/questionTypes/result";
interface Props {
resultContract: boolean;
resultData: QuizQuestionResult;
}
export const checkEmptyData = ({
resultData,
}: {
resultData: QuizQuestionResult;
}) => {
let check = true;
if (
resultData.title?.length > 0 ||
resultData.description?.length > 0 ||
resultData.content.back?.length > 0 ||
resultData.content.originalBack?.length > 0 ||
resultData.content.innerName?.length > 0 ||
resultData.content.text?.length > 0 ||
resultData.content.video?.length > 0 ||
resultData.content.hint.text?.length > 0
)
check = false;
return check;
};
const InfoView = ({ resultData }: { resultData: QuizQuestionResult }) => {
const checkEmpty = checkEmptyData({ resultData });
const question = getQuestionByContentId(resultData.content.rule.parentId);
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const open = Boolean(anchorEl);
const id = open ? "simple-popover" : undefined;
return (
<>
<Info
sx={{
"MuiIconButton-root": {
boxShadow: "0 0 10px 10px red",
},
}}
className={checkEmpty ? "blink" : ""}
onClick={handleClick}
/>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
>
<Paper
sx={{
p: "20px",
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
}}
>
<Typography>
{resultData?.content.rule.parentId === "line"
? "Единый результат в конце прохождения опроса без ветвления"
: `Заголовок вопроса, после которого появится результат: "${
question?.title || "нет заголовка"
}"`}
</Typography>
{checkEmpty && (
<Typography color="red">
Вы не заполнили этот результат никакими данными
</Typography>
)}
</Paper>
</Popover>
</>
);
};
export const ResultCard = ({ resultContract, resultData }: Props) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const isTablet = useMediaQuery(theme.breakpoints.down(800));
const [expand, setExpand] = useState(true);
const [resultCardSettings, setResultCardSettings] = useState(false);
const [buttonPlus, setButtonPlus] = useState(true);
const [inputValue, setInputValue] = useState(resultData.content.text);
const question = getQuestionByContentId(resultData.content.rule.parentId);
const quiz = useCurrentQuiz();
useEffect(() => {
if (
resultData.content.hint.text ||
(quiz?.config.resultInfo.showResultForm === "after" &&
resultData.content.redirect)
) {
setButtonPlus(false);
}
}, []);
useEffect(() => {
setExpand(true);
}, [resultContract]);
return (
<Paper
data-cy="quiz-question-card"
sx={{
maxWidth: "796px",
width: "100%",
borderRadius: "12px",
backgroundColor: expand ? "white" : "#EEE4FC",
border: expand ? "none" : "1px solid #9A9AAF",
boxShadow: "0px 10px 30px #e7e7e7",
m: "20px 0",
}}
>
<Typography sx={{ color: theme.palette.grey2.main, padding: "5px 20px" }}>
{resultData?.content.rule.parentId === "line"
? "Единый результат в конце прохождения опроса без ветвления"
: `Заголовок вопроса, после которого появится результат: "${
question?.title || "нет заголовка"
}"`}
</Typography>
<Box
sx={{
display: expand ? "none" : "flex",
alignItems: "center",
padding: isMobile ? "10px" : "0 20px 20px",
justifyContent: "space-between",
minHeight: "40px",
}}
>
<FormControl
variant="standard"
sx={{
p: 0,
maxWidth: isTablet ? "549px" : "640px",
width: "100%",
marginRight: isMobile ? "0px" : "16.1px",
}}
>
<CustomTextField
value={resultData.title}
placeholder={"Заголовок результата"}
maxLength={200}
onChange={({ target }: { target: HTMLInputElement }) =>
updateQuestion(
resultData.id,
(question) => (question.title = target.value),
)
}
sx={{
margin: isMobile ? "10px 0" : 0,
backgroundColor: expand
? theme.palette.background.default
: "transparent",
height: "48px",
borderRadius: "10px",
borderWidth: "1px !important",
border: !expand ? "none" : null,
"&::placeholder": {
color: "#4D4D4D",
opacity: 0.8,
},
}}
/>
</FormControl>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
width: "auto",
position: "relative",
}}
>
<IconButton
sx={{ padding: "0", margin: "5px" }}
disableRipple
data-cy="expand-question"
onClick={() => setExpand(!expand)}
>
{expand ? (
<ExpandLessIconBG />
) : (
<ExpandLessIcon
sx={{
boxSizing: "border-box",
fill: theme.palette.brightPurple.main,
background: "#FFF",
borderRadius: "6px",
height: "30px",
width: "30px",
}}
/>
)}
</IconButton>
<InfoView resultData={resultData} />
</Box>
</Box>
{expand && (
<>
<Box
sx={{
overflow: "hidden",
maxWidth: "796px",
height: "100%",
bgcolor: "#FFFFFF",
borderRadius: "12px",
boxShadow: "0px 10px 30px #e7e7e7",
}}
>
<Box sx={{ p: "0 20px", pt: "10px" }}>
<Box
sx={{
width: "100%",
maxWidth: "760px",
display: "flex",
alignItems: "center",
gap: "10px",
mb: "19px",
}}
>
<CustomTextField
id="headline-is-bolder"
value={resultData.description}
onChange={({ target }: { target: HTMLInputElement }) =>
updateQuestion(
resultData.id,
(question) => (question.description = target.value),
)
}
placeholder={"Заголовок пожирнее"}
maxLength={200}
sx={{
borderRadius: "8px",
height: "48px",
width: "100%",
}}
/>
<IconButton
sx={{ padding: "0", margin: "5px" }}
disableRipple
data-cy="expand-question"
onClick={() => setExpand(!expand)}
>
<ExpandLessIconBG />
</IconButton>
<InfoView resultData={resultData} />
</Box>
<Box
sx={{
margin: "20px 0",
}}
>
<CustomTextField
id="heading-result"
value={resultData.title}
placeholder={"Заголовок результата"}
maxLength={200}
onChange={({ target }: { target: HTMLInputElement }) =>
updateQuestion(
resultData.id,
(question) => (question.title = target.value),
)
}
/>
</Box>
<TextField
id="heading-description"
value={inputValue}
onChange={({ target }: { target: HTMLInputElement }) => {
if (target.value.length <= 3000) {
setInputValue(target.value);
}
updateQuestion(
resultData.id,
(question) => (question.content.text = target.value),
);
}}
fullWidth
placeholder="Описание"
multiline
rows={4}
sx={{
"& .MuiInputBase-root": {
backgroundColor: "#F2F3F7",
width: "100%",
height: "110px",
borderRadius: "10px",
},
}}
inputProps={{
sx: {
height: "85px",
borderRadius: "10px",
fontSize: "18px",
lineHeight: "21px",
py: 0,
},
}}
/>
<MediaSelectionAndDisplay
resultData={resultData}
cropAspectRatio={{ width: 305.9, height: 305.9 }}
/>
{buttonPlus ? (
<Button
data-cy="add-button"
onClick={() => {
setButtonPlus(false);
}}
sx={{
display: "inline flex",
height: "48px",
padding: "10px 20px",
justifyContent: "center",
alignItems: "center",
gap: "8px",
flexShrink: 0,
borderRadius: "8px",
border: "1px solid #9A9AAF",
background: " #F2F3F7",
color: "#9A9AAF",
my: "30px",
}}
>
Кнопка +
</Button>
) : (
<Box
sx={{
my: "30px",
}}
>
<Box>
<Typography
component={"span"}
sx={{ weight: "500", fontSize: "18px", mb: "10px" }}
>
Призыв к действию
</Typography>
<IconButton
onClick={() => {
setButtonPlus(true);
updateQuestion(
resultData.id,
(q) => (q.content.hint.text = ""),
);
}}
>
<Trash />
</IconButton>
</Box>
<CustomTextField
id="button-text-result"
value={resultData.content.hint.text}
onChange={({ target }: { target: HTMLInputElement }) =>
updateQuestion(resultData.id, (question) => {
question.content.hint.text = target.value;
})
}
maxLength={19}
placeholder="Например: узнать подробнее"
sx={{
"& .MuiInputBase-root": {
backgroundColor: "#F2F3F7",
width: isMobile ? undefined : "409px",
height: "48px",
borderRadius: "8px",
},
}}
inputProps={{
sx: {
height: "85px",
borderRadius: "10px",
fontSize: "18px",
lineHeight: "21px",
py: 0,
},
}}
/>
{quiz?.config.resultInfo.showResultForm === "after" && (
<>
<Typography
sx={{
weight: "500",
fontSize: "18px",
margin: "10px 0",
}}
>
Cсылка для кнопки
</Typography>
<CustomTextField
id="link-page-result"
value={resultData.content.redirect}
onChange={({ target }: { target: HTMLInputElement }) =>
updateQuestion<QuizQuestionResult>(
resultData.id,
(question) => {
question.content.redirect = target.value;
},
)
}
placeholder="https://penahub.ru"
maxLength={200}
sx={{
"& .MuiInputBase-root": {
backgroundColor: "#F2F3F7",
width: isMobile ? undefined : "409px",
height: "48px",
borderRadius: "8px",
},
}}
inputProps={{
sx: {
height: "85px",
borderRadius: "10px",
fontSize: "18px",
lineHeight: "21px",
py: 0,
},
}}
/>
</>
)}
</Box>
)}
</Box>
</Box>
</>
)}
</Paper>
);
};