2024-02-28 08:18:21 +00:00
|
|
|
|
import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon";
|
|
|
|
|
import { CopyIcon } from "@icons/questionsPage/CopyIcon";
|
2024-05-12 17:10:14 +00:00
|
|
|
|
import CopyIconPurple from "@icons/CopyIcon";
|
2024-02-28 08:18:21 +00:00
|
|
|
|
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
|
|
|
|
import Answer from "@icons/questionsPage/answer";
|
|
|
|
|
import Date from "@icons/questionsPage/date";
|
|
|
|
|
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
|
|
|
|
import Download from "@icons/questionsPage/download";
|
|
|
|
|
import DropDown from "@icons/questionsPage/drop_down";
|
|
|
|
|
import Emoji from "@icons/questionsPage/emoji";
|
|
|
|
|
import Input from "@icons/questionsPage/input";
|
|
|
|
|
import OptionsAndPict from "@icons/questionsPage/options_and_pict";
|
|
|
|
|
import OptionsPict from "@icons/questionsPage/options_pict";
|
|
|
|
|
import Page from "@icons/questionsPage/page";
|
|
|
|
|
import RatingIcon from "@icons/questionsPage/rating";
|
|
|
|
|
import Slider from "@icons/questionsPage/slider";
|
|
|
|
|
import { QuestionType } from "@model/question/question";
|
|
|
|
|
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
|
|
|
|
import {
|
|
|
|
|
Box,
|
|
|
|
|
Button,
|
|
|
|
|
FormControl,
|
|
|
|
|
IconButton,
|
|
|
|
|
InputAdornment,
|
|
|
|
|
Modal,
|
|
|
|
|
TextField as MuiTextField,
|
|
|
|
|
TextFieldProps,
|
|
|
|
|
Typography,
|
|
|
|
|
useMediaQuery,
|
|
|
|
|
useTheme,
|
|
|
|
|
} from "@mui/material";
|
|
|
|
|
import {
|
2024-03-15 14:56:39 +00:00
|
|
|
|
collapseAllQuestions,
|
2024-02-28 08:18:21 +00:00
|
|
|
|
copyQuestion,
|
|
|
|
|
deleteQuestion,
|
|
|
|
|
deleteQuestionWithTimeout,
|
|
|
|
|
toggleExpandQuestion,
|
|
|
|
|
updateQuestion,
|
|
|
|
|
updateUntypedQuestion,
|
|
|
|
|
} from "@root/questions/actions";
|
|
|
|
|
import { DeleteFunction } from "@utils/deleteFunc";
|
|
|
|
|
import { FC, memo, useRef, useState } from "react";
|
|
|
|
|
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
|
|
|
|
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
|
|
|
|
|
|
|
|
|
const TextField = MuiTextField as unknown as FC<TextFieldProps>;
|
|
|
|
|
|
|
|
|
|
const maxLengthTextField = 225;
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
|
draggableProps: DraggableProvidedDragHandleProps | null | undefined;
|
|
|
|
|
quizId: number;
|
|
|
|
|
questionId: string;
|
2024-05-12 17:10:14 +00:00
|
|
|
|
questionBackendId: number;
|
2024-02-28 08:18:21 +00:00
|
|
|
|
questionContentId: string | null;
|
|
|
|
|
title: string;
|
|
|
|
|
questionType: QuestionType | null;
|
|
|
|
|
page: number | null;
|
|
|
|
|
isExpanded: boolean;
|
|
|
|
|
questionHasParent: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QuestionPageCardTitle = memo<Props>(function ({
|
|
|
|
|
draggableProps,
|
|
|
|
|
quizId,
|
|
|
|
|
questionId,
|
2024-05-12 17:10:14 +00:00
|
|
|
|
questionBackendId,
|
2024-02-28 08:18:21 +00:00
|
|
|
|
questionContentId,
|
|
|
|
|
title,
|
|
|
|
|
questionType,
|
|
|
|
|
page,
|
|
|
|
|
isExpanded,
|
|
|
|
|
questionHasParent,
|
|
|
|
|
}) {
|
|
|
|
|
const theme = useTheme();
|
|
|
|
|
const [open, setOpen] = useState<boolean>(false);
|
|
|
|
|
const [isTextFieldtActive, setIsTextFieldtActive] = useState(false);
|
|
|
|
|
const [openDelete, setOpenDelete] = useState<boolean>(false);
|
|
|
|
|
const anchorRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
|
|
|
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
|
|
|
|
|
|
|
|
|
const setTitle = (title: string) => {
|
|
|
|
|
const updateQuestionFn =
|
|
|
|
|
questionType === null ? updateUntypedQuestion : updateQuestion;
|
|
|
|
|
|
|
|
|
|
updateQuestionFn(questionId, (question) => {
|
|
|
|
|
question.title = title;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleInputFocus = () => {
|
|
|
|
|
setIsTextFieldtActive(true);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleInputBlur = () => {
|
|
|
|
|
setIsTextFieldtActive(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
2024-05-12 17:10:14 +00:00
|
|
|
|
<>
|
|
|
|
|
<Box
|
2024-02-28 08:18:21 +00:00
|
|
|
|
sx={{
|
2024-05-12 17:10:14 +00:00
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
padding: isMobile ? "10px" : "20px 10px 20px 20px",
|
|
|
|
|
flexDirection: "row",
|
|
|
|
|
flexWrap: isMobile && isExpanded ? "wrap" : "nowrap",
|
2024-02-28 08:18:21 +00:00
|
|
|
|
}}
|
2024-05-12 17:10:14 +00:00
|
|
|
|
>
|
|
|
|
|
<FormControl
|
|
|
|
|
variant="standard"
|
|
|
|
|
sx={{
|
|
|
|
|
p: 0,
|
|
|
|
|
maxWidth: isTablet ? "549px" : "640px",
|
|
|
|
|
width: "100%",
|
|
|
|
|
marginRight: isMobile ? "0px" : "16.1px",
|
|
|
|
|
display: "flex",
|
|
|
|
|
flexDirection: "row",
|
|
|
|
|
flexBasis: isMobile && isExpanded ? "calc(100% - 30px)" : null,
|
|
|
|
|
}}
|
2024-02-28 08:18:21 +00:00
|
|
|
|
>
|
2024-05-12 17:10:14 +00:00
|
|
|
|
<TextField
|
|
|
|
|
id="questionTitle"
|
|
|
|
|
value={title}
|
|
|
|
|
placeholder={"Заголовок вопроса"}
|
|
|
|
|
onChange={({ target }) => setTitle(target.value || " ")}
|
|
|
|
|
onFocus={handleInputFocus}
|
|
|
|
|
onBlur={handleInputBlur}
|
|
|
|
|
inputProps={{
|
|
|
|
|
maxLength: maxLengthTextField,
|
|
|
|
|
}}
|
|
|
|
|
InputProps={{
|
|
|
|
|
startAdornment: (
|
|
|
|
|
<Box>
|
|
|
|
|
<InputAdornment
|
|
|
|
|
ref={anchorRef}
|
|
|
|
|
position="start"
|
|
|
|
|
sx={{ cursor: "pointer" }}
|
|
|
|
|
onClick={() => setOpen((isOpened) => !isOpened)}
|
|
|
|
|
>
|
|
|
|
|
{IconAndrom(isExpanded, questionType)}
|
|
|
|
|
</InputAdornment>
|
|
|
|
|
<ChooseAnswerModal
|
|
|
|
|
open={open}
|
|
|
|
|
onClose={() => setOpen(false)}
|
|
|
|
|
anchorRef={anchorRef}
|
|
|
|
|
questionId={questionId}
|
|
|
|
|
questionContentId={questionContentId}
|
|
|
|
|
questionType={questionType}
|
|
|
|
|
/>
|
|
|
|
|
</Box>
|
|
|
|
|
),
|
|
|
|
|
endAdornment: isTextFieldtActive &&
|
|
|
|
|
title.length >= maxLengthTextField - 7 && (
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
marginTop: "5px",
|
|
|
|
|
marginLeft: "auto",
|
|
|
|
|
position: "absolute",
|
|
|
|
|
bottom: "-28px",
|
|
|
|
|
right: "0",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Typography fontSize="14px">{title.length}</Typography>
|
|
|
|
|
<span>/</span>
|
|
|
|
|
<Typography fontSize="14px">{maxLengthTextField}</Typography>
|
|
|
|
|
</Box>
|
|
|
|
|
),
|
|
|
|
|
}}
|
|
|
|
|
sx={{
|
|
|
|
|
flexGrow: 1,
|
|
|
|
|
margin: isMobile ? "10px 0" : 0,
|
|
|
|
|
"& .MuiInputBase-root": {
|
|
|
|
|
color: "#000000",
|
|
|
|
|
backgroundColor: isExpanded
|
|
|
|
|
? theme.palette.background.default
|
|
|
|
|
: "transparent",
|
|
|
|
|
height: "48px",
|
|
|
|
|
borderRadius: "10px",
|
|
|
|
|
".MuiOutlinedInput-notchedOutline": {
|
|
|
|
|
borderWidth: "1px !important",
|
|
|
|
|
border: !isExpanded ? "none" : null,
|
|
|
|
|
},
|
|
|
|
|
"& .MuiInputBase-input::placeholder": {
|
|
|
|
|
color: "#4D4D4D",
|
|
|
|
|
opacity: 0.8,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</FormControl>
|
2024-02-28 08:18:21 +00:00
|
|
|
|
<IconButton
|
2024-05-12 17:10:14 +00:00
|
|
|
|
disableRipple
|
|
|
|
|
sx={{
|
|
|
|
|
order: isMobile && isExpanded ? "0" : "1",
|
|
|
|
|
padding: isMobile ? "0" : "0 5px",
|
|
|
|
|
right: isMobile ? "0" : null,
|
|
|
|
|
bottom: isMobile ? "0" : null,
|
|
|
|
|
marginLeft: !isMobile && isExpanded ? "10px" : null,
|
|
|
|
|
}}
|
|
|
|
|
{...draggableProps}
|
|
|
|
|
onMouseDown={collapseAllQuestions}
|
|
|
|
|
onTouchStart={collapseAllQuestions}
|
2024-02-28 08:18:21 +00:00
|
|
|
|
>
|
2024-05-12 17:10:14 +00:00
|
|
|
|
<PointsIcon style={{ color: "#4D4D4D", fontSize: "30px" }} />
|
2024-02-28 08:18:21 +00:00
|
|
|
|
</IconButton>
|
2024-05-12 17:10:14 +00:00
|
|
|
|
<Box
|
2024-02-28 08:18:21 +00:00
|
|
|
|
sx={{
|
|
|
|
|
display: "flex",
|
2024-05-12 17:10:14 +00:00
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "flex-end",
|
|
|
|
|
width: isMobile ? "100%" : "auto",
|
|
|
|
|
position: "relative",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<IconButton
|
|
|
|
|
sx={{ padding: "0", margin: "5px" }}
|
|
|
|
|
disableRipple
|
|
|
|
|
data-cy="expand-question"
|
|
|
|
|
onClick={() => toggleExpandQuestion(questionId)}
|
2024-02-28 08:18:21 +00:00
|
|
|
|
>
|
2024-05-12 17:10:14 +00:00
|
|
|
|
{isExpanded ? (
|
|
|
|
|
<ArrowDownIcon
|
|
|
|
|
style={{
|
|
|
|
|
width: "18px",
|
|
|
|
|
color: "#4D4D4D",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<ExpandLessIcon
|
|
|
|
|
sx={{
|
|
|
|
|
boxSizing: "border-box",
|
|
|
|
|
fill: theme.palette.brightPurple.main,
|
|
|
|
|
background: "#FFF",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
height: "30px",
|
|
|
|
|
width: "30px",
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</IconButton>
|
|
|
|
|
{isExpanded ? (
|
|
|
|
|
<></>
|
|
|
|
|
) : (
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
height: "30px",
|
|
|
|
|
borderRight: "solid 1px #4D4D4D",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<IconButton
|
|
|
|
|
sx={{ padding: "0" }}
|
|
|
|
|
onClick={() => copyQuestion(questionId, quizId)}
|
|
|
|
|
>
|
|
|
|
|
<CopyIcon style={{ color: theme.palette.brightPurple.main }} />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<IconButton
|
|
|
|
|
sx={{
|
|
|
|
|
cursor: "pointer",
|
|
|
|
|
borderRadius: "6px",
|
|
|
|
|
padding: "0",
|
|
|
|
|
margin: "0 5px 0 10px",
|
|
|
|
|
}}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
if (questionType === null) {
|
|
|
|
|
deleteQuestion(questionId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (questionHasParent) {
|
|
|
|
|
setOpenDelete(true);
|
|
|
|
|
} else {
|
|
|
|
|
deleteQuestionWithTimeout(questionId, () =>
|
|
|
|
|
DeleteFunction(questionId),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
data-cy="delete-question"
|
|
|
|
|
>
|
|
|
|
|
<DeleteIcon style={{ color: theme.palette.brightPurple.main }} />
|
|
|
|
|
</IconButton>
|
|
|
|
|
<Modal open={openDelete} onClose={() => setOpenDelete(false)}>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
position: "absolute",
|
|
|
|
|
top: "50%",
|
|
|
|
|
left: "50%",
|
|
|
|
|
transform: "translate(-50%, -50%)",
|
|
|
|
|
padding: "30px",
|
|
|
|
|
borderRadius: "10px",
|
|
|
|
|
background: "#FFFFFF",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Typography variant="h6" sx={{ textAlign: "center" }}>
|
|
|
|
|
Вы удаляете вопрос, участвующий в ветвлении. Все его потомки
|
|
|
|
|
потеряют данные ветвления. Вы уверены, что хотите удалить
|
|
|
|
|
вопрос?
|
|
|
|
|
</Typography>
|
|
|
|
|
<Box
|
|
|
|
|
sx={{
|
|
|
|
|
marginTop: "30px",
|
|
|
|
|
display: "flex",
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
gap: "15px",
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<Button
|
|
|
|
|
variant="contained"
|
|
|
|
|
sx={{ minWidth: "150px" }}
|
|
|
|
|
onClick={() => setOpenDelete(false)}
|
|
|
|
|
>
|
|
|
|
|
Отмена
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
variant="contained"
|
|
|
|
|
sx={{ minWidth: "150px" }}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
deleteQuestionWithTimeout(questionId, () =>
|
|
|
|
|
DeleteFunction(questionId),
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Подтвердить
|
|
|
|
|
</Button>
|
|
|
|
|
</Box>
|
|
|
|
|
</Box>
|
|
|
|
|
</Modal>
|
|
|
|
|
</Box>
|
|
|
|
|
)}
|
|
|
|
|
{page !== null && (
|
|
|
|
|
<Box
|
|
|
|
|
style={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
justifyContent: "center",
|
|
|
|
|
height: "30px",
|
|
|
|
|
width: "30px",
|
|
|
|
|
marginLeft: "3px",
|
|
|
|
|
borderRadius: "50%",
|
|
|
|
|
fontSize: "16px",
|
|
|
|
|
color: isExpanded ? theme.palette.brightPurple.main : "#FFF",
|
|
|
|
|
background: isExpanded
|
|
|
|
|
? "#EEE4FC"
|
|
|
|
|
: theme.palette.brightPurple.main,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{page + 1}
|
|
|
|
|
</Box>
|
|
|
|
|
)}
|
|
|
|
|
</Box>
|
|
|
|
|
|
|
|
|
|
</Box>
|
|
|
|
|
{questionType !== null &&
|
|
|
|
|
<Box sx={{
|
|
|
|
|
display: "flex",
|
|
|
|
|
alignItems: "center",
|
|
|
|
|
flexWrap: isMobile ? "wrap" : undefined,
|
|
|
|
|
gap: "10px",
|
|
|
|
|
padding: "0 20px 20px 20px"
|
|
|
|
|
}}>
|
|
|
|
|
<Typography>ID Вопроса</Typography>
|
|
|
|
|
<Typography
|
|
|
|
|
id={"id-copy"}
|
|
|
|
|
>{questionBackendId}</Typography>
|
|
|
|
|
<IconButton
|
|
|
|
|
edge="end"
|
|
|
|
|
onClick={() => navigator.clipboard.writeText(document.querySelector("#id-copy").innerText)
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<CopyIconPurple
|
|
|
|
|
color={"#ffffff"}
|
|
|
|
|
width={"30px"}
|
|
|
|
|
bgcolor={theme.palette.brightPurple.main}
|
|
|
|
|
/>
|
|
|
|
|
</IconButton>
|
|
|
|
|
</Box>}
|
|
|
|
|
</>
|
2024-02-28 08:18:21 +00:00
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
QuestionPageCardTitle.displayName = "QuestionPageCardTitle";
|
|
|
|
|
|
|
|
|
|
export default QuestionPageCardTitle;
|
|
|
|
|
|
|
|
|
|
const IconAndrom = (isExpanded: boolean, questionType: QuestionType | null) => {
|
|
|
|
|
switch (questionType) {
|
|
|
|
|
case "variant":
|
|
|
|
|
return (
|
|
|
|
|
<Answer
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "images":
|
|
|
|
|
return (
|
|
|
|
|
<OptionsPict
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "varimg":
|
|
|
|
|
return (
|
|
|
|
|
<OptionsAndPict
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "emoji":
|
|
|
|
|
return (
|
|
|
|
|
<Emoji
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "text":
|
|
|
|
|
return (
|
|
|
|
|
<Input
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "select":
|
|
|
|
|
return (
|
|
|
|
|
<DropDown
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "date":
|
|
|
|
|
return (
|
|
|
|
|
<Date
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "number":
|
|
|
|
|
return (
|
|
|
|
|
<Slider
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "file":
|
|
|
|
|
return (
|
|
|
|
|
<Download
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "page":
|
|
|
|
|
return (
|
|
|
|
|
<Page
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
case "rating":
|
|
|
|
|
return (
|
|
|
|
|
<RatingIcon
|
|
|
|
|
color={isExpanded ? "#9A9AAF" : "#7E2AEA"}
|
|
|
|
|
sx={{ height: "22px", width: "20px" }}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
default:
|
|
|
|
|
return <></>;
|
|
|
|
|
}
|
|
|
|
|
};
|