feat: ChooseAnswerModal
This commit is contained in:
parent
10f9a5adb1
commit
add32f0b3f
127
src/pages/Questions/DraggableList/ChooseAnswerModal.tsx
Normal file
127
src/pages/Questions/DraggableList/ChooseAnswerModal.tsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Typography,
|
||||||
|
Popper,
|
||||||
|
Grow,
|
||||||
|
Paper,
|
||||||
|
MenuList,
|
||||||
|
MenuItem,
|
||||||
|
ClickAwayListener,
|
||||||
|
Modal,
|
||||||
|
Button,
|
||||||
|
} from "@mui/material";
|
||||||
|
|
||||||
|
import {
|
||||||
|
questionStore,
|
||||||
|
updateQuestionsList,
|
||||||
|
DEFAULT_QUESTION,
|
||||||
|
} from "@root/questions";
|
||||||
|
import { BUTTON_TYPE_QUESTIONS } from "../TypeQuestions";
|
||||||
|
|
||||||
|
import type { RefObject } from "react";
|
||||||
|
|
||||||
|
type ChooseAnswerModalProps = {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
anchorRef: RefObject<HTMLDivElement>;
|
||||||
|
totalIndex: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ChooseAnswerModal = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
anchorRef,
|
||||||
|
totalIndex,
|
||||||
|
}: ChooseAnswerModalProps) => {
|
||||||
|
const [openModal, setOpenModal] = useState<boolean>(false);
|
||||||
|
const [selectedValue, setSelectedValue] = useState<string>("");
|
||||||
|
const quizId = Number(useParams().quizId);
|
||||||
|
const { listQuestions } = questionStore();
|
||||||
|
|
||||||
|
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}
|
||||||
|
onClick={() => {
|
||||||
|
onClose();
|
||||||
|
setOpenModal(true);
|
||||||
|
setSelectedValue(value);
|
||||||
|
}}
|
||||||
|
sx={{ display: "flex", gap: "10px" }}
|
||||||
|
>
|
||||||
|
<Box>{icon}</Box>
|
||||||
|
<Typography>{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];
|
||||||
|
updateQuestionsList(quizId, totalIndex, {
|
||||||
|
...DEFAULT_QUESTION,
|
||||||
|
expanded: question.expanded,
|
||||||
|
type: selectedValue,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Подтвердить
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1,4 +1,4 @@
|
|||||||
import { useState } from "react";
|
import { useState, useRef } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@ -13,6 +13,8 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
|
|
||||||
|
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
||||||
import TypeQuestions from "../TypeQuestions";
|
import TypeQuestions from "../TypeQuestions";
|
||||||
import SwitchQuestionsPage from "../SwitchQuestionsPage";
|
import SwitchQuestionsPage from "../SwitchQuestionsPage";
|
||||||
|
|
||||||
@ -142,6 +144,7 @@ export default function QuestionsPageCard({
|
|||||||
isDragging,
|
isDragging,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
||||||
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
const quizId = Number(useParams().quizId);
|
const quizId = Number(useParams().quizId);
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
@ -149,6 +152,7 @@ export default function QuestionsPageCard({
|
|||||||
const { listQuestions } = questionStore();
|
const { listQuestions } = questionStore();
|
||||||
const { type: switchState, expanded: isExpanded } =
|
const { type: switchState, expanded: isExpanded } =
|
||||||
listQuestions[quizId][totalIndex];
|
listQuestions[quizId][totalIndex];
|
||||||
|
const anchorRef = useRef(null);
|
||||||
const debounced = useDebouncedCallback((title) => {
|
const debounced = useDebouncedCallback((title) => {
|
||||||
updateQuestionsList(quizId, totalIndex, { title });
|
updateQuestionsList(quizId, totalIndex, { title });
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@ -188,9 +192,22 @@ export default function QuestionsPageCard({
|
|||||||
onChange={({ target }) => debounced(target.value)}
|
onChange={({ target }) => debounced(target.value)}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
startAdornment: (
|
startAdornment: (
|
||||||
<InputAdornment position="start">
|
<Box>
|
||||||
{IconAndrom(isExpanded, switchState)}
|
<InputAdornment
|
||||||
</InputAdornment>
|
ref={anchorRef}
|
||||||
|
position="start"
|
||||||
|
sx={{ cursor: "pointer" }}
|
||||||
|
onClick={() => setOpen((isOpened) => !isOpened)}
|
||||||
|
>
|
||||||
|
{IconAndrom(isExpanded, switchState)}
|
||||||
|
</InputAdornment>
|
||||||
|
<ChooseAnswerModal
|
||||||
|
open={open}
|
||||||
|
onClose={() => setOpen(false)}
|
||||||
|
anchorRef={anchorRef}
|
||||||
|
totalIndex={totalIndex}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -10,7 +10,7 @@ import Slider from "../../assets/icons/questionsPage/slider";
|
|||||||
import Download from "../../assets/icons/questionsPage/download";
|
import Download from "../../assets/icons/questionsPage/download";
|
||||||
import Page from "../../assets/icons/questionsPage/page";
|
import Page from "../../assets/icons/questionsPage/page";
|
||||||
import RatingIcon from "../../assets/icons/questionsPage/rating";
|
import RatingIcon from "../../assets/icons/questionsPage/rating";
|
||||||
import { Box, useTheme } 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 { questionStore, updateQuestionsList } from "@root/questions";
|
import { questionStore, updateQuestionsList } from "@root/questions";
|
||||||
@ -19,72 +19,75 @@ interface Props {
|
|||||||
totalIndex: number;
|
totalIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ButtonTypeQuestion = {
|
||||||
|
icon: JSX.Element;
|
||||||
|
title: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
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 TypeQuestions({ totalIndex }: Props) {
|
export default function TypeQuestions({ totalIndex }: Props) {
|
||||||
const theme = useTheme();
|
|
||||||
const quizId = Number(useParams().quizId);
|
const quizId = Number(useParams().quizId);
|
||||||
const { listQuestions } = questionStore();
|
const { listQuestions } = questionStore();
|
||||||
const switchState = listQuestions[quizId][totalIndex].type;
|
const switchState = listQuestions[quizId][totalIndex].type;
|
||||||
const buttonTypeQuestions: {
|
|
||||||
icon: JSX.Element;
|
|
||||||
title: string;
|
|
||||||
value: string;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
icon: <Answer color={theme.palette.grey2.main} />,
|
|
||||||
title: "Варианты ответов",
|
|
||||||
value: "variant",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <OptionsPict color={theme.palette.grey2.main} />,
|
|
||||||
title: "Варианты с картинками",
|
|
||||||
value: "images",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <OptionsAndPict color={theme.palette.grey2.main} />,
|
|
||||||
title: "Варианты и картинка",
|
|
||||||
value: "varimg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Emoji color={theme.palette.grey2.main} />,
|
|
||||||
title: "Эмоджи",
|
|
||||||
value: "emoji",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Input color={theme.palette.grey2.main} />,
|
|
||||||
title: "Своё поле для ввода",
|
|
||||||
value: "text",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <DropDown color={theme.palette.grey2.main} />,
|
|
||||||
title: "Выпадающий список",
|
|
||||||
value: "select",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Date color={theme.palette.grey2.main} />,
|
|
||||||
title: "Дата",
|
|
||||||
value: "date",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Slider color={theme.palette.grey2.main} />,
|
|
||||||
title: "Ползунок",
|
|
||||||
value: "number",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Download color={theme.palette.grey2.main} />,
|
|
||||||
title: "Загрузка файла",
|
|
||||||
value: "file",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <Page color={theme.palette.grey2.main} />,
|
|
||||||
title: "Страница",
|
|
||||||
value: "page",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: <RatingIcon color={theme.palette.grey2.main} />,
|
|
||||||
title: "Рейтинг",
|
|
||||||
value: "rating",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -94,7 +97,7 @@ export default function TypeQuestions({ totalIndex }: Props) {
|
|||||||
padding: "8px 20px 20px",
|
padding: "8px 20px 20px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{buttonTypeQuestions.map(({ icon, title, value }) => (
|
{BUTTON_TYPE_QUESTIONS.map(({ icon, title, value }) => (
|
||||||
<QuestionsMiniButton
|
<QuestionsMiniButton
|
||||||
key={title}
|
key={title}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -78,6 +78,73 @@ interface QuestionStore {
|
|||||||
openedModalSettings: string;
|
openedModalSettings: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_QUESTION: Omit<Question, "id"> = {
|
||||||
|
title: "",
|
||||||
|
description: "",
|
||||||
|
type: "",
|
||||||
|
required: true,
|
||||||
|
deleted: true,
|
||||||
|
page: 0,
|
||||||
|
content: {
|
||||||
|
largeCheck: false,
|
||||||
|
large: "",
|
||||||
|
multi: false,
|
||||||
|
own: false,
|
||||||
|
innerNameCheck: false,
|
||||||
|
innerName: "",
|
||||||
|
back: "",
|
||||||
|
placeholder: "",
|
||||||
|
type: "all",
|
||||||
|
autofill: true,
|
||||||
|
default: "",
|
||||||
|
images: [],
|
||||||
|
number: false,
|
||||||
|
single: false,
|
||||||
|
xy: "",
|
||||||
|
format: "carousel",
|
||||||
|
text: "",
|
||||||
|
picture: "",
|
||||||
|
video: "",
|
||||||
|
dateRange: false,
|
||||||
|
time: false,
|
||||||
|
form: "star",
|
||||||
|
steps: 5,
|
||||||
|
range: "0—100",
|
||||||
|
start: 50,
|
||||||
|
step: 1,
|
||||||
|
chooseRange: false,
|
||||||
|
required: false,
|
||||||
|
replText: "",
|
||||||
|
ratingExpanded: false,
|
||||||
|
ratingDescription: "",
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
answer: "",
|
||||||
|
hints: "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hint: {
|
||||||
|
text: "",
|
||||||
|
video: "",
|
||||||
|
},
|
||||||
|
rule: {
|
||||||
|
or: true,
|
||||||
|
show: true,
|
||||||
|
reqs: [
|
||||||
|
{
|
||||||
|
id: "",
|
||||||
|
vars: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
version: 0,
|
||||||
|
parent_ids: [0],
|
||||||
|
created_at: "",
|
||||||
|
updated_at: "",
|
||||||
|
expanded: false,
|
||||||
|
};
|
||||||
|
|
||||||
export const questionStore = create<QuestionStore>()(
|
export const questionStore = create<QuestionStore>()(
|
||||||
persist<QuestionStore>(
|
persist<QuestionStore>(
|
||||||
() => ({
|
() => ({
|
||||||
@ -135,73 +202,7 @@ export const createQuestion = (quizId: number, placeIndex = -1) => {
|
|||||||
newData[quizId].splice(
|
newData[quizId].splice(
|
||||||
placeIndex < 0 ? newData[quizId].length : placeIndex,
|
placeIndex < 0 ? newData[quizId].length : placeIndex,
|
||||||
0,
|
0,
|
||||||
{
|
{ ...DEFAULT_QUESTION, id }
|
||||||
id,
|
|
||||||
title: "",
|
|
||||||
description: "",
|
|
||||||
type: "",
|
|
||||||
required: true,
|
|
||||||
deleted: true,
|
|
||||||
page: 0,
|
|
||||||
content: {
|
|
||||||
largeCheck: false,
|
|
||||||
large: "",
|
|
||||||
multi: false,
|
|
||||||
own: false,
|
|
||||||
innerNameCheck: false,
|
|
||||||
innerName: "",
|
|
||||||
back: "",
|
|
||||||
placeholder: "",
|
|
||||||
type: "all",
|
|
||||||
autofill: true,
|
|
||||||
default: "",
|
|
||||||
images: [],
|
|
||||||
number: false,
|
|
||||||
single: false,
|
|
||||||
xy: "",
|
|
||||||
format: "carousel",
|
|
||||||
text: "",
|
|
||||||
picture: "",
|
|
||||||
video: "",
|
|
||||||
dateRange: false,
|
|
||||||
time: false,
|
|
||||||
form: "star",
|
|
||||||
steps: 5,
|
|
||||||
range: "0—100",
|
|
||||||
start: 50,
|
|
||||||
step: 1,
|
|
||||||
chooseRange: false,
|
|
||||||
required: false,
|
|
||||||
replText: "",
|
|
||||||
ratingExpanded: false,
|
|
||||||
ratingDescription: "",
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
answer: "",
|
|
||||||
hints: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
hint: {
|
|
||||||
text: "",
|
|
||||||
video: "",
|
|
||||||
},
|
|
||||||
rule: {
|
|
||||||
or: true,
|
|
||||||
show: true,
|
|
||||||
reqs: [
|
|
||||||
{
|
|
||||||
id: "",
|
|
||||||
vars: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
version: 0,
|
|
||||||
parent_ids: [0],
|
|
||||||
created_at: "",
|
|
||||||
updated_at: "",
|
|
||||||
expanded: false,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
questionStore.setState({ listQuestions: newData });
|
questionStore.setState({ listQuestions: newData });
|
||||||
|
Loading…
Reference in New Issue
Block a user