feat: create form questions page
This commit is contained in:
parent
0573316cfc
commit
1bb899dcd7
@ -46,7 +46,7 @@ root.render(
|
|||||||
{routeslink.map((e, i) => (
|
{routeslink.map((e, i) => (
|
||||||
<Route key={i} path={e.path} element={<Main page={e.page} header={e.header} sidebar={e.sidebar} />} />
|
<Route key={i} path={e.path} element={<Main page={e.page} header={e.header} sidebar={e.sidebar} />} />
|
||||||
))}
|
))}
|
||||||
<Route path="quize-setting/:quizId" element={<StartPage />} />
|
<Route path="setting/:quizId" element={<StartPage />} />
|
||||||
<Route path="crop" element={<ImageCrop />} />
|
<Route path="crop" element={<ImageCrop />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|||||||
@ -28,18 +28,26 @@ import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight";
|
|||||||
import { VectorQuestions } from "@icons/questionsPage/VectorQuestions";
|
import { VectorQuestions } from "@icons/questionsPage/VectorQuestions";
|
||||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||||
|
|
||||||
|
import type { SxProps } from "@mui/material";
|
||||||
import type { QuizQuestionBase } from "../../model/questionTypes/shared";
|
import type { QuizQuestionBase } from "../../model/questionTypes/shared";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
switchState: string;
|
switchState: string;
|
||||||
SSHC: (data: string) => void;
|
SSHC: (data: string) => void;
|
||||||
totalIndex: number;
|
totalIndex: number;
|
||||||
|
sx?: SxProps;
|
||||||
|
disableSettings?: boolean;
|
||||||
|
disableBranching?: boolean;
|
||||||
|
disableMiniButtons?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ButtonsOptions({
|
export default function ButtonsOptions({
|
||||||
SSHC,
|
SSHC,
|
||||||
switchState,
|
switchState,
|
||||||
totalIndex,
|
totalIndex,
|
||||||
|
disableSettings = false,
|
||||||
|
disableBranching = false,
|
||||||
|
disableMiniButtons = false,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const quizId = Number(useParams().quizId);
|
const quizId = Number(useParams().quizId);
|
||||||
const { openedModalSettings, listQuestions } = questionStore();
|
const { openedModalSettings, listQuestions } = questionStore();
|
||||||
@ -124,126 +132,137 @@ export default function ButtonsOptions({
|
|||||||
{buttonSetting.map(({ icon, title, value, myFunc }) => (
|
{buttonSetting.map(({ icon, title, value, myFunc }) => (
|
||||||
<Box key={value}>
|
<Box key={value}>
|
||||||
{value === "branching" ? (
|
{value === "branching" ? (
|
||||||
<Tooltip
|
!disableBranching && (
|
||||||
arrow
|
<Tooltip
|
||||||
placement="right"
|
arrow
|
||||||
title={
|
placement="right"
|
||||||
<Box>
|
title={
|
||||||
<Typography
|
<Box>
|
||||||
sx={{
|
<Typography
|
||||||
color: "#4D4D4D",
|
sx={{
|
||||||
fontWeight: "bold",
|
color: "#4D4D4D",
|
||||||
fontSize: "14px",
|
fontWeight: "bold",
|
||||||
marginBottom: "10px",
|
fontSize: "14px",
|
||||||
}}
|
marginBottom: "10px",
|
||||||
>
|
}}
|
||||||
Будет показан при условии
|
>
|
||||||
</Typography>
|
Будет показан при условии
|
||||||
<Typography sx={{ fontWeight: "bold", fontSize: "12px" }}>
|
</Typography>
|
||||||
Название
|
<Typography sx={{ fontWeight: "bold", fontSize: "12px" }}>
|
||||||
</Typography>
|
Название
|
||||||
<Typography
|
</Typography>
|
||||||
sx={{
|
<Typography
|
||||||
fontWeight: "bold",
|
sx={{
|
||||||
fontSize: "12px",
|
fontWeight: "bold",
|
||||||
marginBottom: "10px",
|
fontSize: "12px",
|
||||||
}}
|
marginBottom: "10px",
|
||||||
>
|
}}
|
||||||
Условие 1, Условие 2
|
>
|
||||||
</Typography>
|
Условие 1, Условие 2
|
||||||
<Typography sx={{ color: "#7E2AEA", fontSize: "12px" }}>
|
</Typography>
|
||||||
Все условия обязательны
|
<Typography sx={{ color: "#7E2AEA", fontSize: "12px" }}>
|
||||||
</Typography>
|
Все условия обязательны
|
||||||
</Box>
|
</Typography>
|
||||||
}
|
</Box>
|
||||||
>
|
}
|
||||||
<MiniButtonSetting
|
|
||||||
key={title}
|
|
||||||
onClick={() => {
|
|
||||||
SSHC(value);
|
|
||||||
myFunc();
|
|
||||||
}}
|
|
||||||
sx={{
|
|
||||||
backgroundColor:
|
|
||||||
switchState === value
|
|
||||||
? theme.palette.brightPurple.main
|
|
||||||
: "transparent",
|
|
||||||
color:
|
|
||||||
switchState === value
|
|
||||||
? "#ffffff"
|
|
||||||
: theme.palette.grey3.main,
|
|
||||||
minWidth: isWrappMiniButtonSetting ? "30px" : "64px",
|
|
||||||
height: "30px",
|
|
||||||
"&:hover": {
|
|
||||||
color: theme.palette.grey3.main,
|
|
||||||
"& path": { stroke: theme.palette.grey3.main },
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{icon}
|
<MiniButtonSetting
|
||||||
{isWrappMiniButtonSetting ? null : title}
|
key={title}
|
||||||
</MiniButtonSetting>
|
onClick={() => {
|
||||||
</Tooltip>
|
SSHC(value);
|
||||||
|
myFunc();
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
backgroundColor:
|
||||||
|
switchState === value
|
||||||
|
? theme.palette.brightPurple.main
|
||||||
|
: "transparent",
|
||||||
|
color:
|
||||||
|
switchState === value
|
||||||
|
? "#ffffff"
|
||||||
|
: theme.palette.grey3.main,
|
||||||
|
minWidth: isWrappMiniButtonSetting ? "30px" : "64px",
|
||||||
|
height: "30px",
|
||||||
|
"&:hover": {
|
||||||
|
color: theme.palette.grey3.main,
|
||||||
|
"& path": { stroke: theme.palette.grey3.main },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
{isWrappMiniButtonSetting ? null : title}
|
||||||
|
</MiniButtonSetting>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<MiniButtonSetting
|
<>
|
||||||
key={title}
|
{(value !== "setting" ||
|
||||||
onClick={() => {
|
(value === "setting" && !disableSettings)) && (
|
||||||
SSHC(value);
|
<MiniButtonSetting
|
||||||
myFunc();
|
key={title}
|
||||||
}}
|
onClick={() => {
|
||||||
sx={{
|
SSHC(value);
|
||||||
backgroundColor:
|
myFunc();
|
||||||
switchState === value
|
}}
|
||||||
? theme.palette.brightPurple.main
|
sx={{
|
||||||
: "transparent",
|
backgroundColor:
|
||||||
color:
|
switchState === value
|
||||||
switchState === value
|
? theme.palette.brightPurple.main
|
||||||
? "#ffffff"
|
: "transparent",
|
||||||
: theme.palette.grey3.main,
|
color:
|
||||||
minWidth: isWrappMiniButtonSetting ? "30px" : "64px",
|
switchState === value
|
||||||
height: "30px",
|
? "#ffffff"
|
||||||
"&:hover": {
|
: theme.palette.grey3.main,
|
||||||
color: theme.palette.grey3.main,
|
minWidth: isWrappMiniButtonSetting ? "30px" : "64px",
|
||||||
"& path": { stroke: theme.palette.grey3.main },
|
height: "30px",
|
||||||
},
|
"&:hover": {
|
||||||
}}
|
color: theme.palette.grey3.main,
|
||||||
>
|
"& path": { stroke: theme.palette.grey3.main },
|
||||||
{icon}
|
},
|
||||||
{isWrappMiniButtonSetting ? null : title}
|
}}
|
||||||
</MiniButtonSetting>
|
>
|
||||||
|
{icon}
|
||||||
|
{isWrappMiniButtonSetting ? null : title}
|
||||||
|
</MiniButtonSetting>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
<MiniButtonSetting
|
{!disableMiniButtons && (
|
||||||
onClick={() => setOpenedReallyChangingModal(true)}
|
<>
|
||||||
sx={{
|
<MiniButtonSetting
|
||||||
minWidth: "30px",
|
onClick={() => setOpenedReallyChangingModal(true)}
|
||||||
height: "30px",
|
sx={{
|
||||||
backgroundColor: "#FEDFD0",
|
minWidth: "30px",
|
||||||
}}
|
height: "30px",
|
||||||
>
|
backgroundColor: "#FEDFD0",
|
||||||
<DoubleTick style={{ color: "#FC712F", fontSize: "9px" }} />
|
}}
|
||||||
</MiniButtonSetting>
|
>
|
||||||
<MiniButtonSetting
|
<DoubleTick style={{ color: "#FC712F", fontSize: "9px" }} />
|
||||||
onClick={() => setOpenedReallyChangingModal(true)}
|
</MiniButtonSetting>
|
||||||
sx={{
|
<MiniButtonSetting
|
||||||
minWidth: "30px",
|
onClick={() => setOpenedReallyChangingModal(true)}
|
||||||
height: "30px",
|
sx={{
|
||||||
backgroundColor: "#FEDFD0",
|
minWidth: "30px",
|
||||||
}}
|
height: "30px",
|
||||||
>
|
backgroundColor: "#FEDFD0",
|
||||||
<DoubleArrowRight style={{ color: "#FC712F", fontSize: "9px" }} />
|
}}
|
||||||
</MiniButtonSetting>
|
>
|
||||||
<MiniButtonSetting
|
<DoubleArrowRight style={{ color: "#FC712F", fontSize: "9px" }} />
|
||||||
onClick={() => setOpenedReallyChangingModal(true)}
|
</MiniButtonSetting>
|
||||||
sx={{
|
<MiniButtonSetting
|
||||||
minWidth: "30px",
|
onClick={() => setOpenedReallyChangingModal(true)}
|
||||||
height: "30px",
|
sx={{
|
||||||
backgroundColor: "#FEDFD0",
|
minWidth: "30px",
|
||||||
}}
|
height: "30px",
|
||||||
>
|
backgroundColor: "#FEDFD0",
|
||||||
<VectorQuestions style={{ color: "#FC712F", fontSize: "9px" }} />
|
}}
|
||||||
</MiniButtonSetting>
|
>
|
||||||
|
<VectorQuestions style={{ color: "#FC712F", fontSize: "9px" }} />
|
||||||
|
</MiniButtonSetting>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
@ -172,9 +172,9 @@ export default function QuestionsPageCard({
|
|||||||
maxWidth: "796px",
|
maxWidth: "796px",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
borderRadius: "12px",
|
borderRadius: "12px",
|
||||||
boxShadow: "none",
|
|
||||||
backgroundColor: question.expanded ? "white" : "#EEE4FC",
|
backgroundColor: question.expanded ? "white" : "#EEE4FC",
|
||||||
border: question.expanded ? "none" : "1px solid #9A9AAF",
|
border: question.expanded ? "none" : "1px solid #9A9AAF",
|
||||||
|
boxShadow: "0px 10px 30px #e7e7e7",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
|
|||||||
148
src/pages/Questions/Form/FormDraggableList/ChooseAnswerModal.tsx
Normal file
148
src/pages/Questions/Form/FormDraggableList/ChooseAnswerModal.tsx
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Popper,
|
||||||
|
Grow,
|
||||||
|
Paper,
|
||||||
|
MenuList,
|
||||||
|
MenuItem,
|
||||||
|
ClickAwayListener,
|
||||||
|
Modal,
|
||||||
|
Button,
|
||||||
|
useTheme,
|
||||||
|
} from "@mui/material";
|
||||||
|
|
||||||
|
import {
|
||||||
|
questionStore,
|
||||||
|
updateQuestionsList,
|
||||||
|
removeQuestionForce,
|
||||||
|
createQuestion,
|
||||||
|
} from "@root/questions";
|
||||||
|
import { BUTTON_TYPE_QUESTIONS } from "../../TypeQuestions";
|
||||||
|
|
||||||
|
import type { RefObject } from "react";
|
||||||
|
import type {
|
||||||
|
QuizQuestionType,
|
||||||
|
QuizQuestionBase,
|
||||||
|
} from "../../../../model/questionTypes/shared";
|
||||||
|
|
||||||
|
type ChooseAnswerModalProps = {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
anchorRef: RefObject<HTMLDivElement>;
|
||||||
|
totalIndex: number;
|
||||||
|
switchState: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ChooseAnswerModal = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
anchorRef,
|
||||||
|
totalIndex,
|
||||||
|
switchState,
|
||||||
|
}: ChooseAnswerModalProps) => {
|
||||||
|
const [openModal, setOpenModal] = useState<boolean>(false);
|
||||||
|
const [selectedValue, setSelectedValue] = useState<QuizQuestionType>("text");
|
||||||
|
const quizId = Number(useParams().quizId);
|
||||||
|
const { listQuestions } = questionStore();
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Popper
|
||||||
|
placement="right-start"
|
||||||
|
open={open}
|
||||||
|
anchorEl={anchorRef.current}
|
||||||
|
transition
|
||||||
|
>
|
||||||
|
{({ TransitionProps }) => (
|
||||||
|
<Grow {...TransitionProps}>
|
||||||
|
<Paper>
|
||||||
|
<ClickAwayListener onClickAway={onClose}>
|
||||||
|
<MenuList autoFocusItem={open}>
|
||||||
|
{BUTTON_TYPE_QUESTIONS.map(({ icon, title, value }) => (
|
||||||
|
<MenuItem
|
||||||
|
key={value}
|
||||||
|
sx={{ display: "flex", gap: "10px" }}
|
||||||
|
{...(value !== switchState && {
|
||||||
|
onClick: () => {
|
||||||
|
onClose();
|
||||||
|
setOpenModal(true);
|
||||||
|
setSelectedValue(value);
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Box>{icon}</Box>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
color:
|
||||||
|
value === switchState
|
||||||
|
? theme.palette.brightPurple.main
|
||||||
|
: theme.palette.grey2.main,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Typography>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</MenuList>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
)}
|
||||||
|
</Popper>
|
||||||
|
<Modal open={openModal} onClose={() => setOpenModal(false)}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
transform: "translate(-50%, -50%)",
|
||||||
|
padding: "30px",
|
||||||
|
borderRadius: "10px",
|
||||||
|
background: "#FFFFFF",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography variant="h6">
|
||||||
|
Все настройки, кроме заголовка вопроса будут сброшены
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: "30px",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
gap: "15px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{ minWidth: "150px" }}
|
||||||
|
onClick={() => setOpenModal(false)}
|
||||||
|
>
|
||||||
|
Отмена
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{ minWidth: "150px" }}
|
||||||
|
onClick={() => {
|
||||||
|
setOpenModal(false);
|
||||||
|
|
||||||
|
const question = { ...listQuestions[quizId][totalIndex] };
|
||||||
|
|
||||||
|
removeQuestionForce(quizId, question.id);
|
||||||
|
createQuestion(quizId, selectedValue, totalIndex);
|
||||||
|
updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, {
|
||||||
|
expanded: question.expanded,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Подтвердить
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
import { memo } from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { Draggable } from "react-beautiful-dnd";
|
||||||
|
import { Box, ListItem, Typography, useTheme } from "@mui/material";
|
||||||
|
|
||||||
|
import QuestionsPageCard from "./QuestionPageCard";
|
||||||
|
|
||||||
|
import { updateQuestionsList } from "@root/questions";
|
||||||
|
|
||||||
|
import { QuizQuestionBase } from "../../../../model/questionTypes/shared";
|
||||||
|
|
||||||
|
type FormDraggableListItemProps = {
|
||||||
|
index: number;
|
||||||
|
isDragging: boolean;
|
||||||
|
questionData: QuizQuestionBase;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(
|
||||||
|
({ index, isDragging, questionData }: FormDraggableListItemProps) => {
|
||||||
|
const quizId = Number(useParams().quizId);
|
||||||
|
const theme = useTheme();
|
||||||
|
console.log("Мой индекс " + index);
|
||||||
|
console.log(questionData);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Draggable draggableId={String(index)} index={index}>
|
||||||
|
{(provided) => (
|
||||||
|
<ListItem
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
sx={{ userSelect: "none", padding: 0 }}
|
||||||
|
>
|
||||||
|
{questionData.deleted ? (
|
||||||
|
<Box
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
sx={{
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "800px",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "center",
|
||||||
|
marginBottom: "40px",
|
||||||
|
gap: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
sx={{
|
||||||
|
fontSize: "16px",
|
||||||
|
color: theme.palette.grey2.main,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Вопрос удалён.
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
onClick={() => {
|
||||||
|
updateQuestionsList<QuizQuestionBase>(quizId, index, {
|
||||||
|
...questionData,
|
||||||
|
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" }}>
|
||||||
|
<QuestionsPageCard
|
||||||
|
key={index}
|
||||||
|
totalIndex={index}
|
||||||
|
draggableProps={provided.dragHandleProps}
|
||||||
|
isDragging={isDragging}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</ListItem>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
444
src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx
Normal file
444
src/pages/Questions/Form/FormDraggableList/QuestionPageCard.tsx
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
import { useState, useRef, useEffect } from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Checkbox,
|
||||||
|
FormControl,
|
||||||
|
FormControlLabel,
|
||||||
|
IconButton,
|
||||||
|
InputAdornment,
|
||||||
|
Paper,
|
||||||
|
TextField,
|
||||||
|
useMediaQuery,
|
||||||
|
useTheme,
|
||||||
|
} from "@mui/material";
|
||||||
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
|
||||||
|
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
||||||
|
import FormTypeQuestions from "../FormTypeQuestions";
|
||||||
|
import SwitchQuestionsPage from "../../SwitchQuestionsPage";
|
||||||
|
|
||||||
|
import {
|
||||||
|
questionStore,
|
||||||
|
updateQuestionsList,
|
||||||
|
createQuestion,
|
||||||
|
copyQuestion,
|
||||||
|
removeQuestion,
|
||||||
|
removeQuestionForce,
|
||||||
|
} from "@root/questions";
|
||||||
|
|
||||||
|
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||||
|
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||||
|
import { OneIcon } from "@icons/questionsPage/OneIcon";
|
||||||
|
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
||||||
|
import { CopyIcon } from "@icons/questionsPage/CopyIcon";
|
||||||
|
import { CrossedEyeIcon } from "@icons/CrossedEyeIcon";
|
||||||
|
import { HideIcon } from "@icons/questionsPage/hideIcon";
|
||||||
|
import Answer from "@icons/questionsPage/answer";
|
||||||
|
import OptionsPict from "@icons/questionsPage/options_pict";
|
||||||
|
import OptionsAndPict from "@icons/questionsPage/options_and_pict";
|
||||||
|
import Emoji from "@icons/questionsPage/emoji";
|
||||||
|
import Input from "@icons/questionsPage/input";
|
||||||
|
import DropDown from "@icons/questionsPage/drop_down";
|
||||||
|
import Date from "@icons/questionsPage/date";
|
||||||
|
import Slider from "@icons/questionsPage/slider";
|
||||||
|
import Download from "@icons/questionsPage/download";
|
||||||
|
import Page from "@icons/questionsPage/page";
|
||||||
|
import RatingIcon from "@icons/questionsPage/rating";
|
||||||
|
import { ArrowDownIcon } from "@icons/questionsPage/ArrowDownIcon";
|
||||||
|
import { ReactComponent as PlusIcon } from "../../../../assets/icons/plus.svg";
|
||||||
|
|
||||||
|
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
||||||
|
import type { QuizQuestionBase } from "../../../../model/questionTypes/shared";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
totalIndex: number;
|
||||||
|
draggableProps: DraggableProvidedDragHandleProps | null | undefined;
|
||||||
|
isDragging: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IconAndrom = (isExpanded: boolean, switchState: string) => {
|
||||||
|
switch (switchState) {
|
||||||
|
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 <></>;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default function QuestionsPageCard({
|
||||||
|
totalIndex,
|
||||||
|
draggableProps,
|
||||||
|
isDragging,
|
||||||
|
}: Props) {
|
||||||
|
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
||||||
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
|
const quizId = Number(useParams().quizId);
|
||||||
|
const theme = useTheme();
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
const { listQuestions } = questionStore();
|
||||||
|
const question = listQuestions[quizId][totalIndex] as QuizQuestionBase;
|
||||||
|
const anchorRef = useRef(null);
|
||||||
|
const debounced = useDebouncedCallback((title) => {
|
||||||
|
updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, { title });
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (question.deleteTimeoutId) {
|
||||||
|
clearTimeout(question.deleteTimeoutId);
|
||||||
|
}
|
||||||
|
}, [question]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Paper
|
||||||
|
id={String(totalIndex)}
|
||||||
|
sx={{
|
||||||
|
overflow: "hidden",
|
||||||
|
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 }) => debounced(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}
|
||||||
|
totalIndex={totalIndex}
|
||||||
|
switchState={question.type}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
sx={{
|
||||||
|
margin: isMobile ? "10px 0" : 0,
|
||||||
|
"& .MuiInputBase-root": {
|
||||||
|
color: question.expanded ? "#9A9AAF" : "#4D4D4D",
|
||||||
|
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.length === 0 ? 0 : "18px",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
width: isMobile ? "100%" : "auto",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
sx={{ padding: "0", margin: "5px" }}
|
||||||
|
disableRipple
|
||||||
|
onClick={() =>
|
||||||
|
updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, {
|
||||||
|
expanded: !question.expanded,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{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(quizId, totalIndex)}
|
||||||
|
>
|
||||||
|
<CopyIcon
|
||||||
|
style={{ color: theme.palette.brightPurple.main }}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
<IconButton
|
||||||
|
sx={{
|
||||||
|
cursor: "pointer",
|
||||||
|
borderRadius: "6px",
|
||||||
|
padding: "0",
|
||||||
|
margin: "0 5px 0 10px",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
const removedId = question.id;
|
||||||
|
if (question.deleteTimeoutId) {
|
||||||
|
clearTimeout(question.deleteTimeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeQuestion(quizId, totalIndex);
|
||||||
|
|
||||||
|
const newTimeoutId = window.setTimeout(() => {
|
||||||
|
removeQuestionForce(quizId, removedId);
|
||||||
|
}, 5000);
|
||||||
|
|
||||||
|
updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, {
|
||||||
|
...question,
|
||||||
|
deleteTimeoutId: newTimeoutId,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteIcon
|
||||||
|
style={{ color: theme.palette.brightPurple.main }}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<OneIcon
|
||||||
|
style={{
|
||||||
|
fontSize: "30px",
|
||||||
|
marginLeft: "3px",
|
||||||
|
color: !question.expanded ? "#FFF" : "",
|
||||||
|
fill: question.expanded
|
||||||
|
? "#EEE4FC"
|
||||||
|
: theme.palette.brightPurple.main,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<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.length === 0 ? (
|
||||||
|
<FormTypeQuestions totalIndex={totalIndex} />
|
||||||
|
) : (
|
||||||
|
<SwitchQuestionsPage totalIndex={totalIndex} />
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Paper>
|
||||||
|
<Box
|
||||||
|
onMouseEnter={() => setPlusVisible(true)}
|
||||||
|
onMouseLeave={() => setPlusVisible(false)}
|
||||||
|
sx={{
|
||||||
|
maxWidth: "825px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
height: "40px",
|
||||||
|
cursor: "pointer",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
onClick={() => createQuestion(quizId, "", totalIndex + 1)}
|
||||||
|
sx={{
|
||||||
|
display: plusVisible && !isDragging ? "flex" : "none",
|
||||||
|
width: "100%",
|
||||||
|
alignItems: "center",
|
||||||
|
columnGap: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
11
src/pages/Questions/Form/FormDraggableList/helper.ts
Normal file
11
src/pages/Questions/Form/FormDraggableList/helper.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export const reorder = <T>(
|
||||||
|
list: T[],
|
||||||
|
startIndex: number,
|
||||||
|
endIndex: number
|
||||||
|
): T[] => {
|
||||||
|
const result = Array.from(list);
|
||||||
|
const [removed] = result.splice(startIndex, 1);
|
||||||
|
result.splice(endIndex, 0, removed);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
48
src/pages/Questions/Form/FormDraggableList/index.tsx
Normal file
48
src/pages/Questions/Form/FormDraggableList/index.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { Box } from "@mui/material";
|
||||||
|
import { DragDropContext, Droppable } from "react-beautiful-dnd";
|
||||||
|
|
||||||
|
import DraggableListItem from "./FormDraggableListItem";
|
||||||
|
|
||||||
|
import { questionStore, updateQuestionsListDragAndDrop } from "@root/questions";
|
||||||
|
|
||||||
|
import { reorder } from "./helper";
|
||||||
|
|
||||||
|
import type { DropResult } from "react-beautiful-dnd";
|
||||||
|
|
||||||
|
export const FormDraggableList = () => {
|
||||||
|
const quizId = Number(useParams().quizId);
|
||||||
|
const { listQuestions } = questionStore();
|
||||||
|
|
||||||
|
const onDragEnd = ({ destination, source }: DropResult) => {
|
||||||
|
if (destination) {
|
||||||
|
const newItems = reorder(
|
||||||
|
listQuestions[quizId],
|
||||||
|
source.index,
|
||||||
|
destination.index
|
||||||
|
);
|
||||||
|
|
||||||
|
updateQuestionsListDragAndDrop(quizId, newItems);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
|
<Droppable droppableId="droppable-list">
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<Box ref={provided.innerRef} {...provided.droppableProps}>
|
||||||
|
{listQuestions[quizId]?.map((question, index) => (
|
||||||
|
<DraggableListItem
|
||||||
|
key={index}
|
||||||
|
index={index}
|
||||||
|
isDragging={snapshot.isDraggingOver}
|
||||||
|
questionData={question}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
{provided.placeholder}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
</DragDropContext>
|
||||||
|
);
|
||||||
|
};
|
||||||
103
src/pages/Questions/Form/FormQuestionsPage.tsx
Normal file
103
src/pages/Questions/Form/FormQuestionsPage.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { Box, Button, IconButton, Typography, useTheme } from "@mui/material";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
|
import { FormDraggableList } from "./FormDraggableList";
|
||||||
|
import ButtonsOptions from "../ButtonsOptions";
|
||||||
|
|
||||||
|
import {
|
||||||
|
questionStore,
|
||||||
|
createQuestion,
|
||||||
|
updateQuestionsList,
|
||||||
|
} from "@root/questions";
|
||||||
|
import { quizStore } from "@root/quizes";
|
||||||
|
|
||||||
|
import AddPlus from "../../../assets/icons/questionsPage/addPlus";
|
||||||
|
import ArrowLeft from "../../../assets/icons/questionsPage/arrowLeft";
|
||||||
|
|
||||||
|
import type { AnyQuizQuestion } from "../../../model/questionTypes/shared";
|
||||||
|
|
||||||
|
export default function FormQuestionsPage() {
|
||||||
|
const { listQuizes, updateQuizesList } = quizStore();
|
||||||
|
const quizId = Number(useParams().quizId);
|
||||||
|
const { listQuestions } = questionStore();
|
||||||
|
const handleNext = () => {
|
||||||
|
updateQuizesList(quizId, { step: listQuizes[quizId].step + 1 });
|
||||||
|
};
|
||||||
|
|
||||||
|
const collapseEverything = () => {
|
||||||
|
listQuestions[quizId].forEach((item, index) => {
|
||||||
|
updateQuestionsList<AnyQuizQuestion>(quizId, index, {
|
||||||
|
...item,
|
||||||
|
expanded: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
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={collapseEverything}
|
||||||
|
>
|
||||||
|
Свернуть всё
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<FormDraggableList />
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
maxWidth: "796px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
createQuestion(quizId);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AddPlus />
|
||||||
|
</IconButton>
|
||||||
|
<Box sx={{ display: "flex", gap: "8px" }}>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
sx={{ padding: "10px 20px", borderRadius: "8px", height: "44px" }}
|
||||||
|
>
|
||||||
|
<ArrowLeft />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
sx={{
|
||||||
|
height: "44px",
|
||||||
|
padding: "10px 20px",
|
||||||
|
borderRadius: "8px",
|
||||||
|
background: theme.palette.brightPurple.main,
|
||||||
|
fontSize: "18px",
|
||||||
|
}}
|
||||||
|
onClick={handleNext}
|
||||||
|
>
|
||||||
|
Следующий шаг
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
146
src/pages/Questions/Form/FormTypeQuestions.tsx
Normal file
146
src/pages/Questions/Form/FormTypeQuestions.tsx
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import QuestionsMiniButton from "@ui_kit/QuestionsMiniButton";
|
||||||
|
import Answer from "../../../assets/icons/questionsPage/answer";
|
||||||
|
import OptionsPict from "../../../assets/icons/questionsPage/options_pict";
|
||||||
|
import OptionsAndPict from "../../../assets/icons/questionsPage/options_and_pict";
|
||||||
|
import Emoji from "../../../assets/icons/questionsPage/emoji";
|
||||||
|
import Input from "../../../assets/icons/questionsPage/input";
|
||||||
|
import DropDown from "../../../assets/icons/questionsPage/drop_down";
|
||||||
|
import Date from "../../../assets/icons/questionsPage/date";
|
||||||
|
import Slider from "../../../assets/icons/questionsPage/slider";
|
||||||
|
import Download from "../../../assets/icons/questionsPage/download";
|
||||||
|
import Page from "../../../assets/icons/questionsPage/page";
|
||||||
|
import RatingIcon from "../../../assets/icons/questionsPage/rating";
|
||||||
|
import { Box } from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import ButtonsOptions from "../ButtonsOptions";
|
||||||
|
|
||||||
|
import {
|
||||||
|
questionStore,
|
||||||
|
updateQuestionsList,
|
||||||
|
createQuestion,
|
||||||
|
removeQuestionForce,
|
||||||
|
} from "@root/questions";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
QuizQuestionType,
|
||||||
|
QuizQuestionBase,
|
||||||
|
} from "../../../model/questionTypes/shared";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
totalIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ButtonTypeQuestion = {
|
||||||
|
icon: JSX.Element;
|
||||||
|
title: string;
|
||||||
|
value: QuizQuestionType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BUTTON_TYPE_QUESTIONS: ButtonTypeQuestion[] = [
|
||||||
|
{
|
||||||
|
icon: <Answer color="#9A9AAF" />,
|
||||||
|
title: "Варианты ответов",
|
||||||
|
value: "variant",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <OptionsPict color="#9A9AAF" />,
|
||||||
|
title: "Варианты с картинками",
|
||||||
|
value: "images",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <OptionsAndPict color="#9A9AAF" />,
|
||||||
|
title: "Варианты и картинка",
|
||||||
|
value: "varimg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <Emoji color="#9A9AAF" />,
|
||||||
|
title: "Эмоджи",
|
||||||
|
value: "emoji",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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: <Page color="#9A9AAF" />,
|
||||||
|
title: "Страница",
|
||||||
|
value: "page",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: <RatingIcon color="#9A9AAF" />,
|
||||||
|
title: "Рейтинг",
|
||||||
|
value: "rating",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function FormTypeQuestions({ totalIndex }: Props) {
|
||||||
|
const [switchState, setSwitchState] = useState("setting");
|
||||||
|
const quizId = Number(useParams().quizId);
|
||||||
|
const { listQuestions } = questionStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
paddingTop: "8px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
gap: "20px",
|
||||||
|
margin: "0 20px 20px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{BUTTON_TYPE_QUESTIONS.map(({ icon, title, value }) => (
|
||||||
|
<QuestionsMiniButton
|
||||||
|
key={title}
|
||||||
|
onClick={() => {
|
||||||
|
const question = { ...listQuestions[quizId][totalIndex] };
|
||||||
|
|
||||||
|
removeQuestionForce(quizId, question.id);
|
||||||
|
createQuestion(quizId, value, totalIndex);
|
||||||
|
updateQuestionsList<QuizQuestionBase>(quizId, totalIndex, {
|
||||||
|
expanded: question.expanded,
|
||||||
|
type: value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
icon={icon}
|
||||||
|
text={title}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
<ButtonsOptions
|
||||||
|
switchState={switchState}
|
||||||
|
SSHC={setSwitchState}
|
||||||
|
totalIndex={totalIndex}
|
||||||
|
disableSettings
|
||||||
|
disableBranching
|
||||||
|
disableMiniButtons
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -13,6 +13,7 @@ import RatingIcon from "../../assets/icons/questionsPage/rating";
|
|||||||
import { Box } from "@mui/material";
|
import { Box } from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
questionStore,
|
questionStore,
|
||||||
updateQuestionsList,
|
updateQuestionsList,
|
||||||
|
|||||||
@ -35,7 +35,7 @@ export default function FirstQuiz() {
|
|||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate(`/quize-setting/${createBlank()}`);
|
navigate(`/setting/${createBlank()}`);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Создать +
|
Создать +
|
||||||
|
|||||||
@ -40,7 +40,7 @@ export default function MyQuizzesFull({outerContainerSx: sx, children}: Props) {
|
|||||||
variant="contained"
|
variant="contained"
|
||||||
sx={{padding: "10px 47px"}}
|
sx={{padding: "10px 47px"}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate(`/quize-setting/${createBlank()}`);
|
navigate(`/setting/${createBlank()}`);
|
||||||
}}
|
}}
|
||||||
>Создать +</Button>
|
>Создать +</Button>
|
||||||
</Box>
|
</Box>
|
||||||
@ -62,7 +62,7 @@ export default function MyQuizzesFull({outerContainerSx: sx, children}: Props) {
|
|||||||
removeQuiz(e.id)
|
removeQuiz(e.id)
|
||||||
}}
|
}}
|
||||||
onClickEdit={() =>
|
onClickEdit={() =>
|
||||||
navigate(`/quize-setting/${e.id}`)
|
navigate(`/setting/${e.id}`)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import StepOne from "../pages/startPage/stepOne";
|
|||||||
import Steptwo from "../pages/startPage/steptwo";
|
import Steptwo from "../pages/startPage/steptwo";
|
||||||
import StartPageSettings from "../pages/startPage/StartPageSettings";
|
import StartPageSettings from "../pages/startPage/StartPageSettings";
|
||||||
import QuestionsPage from "../pages/Questions/QuestionsPage";
|
import QuestionsPage from "../pages/Questions/QuestionsPage";
|
||||||
|
import FormQuestionsPage from "../pages/Questions/Form/FormQuestionsPage";
|
||||||
import ContactFormPage from "../pages/ContactFormPage/ContactFormPage";
|
import ContactFormPage from "../pages/ContactFormPage/ContactFormPage";
|
||||||
import InstallQuiz from "../pages/InstallQuiz/InstallQuiz";
|
import InstallQuiz from "../pages/InstallQuiz/InstallQuiz";
|
||||||
import { Result } from "../pages/Result/Result";
|
import { Result } from "../pages/Result/Result";
|
||||||
@ -27,7 +28,7 @@ export default function SwitchStepPages({
|
|||||||
if (!startpage) return <Steptwo />;
|
if (!startpage) return <Steptwo />;
|
||||||
return <StartPageSettings />;
|
return <StartPageSettings />;
|
||||||
case 2:
|
case 2:
|
||||||
if (quizType === "form") return <QuestionsPage />;
|
if (quizType === "form") return <FormQuestionsPage />;
|
||||||
return <QuestionsPage />;
|
return <QuestionsPage />;
|
||||||
case 3:
|
case 3:
|
||||||
if (!createResult) return <Result />;
|
if (!createResult) return <Result />;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user