numbered the questions in the Questionnaire type

This commit is contained in:
ArtChaos189 2023-12-16 15:17:07 +03:00
parent 194c3aade5
commit 5fb444e7bc
8 changed files with 947 additions and 960 deletions

@ -18,18 +18,28 @@ import RatingIcon from "@icons/questionsPage/rating";
import Slider from "@icons/questionsPage/slider";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import {
Box,
Checkbox,
FormControl,
FormControlLabel,
IconButton,
InputAdornment,
Paper,
TextField,
useMediaQuery,
useTheme,
Box,
Checkbox,
FormControl,
FormControlLabel,
IconButton,
InputAdornment,
Paper,
TextField,
useMediaQuery,
useTheme,
} from "@mui/material";
import { copyQuestion, createUntypedQuestion, deleteQuestion, clearRuleForAll, toggleExpandQuestion, updateQuestion, updateUntypedQuestion, getQuestionByContentId, deleteQuestionWithTimeout } from "@root/questions/actions";
import {
copyQuestion,
createUntypedQuestion,
deleteQuestion,
clearRuleForAll,
toggleExpandQuestion,
updateQuestion,
updateUntypedQuestion,
getQuestionByContentId,
deleteQuestionWithTimeout,
} from "@root/questions/actions";
import { updateRootContentId } from "@root/quizes/actions";
import { useRef, useState } from "react";
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
@ -44,445 +54,387 @@ import { useCurrentQuiz } from "@root/quizes/hooks";
import { useQuestionsStore } from "@root/questions/store";
interface Props {
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
draggableProps: DraggableProvidedDragHandleProps | null | undefined;
isDragging: boolean;
index: number;
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
draggableProps: DraggableProvidedDragHandleProps | null | undefined;
isDragging: boolean;
index: number;
}
export default function QuestionsPageCard({ question, draggableProps, isDragging, index }: Props) {
const { questions } = useQuestionsStore();
const [plusVisible, setPlusVisible] = useState<boolean>(false);
const [open, setOpen] = useState<boolean>(false);
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const anchorRef = useRef(null);
const quiz = useCurrentQuiz();
const { questions } = useQuestionsStore();
const [plusVisible, setPlusVisible] = useState<boolean>(false);
const [open, setOpen] = useState<boolean>(false);
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const anchorRef = useRef(null);
const quiz = useCurrentQuiz();
const setTitle = useDebouncedCallback((title) => {
const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
const setTitle = useDebouncedCallback((title) => {
const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
updateQuestionFn(question.id, question => {
question.title = title;
});
}, 200);
updateQuestionFn(question.id, (question) => {
question.title = title;
});
}, 200);
return (
<>
<Paper
id={question.id}
data-cy="quiz-question-card"
sx={{
maxWidth: "796px",
width: "100%",
borderRadius: "12px",
backgroundColor: question.expanded ? "white" : "#EEE4FC",
border: question.expanded ? "none" : "1px solid #9A9AAF",
boxShadow: "0px 10px 30px #e7e7e7",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
padding: isMobile ? "10px" : "20px 10px 20px 20px",
flexDirection: isMobile ? "column" : null,
}}
>
<FormControl
variant="standard"
sx={{
p: 0,
maxWidth: isTablet ? "549px" : "640px",
width: "100%",
marginRight: isMobile ? "0px" : "16.1px",
}}
return (
<>
<Paper
id={question.id}
data-cy="quiz-question-card"
sx={{
maxWidth: "796px",
width: "100%",
borderRadius: "12px",
backgroundColor: question.expanded ? "white" : "#EEE4FC",
border: question.expanded ? "none" : "1px solid #9A9AAF",
boxShadow: "0px 10px 30px #e7e7e7",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
padding: isMobile ? "10px" : "20px 10px 20px 20px",
flexDirection: isMobile ? "column" : null,
}}
>
<FormControl
variant="standard"
sx={{
p: 0,
maxWidth: isTablet ? "549px" : "640px",
width: "100%",
marginRight: isMobile ? "0px" : "16.1px",
}}
>
<TextField
defaultValue={question.title}
placeholder={"Заголовок вопроса"}
onChange={({ target }: { target: HTMLInputElement }) => setTitle(target.value || " ")}
InputProps={{
startAdornment: (
<Box>
<InputAdornment
ref={anchorRef}
position="start"
sx={{ cursor: "pointer" }}
onClick={() => setOpen((isOpened) => !isOpened)}
>
<TextField
defaultValue={question.title}
placeholder={"Заголовок вопроса"}
onChange={({ target }: { target: HTMLInputElement; }) => setTitle(target.value || " ")}
InputProps={{
startAdornment: (
<Box>
<InputAdornment
ref={anchorRef}
position="start"
sx={{ cursor: "pointer" }}
onClick={() => setOpen((isOpened) => !isOpened)}
>
{IconAndrom(question.expanded, question.type)}
</InputAdornment>
<ChooseAnswerModal
open={open}
onClose={() => setOpen(false)}
anchorRef={anchorRef}
question={question}
questionType={question.type}
/>
</Box>
),
}}
sx={{
margin: isMobile ? "10px 0" : 0,
"& .MuiInputBase-root": {
color: "#000000",
backgroundColor: question.expanded
? theme.palette.background.default
: "transparent",
height: "48px",
borderRadius: "10px",
".MuiOutlinedInput-notchedOutline": {
borderWidth: "1px !important",
border: !question.expanded ? "none" : null,
},
"& .MuiInputBase-input::placeholder": {
color: "#4D4D4D",
opacity: 0.8,
},
},
}}
inputProps={{
sx: {
fontSize: "18px",
lineHeight: "21px",
py: 0,
paddingLeft: question.type === null ? 0 : "18px",
},
"data-cy": "quiz-question-title",
}}
/>
</FormControl>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
width: isMobile ? "100%" : "auto",
position: "relative",
}}
>
<IconButton
sx={{ padding: "0", margin: "5px" }}
disableRipple
data-cy="expand-question"
onClick={() => toggleExpandQuestion(question.id)}
>
{question.expanded ? (
<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>
{question.expanded ? (
<></>
) : (
<Box
sx={{
display: "flex",
height: "30px",
borderRight: "solid 1px #4D4D4D",
}}
>
<FormControlLabel
control={
<Checkbox
icon={
<HideIcon
style={{
boxSizing: "border-box",
color: "#7E2AEA",
background: "#FFF",
borderRadius: "6px",
height: "30px",
width: "30px",
padding: "3px",
}}
/>
}
checkedIcon={<CrossedEyeIcon />}
/>
}
label={""}
sx={{
color: theme.palette.grey2.main,
ml: "-9px",
mr: 0,
userSelect: "none",
}}
/>
<IconButton
sx={{ padding: "0" }}
onClick={() => copyQuestion(question.id, question.quizId)}
>
<CopyIcon
style={{ color: theme.palette.brightPurple.main }}
/>
</IconButton>
<IconButton
sx={{
cursor: "pointer",
borderRadius: "6px",
padding: "0",
margin: "0 5px 0 10px",
}}
onClick={() => {
const deleteFn = () => {
if (question.type !== null) {
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
updateRootContentId(quiz.id, "");
clearRuleForAll();
deleteQuestion(question.id);
questions.forEach(q => {
if (q.type === "result") {
deleteQuestion(q.id);
}
});
} else if (question.content.rule.parentId.length > 0) { //удалить из стора вопрос из дерева и очистить его потомков
const clearQuestions = [] as string[];
//записываем потомков , а их результаты удаляем
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
questions.forEach((targetQuestion) => {
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {//если у вопроса совпал родитель с родителем => он потомок, в кучу его
if (targetQuestion.type === "result") {
deleteQuestion(targetQuestion.id);
} else {
if (!clearQuestions.includes(targetQuestion.content.id)) clearQuestions.push(targetQuestion.content.id);
getChildren(targetQuestion); //и ищем его потомков
}
}
});
};
getChildren(question);
//чистим потомков от инфы ветвления
clearQuestions.forEach((id) => {
updateQuestion(id, question => {
question.content.rule.parentId = "";
question.content.rule.main = [];
question.content.rule.default = "";
});
});
//чистим rule родителя
const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
const newRule = {};
newRule.main = parentQuestion.content.rule.main.filter((data) => data.next !== question.content.id); //удаляем условия перехода от родителя к этому вопросу
newRule.parentId = parentQuestion.content.rule.parentId;
newRule.default = parentQuestion.content.rule.parentId === question.content.id ? "" : parentQuestion.content.rule.parentId;
newRule.children = [...parentQuestion.content.rule.children].splice(parentQuestion.content.rule.children.indexOf(question.content.id), 1);
updateQuestion(question.content.rule.parentId, (PQ) => {
PQ.content.rule = newRule;
});
deleteQuestion(question.id);
}
deleteQuestion(question.id);
} else {
console.log("удаляю безтипогово");
deleteQuestion(question.id);
}
};
deleteQuestionWithTimeout(question.id, deleteFn);
}}
data-cy="delete-question"
>
<DeleteIcon
style={{ color: theme.palette.brightPurple.main }}
/>
</IconButton>
</Box>
)}
{question.type !== null &&
<Box
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "30px",
width: "30px",
marginLeft: "3px",
borderRadius: "50%",
fontSize: "16px",
color: question.expanded
? theme.palette.brightPurple.main
: "#FFF",
background: question.expanded
? "#EEE4FC"
: theme.palette.brightPurple.main,
}}
>
{question.page + 1}
</Box>
}
<IconButton
disableRipple
sx={{
padding: isMobile ? "0" : "0 5px",
right: isMobile ? "0" : null,
bottom: isMobile ? "0" : null,
}}
{...draggableProps}
>
<PointsIcon style={{ color: "#4D4D4D", fontSize: "30px" }} />
</IconButton>
</Box>
</Box>
{question.expanded && (
<Box
sx={{
display: "flex",
flexDirection: "column",
padding: 0,
borderRadius: "12px",
}}
>
{question.type === null ? (
<TypeQuestions question={question} />
) : (
<SwitchQuestionsPage question={question} />
)}
</Box>
)}
</Paper>
<Box
onMouseEnter={() => setPlusVisible(true)}
onMouseLeave={() => setPlusVisible(false)}
sx={{
maxWidth: "825px",
display: "flex",
alignItems: "center",
height: "40px",
cursor: "pointer",
}}
>
<Box
onClick={() => createUntypedQuestion(question.quizId, question.id)}
sx={{
display: plusVisible && !isDragging ? "flex" : "none",
width: "100%",
alignItems: "center",
columnGap: "10px",
}}
data-cy="create-question"
>
<Box
sx={{
boxSizing: "border-box",
width: "100%",
height: "1px",
backgroundPosition: "bottom",
backgroundRepeat: "repeat-x",
backgroundSize: "20px 1px",
backgroundImage:
"radial-gradient(circle, #7E2AEA 6px, #F2F3F7 1px)",
}}
{IconAndrom(question.expanded, question.type)}
</InputAdornment>
<ChooseAnswerModal
open={open}
onClose={() => setOpen(false)}
anchorRef={anchorRef}
question={question}
questionType={question.type}
/>
<PlusIcon />
</Box>
</Box>
</>
);
</Box>
),
}}
sx={{
margin: isMobile ? "10px 0" : 0,
"& .MuiInputBase-root": {
color: "#000000",
backgroundColor: question.expanded ? theme.palette.background.default : "transparent",
height: "48px",
borderRadius: "10px",
".MuiOutlinedInput-notchedOutline": {
borderWidth: "1px !important",
border: !question.expanded ? "none" : null,
},
"& .MuiInputBase-input::placeholder": {
color: "#4D4D4D",
opacity: 0.8,
},
},
}}
inputProps={{
sx: {
fontSize: "18px",
lineHeight: "21px",
py: 0,
paddingLeft: question.type === null ? 0 : "18px",
},
"data-cy": "quiz-question-title",
}}
/>
</FormControl>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
width: isMobile ? "100%" : "auto",
position: "relative",
}}
>
<IconButton
sx={{ padding: "0", margin: "5px" }}
disableRipple
data-cy="expand-question"
onClick={() => toggleExpandQuestion(question.id)}
>
{question.expanded ? (
<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>
{question.expanded ? (
<></>
) : (
<Box
sx={{
display: "flex",
height: "30px",
borderRight: "solid 1px #4D4D4D",
}}
>
<FormControlLabel
control={
<Checkbox
icon={
<HideIcon
style={{
boxSizing: "border-box",
color: "#7E2AEA",
background: "#FFF",
borderRadius: "6px",
height: "30px",
width: "30px",
padding: "3px",
}}
/>
}
checkedIcon={<CrossedEyeIcon />}
/>
}
label={""}
sx={{
color: theme.palette.grey2.main,
ml: "-9px",
mr: 0,
userSelect: "none",
}}
/>
<IconButton sx={{ padding: "0" }} onClick={() => copyQuestion(question.id, question.quizId)}>
<CopyIcon style={{ color: theme.palette.brightPurple.main }} />
</IconButton>
<IconButton
sx={{
cursor: "pointer",
borderRadius: "6px",
padding: "0",
margin: "0 5px 0 10px",
}}
onClick={() => {
const deleteFn = () => {
if (question.type !== null) {
if (question.content.rule.parentId === "root") {
//удалить из стора root и очистить rule всем вопросам
updateRootContentId(quiz.id, "");
clearRuleForAll();
deleteQuestion(question.id);
questions.forEach((q) => {
if (q.type === "result") {
deleteQuestion(q.id);
}
});
} else if (question.content.rule.parentId.length > 0) {
//удалить из стора вопрос из дерева и очистить его потомков
const clearQuestions = [] as string[];
//записываем потомков , а их результаты удаляем
const getChildren = (parentQuestion: AnyTypedQuizQuestion) => {
questions.forEach((targetQuestion) => {
if (targetQuestion.content.rule.parentId === parentQuestion.content.id) {
//если у вопроса совпал родитель с родителем => он потомок, в кучу его
if (targetQuestion.type === "result") {
deleteQuestion(targetQuestion.id);
} else {
if (!clearQuestions.includes(targetQuestion.content.id))
clearQuestions.push(targetQuestion.content.id);
getChildren(targetQuestion); //и ищем его потомков
}
}
});
};
getChildren(question);
//чистим потомков от инфы ветвления
clearQuestions.forEach((id) => {
updateQuestion(id, (question) => {
question.content.rule.parentId = "";
question.content.rule.main = [];
question.content.rule.default = "";
});
});
//чистим rule родителя
const parentQuestion = getQuestionByContentId(question.content.rule.parentId);
const newRule = {};
newRule.main = parentQuestion.content.rule.main.filter(
(data) => data.next !== question.content.id
); //удаляем условия перехода от родителя к этому вопросу
newRule.parentId = parentQuestion.content.rule.parentId;
newRule.default =
parentQuestion.content.rule.parentId === question.content.id
? ""
: parentQuestion.content.rule.parentId;
newRule.children = [...parentQuestion.content.rule.children].splice(
parentQuestion.content.rule.children.indexOf(question.content.id),
1
);
updateQuestion(question.content.rule.parentId, (PQ) => {
PQ.content.rule = newRule;
});
deleteQuestion(question.id);
}
deleteQuestion(question.id);
} else {
console.log("удаляю безтипогово");
deleteQuestion(question.id);
}
};
deleteQuestionWithTimeout(question.id, deleteFn);
}}
data-cy="delete-question"
>
<DeleteIcon style={{ color: theme.palette.brightPurple.main }} />
</IconButton>
</Box>
)}
{question.type !== null && (
<Box
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "30px",
width: "30px",
marginLeft: "3px",
borderRadius: "50%",
fontSize: "16px",
color: question.expanded ? theme.palette.brightPurple.main : "#FFF",
background: question.expanded ? "#EEE4FC" : theme.palette.brightPurple.main,
}}
>
{question.page + 1}
</Box>
)}
<IconButton
disableRipple
sx={{
padding: isMobile ? "0" : "0 5px",
right: isMobile ? "0" : null,
bottom: isMobile ? "0" : null,
}}
{...draggableProps}
>
<PointsIcon style={{ color: "#4D4D4D", fontSize: "30px" }} />
</IconButton>
</Box>
</Box>
{question.expanded && (
<Box
sx={{
display: "flex",
flexDirection: "column",
padding: 0,
borderRadius: "12px",
}}
>
{question.type === null ? (
<TypeQuestions question={question} />
) : (
<SwitchQuestionsPage question={question} />
)}
</Box>
)}
</Paper>
<Box
onMouseEnter={() => setPlusVisible(true)}
onMouseLeave={() => setPlusVisible(false)}
sx={{
maxWidth: "825px",
display: "flex",
alignItems: "center",
height: "40px",
cursor: "pointer",
}}
>
<Box
onClick={() => createUntypedQuestion(question.quizId, question.id)}
sx={{
display: plusVisible && !isDragging ? "flex" : "none",
width: "100%",
alignItems: "center",
columnGap: "10px",
}}
data-cy="create-question"
>
<Box
sx={{
boxSizing: "border-box",
width: "100%",
height: "1px",
backgroundPosition: "bottom",
backgroundRepeat: "repeat-x",
backgroundSize: "20px 1px",
backgroundImage: "radial-gradient(circle, #7E2AEA 6px, #F2F3F7 1px)",
}}
/>
<PlusIcon />
</Box>
</Box>
</>
);
}
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 <></>;
}
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 <></>;
}
};

@ -5,80 +5,77 @@ import { Draggable } from "react-beautiful-dnd";
import { AnyTypedQuizQuestion, UntypedQuizQuestion } from "../../../../model/questionTypes/shared";
import QuestionsPageCard from "./QuestionPageCard";
type FormDraggableListItemProps = {
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
questionIndex: number;
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
questionIndex: number;
};
export default memo(
({ question, questionIndex }: FormDraggableListItemProps) => {
const theme = useTheme();
export default memo(({ question, questionIndex }: FormDraggableListItemProps) => {
const theme = useTheme();
return (
<Draggable draggableId={String(questionIndex)} index={questionIndex}>
{(provided) => (
<ListItem
ref={provided.innerRef}
{...(questionIndex !== 0 ? provided.draggableProps : {})}
sx={{ userSelect: "none", padding: 0 }}
>
{question.deleted ? (
<Box
{...provided.dragHandleProps}
sx={{
width: "100%",
maxWidth: "800px",
display: "flex",
justifyContent: "center",
marginTop: "30px",
gap: "5px",
}}
>
<Typography
sx={{
fontSize: "16px",
color: theme.palette.grey2.main,
}}
>
Вопрос удалён.
</Typography>
<Typography
onClick={() => {
updateQuestion(question.id, question => {
question.deleted = false;
});
}}
sx={{
cursor: "pointer",
fontSize: "16px",
textDecoration: "underline",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
>
Восстановить?
</Typography>
</Box>
) : (
<Box
sx={{
width: "100%",
position: "relative",
borderBottom: "1px solid rgba(0, 0, 0, 0.23)",
}}
>
<QuestionsPageCard
key={questionIndex}
question={question}
questionIndex={questionIndex}
draggableProps={provided.dragHandleProps}
/>
</Box>
)}
</ListItem>
)}
</Draggable>
);
}
);
return (
<Draggable draggableId={String(questionIndex)} index={questionIndex}>
{(provided) => (
<ListItem
ref={provided.innerRef}
{...(questionIndex !== 0 ? provided.draggableProps : {})}
sx={{ userSelect: "none", padding: 0 }}
>
{question.deleted ? (
<Box
{...provided.dragHandleProps}
sx={{
width: "100%",
maxWidth: "800px",
display: "flex",
justifyContent: "center",
marginTop: "30px",
gap: "5px",
}}
>
<Typography
sx={{
fontSize: "16px",
color: theme.palette.grey2.main,
}}
>
Вопрос удалён.
</Typography>
<Typography
onClick={() => {
updateQuestion(question.id, (question) => {
question.deleted = false;
});
}}
sx={{
cursor: "pointer",
fontSize: "16px",
textDecoration: "underline",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
>
Восстановить?
</Typography>
</Box>
) : (
<Box
sx={{
width: "100%",
position: "relative",
borderBottom: "1px solid rgba(0, 0, 0, 0.23)",
}}
>
<QuestionsPageCard
key={questionIndex}
question={question}
questionIndex={questionIndex}
draggableProps={provided.dragHandleProps}
/>
</Box>
)}
</ListItem>
)}
</Draggable>
);
});

@ -11,8 +11,8 @@ 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 { Box, InputAdornment, Paper } from "@mui/material";
import { updateQuestion, updateUntypedQuestion } from "@root/questions/actions";
import { Box, FormControlLabel, IconButton, InputAdornment, Paper, useMediaQuery, useTheme } from "@mui/material";
import { toggleExpandQuestion, updateQuestion, updateUntypedQuestion } from "@root/questions/actions";
import CustomTextField from "@ui_kit/CustomTextField";
import { useRef, useState } from "react";
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
@ -22,142 +22,206 @@ import SwitchQuestionsPage from "../../SwitchQuestionsPage";
import { ChooseAnswerModal } from "./ChooseAnswerModal";
import FormTypeQuestions from "../FormTypeQuestions";
import { QuestionType } from "@model/question/question";
import { CrossedEyeIcon } from "@icons/CrossedEyeIcon";
import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon";
import { CopyIcon } from "@icons/questionsPage/CopyIcon";
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
import { HideIcon } from "@icons/questionsPage/hideIcon";
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
import { NoLuggageOutlined, SignalCellularNullOutlined } from "@mui/icons-material";
interface Props {
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
questionIndex: number;
draggableProps: DraggableProvidedDragHandleProps | null | undefined;
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
questionIndex: number;
draggableProps: DraggableProvidedDragHandleProps | null | undefined;
}
export default function QuestionsPageCard({
question,
questionIndex,
draggableProps,
}: Props) {
const [open, setOpen] = useState<boolean>(false);
const anchorRef = useRef(null);
export default function QuestionsPageCard({ question, questionIndex, draggableProps }: Props) {
const [open, setOpen] = useState<boolean>(false);
const anchorRef = useRef(null);
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const setTitle = useDebouncedCallback((title) => {
const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
const setTitle = useDebouncedCallback((title) => {
const updateQuestionFn = question.type === null ? updateUntypedQuestion : updateQuestion;
updateQuestionFn(question.id, question => {
question.title = title;
});
}, 200);
updateQuestionFn(question.id, (question) => {
question.title = title;
});
}, 200);
return (
<>
<Paper
sx={{
overflow: "hidden",
maxWidth: "796px",
width: "100%",
backgroundColor: "white",
border: "none",
boxShadow: "none",
paddingBottom: "20px",
borderRadius: "0",
borderTopLeftRadius: "12px",
borderTopRightRadius: "12px",
}}
>
<Box
sx={{
display: "flex",
flexDirection: "column",
padding: 0,
}}
>
<CustomTextField
placeholder={`Заголовок ${questionIndex + 1} вопроса`}
text={question.title}
onChange={({ target }) => setTitle(target.value)}
sx={{ margin: "20px", width: "auto" }}
InputProps={{
startAdornment: (
<Box>
<InputAdornment
ref={anchorRef}
position="start"
sx={{ cursor: "pointer" }}
onClick={() => setOpen((isOpened) => !isOpened)}
>
{IconAndrom(question.type)}
</InputAdornment>
<ChooseAnswerModal
open={open}
onClose={() => setOpen(false)}
anchorRef={anchorRef}
question={question}
questionType={question.type}
/>
</Box>
),
endAdornment: (
<Box {...draggableProps}>
{questionIndex !== 0 && (
<InputAdornment position="start">
<PointsIcon
style={{ color: "#9A9AAF", fontSize: "30px" }}
/>
</InputAdornment>
)}
</Box>
),
}}
return (
<>
<Paper
sx={{
overflow: "hidden",
maxWidth: "796px",
width: "100%",
backgroundColor: "white",
border: "none",
boxShadow: "none",
paddingBottom: "20px",
borderRadius: "0",
borderTopLeftRadius: "12px",
borderTopRightRadius: "12px",
}}
>
<Box
sx={{
display: "flex",
p: 0,
flexDirection: "column",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
margin: "20px",
gap: "18px",
flexDirection: isMobile ? "column-reverse" : null,
}}
>
<CustomTextField
placeholder={`Заголовок ${questionIndex + 1} вопроса`}
text={question.title}
onChange={({ target }) => setTitle(target.value)}
sx={{ width: "100%" }}
InputProps={{
startAdornment: (
<Box>
<InputAdornment
ref={anchorRef}
position="start"
sx={{ cursor: "pointer" }}
onClick={() => setOpen((isOpened) => !isOpened)}
>
{IconAndrom(question.type)}
</InputAdornment>
<ChooseAnswerModal
open={open}
onClose={() => setOpen(false)}
anchorRef={anchorRef}
question={question}
questionType={question.type}
/>
{question.type === null ? (
<FormTypeQuestions question={question} />
) : (
<SwitchQuestionsPage question={question} />
)}
</Box>
),
}}
/>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: isMobile ? "100%" : "auto",
position: "relative",
}}
>
<Box
sx={{
flexDirection: isMobile ? "row-reverse" : null,
display: "flex",
alignItems: "center",
gap: "4px",
}}
>
<IconButton
sx={{ padding: "0", margin: "5px" }}
disableRipple
data-cy="expand-question"
onClick={() => toggleExpandQuestion(question.id)}
>
{question.expanded ? (
<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>
<Box
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
height: "30px",
width: "30px",
marginLeft: "3px",
borderRadius: "50%",
fontSize: "16px",
color: question.expanded ? theme.palette.brightPurple.main : "#FFF",
background: question.expanded ? "#EEE4FC" : theme.palette.brightPurple.main,
}}
>
{questionIndex + 1}
</Box>
</Paper>
</>
);
</Box>
<IconButton
disableRipple
sx={{
padding: isMobile ? "0" : "0 5px",
right: isMobile ? "0" : null,
bottom: isMobile ? "0" : null,
}}
{...draggableProps}
>
<PointsIcon style={{ color: "#4D4D4D", fontSize: "30px" }} />
</IconButton>
</Box>
</Box>
{question.type === null ? (
<FormTypeQuestions question={question} />
) : (
<SwitchQuestionsPage question={question} />
)}
</Box>
</Paper>
</>
);
}
const IconAndrom = (questionType: QuestionType | null) => {
switch (questionType) {
case "variant":
return <Answer color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "images":
return (
<OptionsPict color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />
);
case "varimg":
return (
<OptionsAndPict
color="#9A9AAF"
sx={{ height: "22px", width: "20px" }}
/>
);
case "emoji":
return <Emoji color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "text":
return <Input color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "select":
return (
<DropDown color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />
);
case "date":
return <Date color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "number":
return <Slider color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "file":
return (
<Download color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />
);
case "page":
return <Page color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "rating":
return (
<RatingIcon color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />
);
default:
return (
<AnswerGroup color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />
);
}
switch (questionType) {
case "variant":
return <Answer color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "images":
return <OptionsPict color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "varimg":
return <OptionsAndPict color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "emoji":
return <Emoji color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "text":
return <Input color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "select":
return <DropDown color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "date":
return <Date color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "number":
return <Slider color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "file":
return <Download color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "page":
return <Page color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
case "rating":
return <RatingIcon color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
default:
return <AnswerGroup color="#9A9AAF" sx={{ height: "22px", width: "20px" }} />;
}
};

@ -5,31 +5,25 @@ import { DragDropContext, Droppable } from "react-beautiful-dnd";
import FormDraggableListItem from "./FormDraggableListItem";
import { useQuestions } from "@root/questions/hooks";
export const FormDraggableList = () => {
const { questions } = useQuestions();
const { questions } = useQuestions()
const onDragEnd = ({ destination, source }: DropResult) => {
if (destination) reorderQuestions(source.index, destination.index);
};
const onDragEnd = ({ destination, source }: DropResult) => {
if (destination) reorderQuestions(source.index, destination.index);
};
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable-list">
{(provided) => (
<Box ref={provided.innerRef} {...provided.droppableProps}>
{questions?.map((question, index) => (
<FormDraggableListItem
key={question.id}
question={question}
questionIndex={index}
/>
))}
{provided.placeholder}
</Box>
)}
</Droppable>
</DragDropContext>
);
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable-list">
{(provided) => (
<Box ref={provided.innerRef} {...provided.droppableProps}>
{questions?.map((question, index) => (
<FormDraggableListItem key={question.id} question={question} questionIndex={index} />
))}
{provided.placeholder}
</Box>
)}
</Droppable>
</DragDropContext>
);
};

@ -8,106 +8,103 @@ import { FormDraggableList } from "./FormDraggableList";
import { collapseAllQuestions, createUntypedQuestion } from "@root/questions/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
export default function FormQuestionsPage() {
const theme = useTheme();
const quiz = useCurrentQuiz();
const theme = useTheme();
const quiz = useCurrentQuiz();
if (!quiz) return null;
if (!quiz) return null;
return (
<>
<Box
sx={{
maxWidth: "796px",
width: "100%",
display: "flex",
justifyContent: "space-between",
margin: "60px 0 40px 0",
}}
>
<Typography variant={"h5"}>Заголовок анкеты</Typography>
<Button
sx={{
fontSize: "16px",
lineHeight: "19px",
padding: 0,
textDecoration: "underline",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
onClick={collapseAllQuestions}
>
Свернуть всё
</Button>
</Box>
<Box
sx={{
maxWidth: "796px",
boxShadow: "0px 10px 30px #e7e7e7",
borderRadius: "12px",
marginBottom: "30px",
borderTop: "1px solid transparent",
borderBottom: "1px solid transparent",
background: "#FFFFFF",
}}
>
<FormDraggableList />
<Box
sx={{
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: "15px",
padding: "4px",
margin: "15px",
border: "1px solid transparent",
borderRadius: "8px",
"&:hover": {
border: "1px solid #9A9AAF",
},
}}
onClick={() => {
createUntypedQuestion(quiz.backendId);
}}
data-cy="create-question"
>
<AddAnswer color="#EEE4FC" />
<Typography sx={{ color: "#9A9AAF" }}>
Добавить еще один вопрос
</Typography>
</Box>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
gap: "8px",
maxWidth: "796px",
}}
>
<Button
variant="outlined"
sx={{ padding: "10px 20px", borderRadius: "8px", height: "44px" }}
onClick={decrementCurrentStep}
>
<ArrowLeft />
</Button>
<Button
variant="contained"
sx={{
height: "44px",
padding: "10px 20px",
borderRadius: "8px",
background: theme.palette.brightPurple.main,
fontSize: "18px",
}}
onClick={incrementCurrentStep}
>
Следующий шаг
</Button>
</Box>
{createPortal(<QuizPreview />, document.body)}
</>
);
return (
<>
<Box
sx={{
maxWidth: "796px",
width: "100%",
display: "flex",
justifyContent: "space-between",
margin: "60px 0 40px 0",
}}
>
<Typography variant={"h5"}>Заголовок анкеты</Typography>
<Button
sx={{
fontSize: "16px",
lineHeight: "19px",
padding: 0,
textDecoration: "underline",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
onClick={collapseAllQuestions}
>
Свернуть всё
</Button>
</Box>
<Box
sx={{
maxWidth: "796px",
boxShadow: "0px 10px 30px #e7e7e7",
borderRadius: "12px",
marginBottom: "30px",
borderTop: "1px solid transparent",
borderBottom: "1px solid transparent",
background: "#FFFFFF",
}}
>
<FormDraggableList />
<Box
sx={{
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: "15px",
padding: "4px",
margin: "15px",
border: "1px solid transparent",
borderRadius: "8px",
"&:hover": {
border: "1px solid #9A9AAF",
},
}}
onClick={() => {
createUntypedQuestion(quiz.backendId);
}}
data-cy="create-question"
>
<AddAnswer color="#EEE4FC" />
<Typography sx={{ color: "#9A9AAF" }}>Добавить еще один вопрос</Typography>
</Box>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "flex-end",
gap: "8px",
maxWidth: "796px",
}}
>
<Button
variant="outlined"
sx={{ padding: "10px 20px", borderRadius: "8px", height: "44px" }}
onClick={decrementCurrentStep}
>
<ArrowLeft />
</Button>
<Button
variant="contained"
sx={{
height: "44px",
padding: "10px 20px",
borderRadius: "8px",
background: theme.palette.brightPurple.main,
fontSize: "18px",
}}
onClick={incrementCurrentStep}
>
Следующий шаг
</Button>
</Box>
{createPortal(<QuizPreview />, document.body)}
</>
);
}

@ -12,80 +12,75 @@ import Slider from "../../../assets/icons/questionsPage/slider";
import { QuestionType } from "@model/question/question";
import { createTypedQuestion } from "@root/questions/actions";
import type {
UntypedQuizQuestion
} from "../../../model/questionTypes/shared";
import type { UntypedQuizQuestion } from "../../../model/questionTypes/shared";
type ButtonTypeQuestion = {
icon: JSX.Element;
title: string;
value: QuestionType;
icon: JSX.Element;
title: string;
value: QuestionType;
};
const BUTTON_TYPE_SHORT_QUESTIONS: ButtonTypeQuestion[] = [
{
icon: <Answer color="#9A9AAF" />,
title: "Варианты ответов",
value: "variant",
},
{
icon: <Input color="#9A9AAF" />,
title: "Своё поле для ввода",
value: "text",
},
{
icon: <DropDown color="#9A9AAF" />,
title: "Выпадающий список",
value: "select",
},
{
icon: <Date color="#9A9AAF" />,
title: "Дата",
value: "date",
},
{
icon: <Slider color="#9A9AAF" />,
title: "Ползунок",
value: "number",
},
{
icon: <Download color="#9A9AAF" />,
title: "Загрузка файла",
value: "file",
},
{
icon: <Answer color="#9A9AAF" />,
title: "Варианты ответов",
value: "variant",
},
{
icon: <Input color="#9A9AAF" />,
title: "Своё поле для ввода",
value: "text",
},
{
icon: <DropDown color="#9A9AAF" />,
title: "Выпадающий список",
value: "select",
},
{
icon: <Date color="#9A9AAF" />,
title: "Дата",
value: "date",
},
{
icon: <Slider color="#9A9AAF" />,
title: "Ползунок",
value: "number",
},
{
icon: <Download color="#9A9AAF" />,
title: "Загрузка файла",
value: "file",
},
];
interface Props {
question: UntypedQuizQuestion;
question: UntypedQuizQuestion;
}
export default function FormTypeQuestions({ question }: Props) {
return (
<Box>
<Box
sx={{
display: "flex",
flexWrap: "wrap",
gap: "20px",
margin: "20px",
}}
>
{(("page" in question) && question.page === 0
? BUTTON_TYPE_QUESTIONS
: BUTTON_TYPE_SHORT_QUESTIONS
).map(({ icon, title, value: questionType }) => (
<QuestionsMiniButton
key={title}
onClick={() => {
createTypedQuestion(question.id, questionType);
}}
icon={icon}
text={title}
/>
))}
</Box>
</Box>
);
return (
<Box>
<Box
sx={{
display: "flex",
flexWrap: "wrap",
gap: "20px",
margin: "20px",
}}
>
{("page" in question && question.page === 0 ? BUTTON_TYPE_QUESTIONS : BUTTON_TYPE_SHORT_QUESTIONS).map(
({ icon, title, value: questionType }) => (
<QuestionsMiniButton
key={title}
onClick={() => {
createTypedQuestion(question.id, questionType);
}}
icon={icon}
text={title}
/>
)
)}
</Box>
</Box>
);
}

@ -1,12 +1,5 @@
import { useState, useEffect, useLayoutEffect, useRef } from "react"
import {
Box,
Button,
IconButton,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import { useState, useEffect, useLayoutEffect, useRef } from "react";
import { Box, Button, IconButton, Typography, useMediaQuery, useTheme } from "@mui/material";
import { collapseAllQuestions, createUntypedQuestion } from "@root/questions/actions";
import { decrementCurrentStep, incrementCurrentStep } from "@root/quizes/actions";
import { useCurrentQuiz } from "@root/quizes/hooks";
@ -14,105 +7,102 @@ import QuizPreview from "@ui_kit/QuizPreview/QuizPreview";
import { createPortal } from "react-dom";
import AddPlus from "../../assets/icons/questionsPage/addPlus";
import ArrowLeft from "../../assets/icons/questionsPage/arrowLeft";
import BranchingQuestions from "./BranchingModal/BranchingQuestionsModal"
import BranchingQuestions from "./BranchingModal/BranchingQuestionsModal";
import { QuestionSwitchWindowTool } from "./QuestionSwitchWindowTool";
import { useQuestionsStore } from "@root/questions/store";
import { updateOpenBranchingPanel, updateEditSomeQuestion } from "@root/uiTools/actions";
import { useUiTools } from "@root/uiTools/store";
export default function QuestionsPage() {
const theme = useTheme();
const { openedModalSettingsId, openBranchingPanel } = useUiTools();
const isMobile = useMediaQuery(theme.breakpoints.down(660));
const quiz = useCurrentQuiz();
useLayoutEffect(() => {
updateOpenBranchingPanel(false)
updateEditSomeQuestion()
},[])
const theme = useTheme();
const { openedModalSettingsId, openBranchingPanel } = useUiTools();
const isMobile = useMediaQuery(theme.breakpoints.down(660));
const quiz = useCurrentQuiz();
useLayoutEffect(() => {
updateOpenBranchingPanel(false);
updateEditSomeQuestion();
}, []);
const ref = useRef()
if (!quiz) return null;
const ref = useRef();
if (!quiz) return null;
return (
<>
<Box
ref={ref}
id="QuestionsPage"
sx={{
maxWidth: "796px",
width: "100%",
display: "flex",
justifyContent: "space-between",
margin: "60px 0 40px 0",
}}
>
<Typography variant={"h5"}>{quiz.name ? quiz.name : "Заголовок квиза"}</Typography>
<Button
sx={{
display: openBranchingPanel ? "none" : "flex",
fontSize: "16px",
lineHeight: "19px",
padding: 0,
textDecoration: "underline",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
onClick={collapseAllQuestions}
>
Свернуть всё
</Button>
</Box>
<QuestionSwitchWindowTool />
<Box
sx={{
display: "flex",
justifyContent: "space-between",
maxWidth: "796px",
}}
>
<IconButton
onClick={() => {
createUntypedQuestion(quiz.backendId);
}}
sx={{
position: "fixed",
left: isMobile ? "20px" : "250px",
bottom: isMobile ? "140px" : "20px",
}}
data-cy="create-question"
>
<AddPlus />
</IconButton>
return (
<>
<Box
ref={ref}
id="QuestionsPage"
sx={{
maxWidth: "796px",
width: "100%",
display: "flex",
justifyContent: "space-between",
margin: "60px 0 40px 0",
}}
>
<Typography variant={"h5"}>{
quiz.name ? quiz.name : "Заголовок квиза" }</Typography>
<Button
sx={{
display: openBranchingPanel ? "none" : "flex",
fontSize: "16px",
lineHeight: "19px",
padding: 0,
textDecoration: "underline",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
onClick={collapseAllQuestions}
>
Свернуть всё
</Button>
</Box>
<QuestionSwitchWindowTool/>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
maxWidth: "796px",
}}
>
<IconButton
onClick={() => {
createUntypedQuestion(quiz.backendId);
}}
sx={{
position: "fixed",
left: isMobile ? "20px" : "250px",
bottom: isMobile ? "140px" : "20px",
}}
data-cy="create-question"
>
<AddPlus />
</IconButton>
<Box sx={{ display: "flex", gap: "8px", marginLeft: "auto" }}>
<Button
variant="outlined"
sx={{ padding: "10px 20px", borderRadius: "8px", height: "44px" }}
data-cy="back-button"
onClick={decrementCurrentStep}
>
<ArrowLeft />
</Button>
<Button
variant="contained"
sx={{
height: "44px",
padding: "10px 20px",
borderRadius: "8px",
background: theme.palette.brightPurple.main,
fontSize: "18px",
}}
onClick={incrementCurrentStep}
>
Следующий шаг
</Button>
</Box>
</Box>
{createPortal(<QuizPreview />, document.body)}
{openedModalSettingsId !== null && <BranchingQuestions/>}
</>
);
<Box sx={{ display: "flex", gap: "8px", marginLeft: "auto" }}>
<Button
variant="outlined"
sx={{ padding: "10px 20px", borderRadius: "8px", height: "44px" }}
data-cy="back-button"
onClick={decrementCurrentStep}
>
<ArrowLeft />
</Button>
<Button
variant="contained"
sx={{
height: "44px",
padding: "10px 20px",
borderRadius: "8px",
background: theme.palette.brightPurple.main,
fontSize: "18px",
}}
onClick={incrementCurrentStep}
>
Следующий шаг
</Button>
</Box>
</Box>
{createPortal(<QuizPreview />, document.body)}
{openedModalSettingsId !== null && <BranchingQuestions />}
</>
);
}

@ -12,48 +12,46 @@ import UploadFile from "./UploadFile/UploadFile";
import AnswerOptions from "./answerOptions/AnswerOptions";
import { notReachable } from "../../utils/notReachable";
interface Props {
question: AnyTypedQuizQuestion;
question: AnyTypedQuizQuestion;
}
export default function SwitchQuestionsPage({ question }: Props) {
switch (question.type) {
case "variant":
return <AnswerOptions question={question} />;
switch (question.type) {
case "variant":
return <AnswerOptions question={question} />;
case "images":
return <OptionsPicture question={question} />;
case "images":
return <OptionsPicture question={question} />;
case "varimg":
return <OptionsAndPicture question={question} />;
case "varimg":
return <OptionsAndPicture question={question} />;
case "emoji":
return <Emoji question={question} />;
case "emoji":
return <Emoji question={question} />;
case "text":
return <OwnTextField question={question} />;
case "text":
return <OwnTextField question={question} />;
case "select":
return <DropDown question={question} />;
case "select":
return <DropDown question={question} />;
case "date":
return <DataOptions question={question} />;
case "date":
return <DataOptions question={question} />;
case "number":
return <SliderOptions question={question} />;
case "number":
return <SliderOptions question={question} />;
case "file":
return <UploadFile question={question} />;
case "file":
return <UploadFile question={question} />;
case "page":
return <PageOptions question={question} />;
case "page":
return <PageOptions question={question} />;
case "rating":
return <RatingOptions question={question} />;
case "rating":
return <RatingOptions question={question} />;
default:
notReachable(question)
}
default:
notReachable(question);
}
}