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 {
|
||||
Box,
|
||||
@ -13,6 +13,8 @@ import {
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
|
||||
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
||||
import TypeQuestions from "../TypeQuestions";
|
||||
import SwitchQuestionsPage from "../SwitchQuestionsPage";
|
||||
|
||||
@ -142,6 +144,7 @@ export default function QuestionsPageCard({
|
||||
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));
|
||||
@ -149,6 +152,7 @@ export default function QuestionsPageCard({
|
||||
const { listQuestions } = questionStore();
|
||||
const { type: switchState, expanded: isExpanded } =
|
||||
listQuestions[quizId][totalIndex];
|
||||
const anchorRef = useRef(null);
|
||||
const debounced = useDebouncedCallback((title) => {
|
||||
updateQuestionsList(quizId, totalIndex, { title });
|
||||
}, 1000);
|
||||
@ -188,9 +192,22 @@ export default function QuestionsPageCard({
|
||||
onChange={({ target }) => debounced(target.value)}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
{IconAndrom(isExpanded, switchState)}
|
||||
</InputAdornment>
|
||||
<Box>
|
||||
<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={{
|
||||
|
@ -10,7 +10,7 @@ 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, useTheme } from "@mui/material";
|
||||
import { Box } from "@mui/material";
|
||||
import React from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { questionStore, updateQuestionsList } from "@root/questions";
|
||||
@ -19,72 +19,75 @@ interface Props {
|
||||
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) {
|
||||
const theme = useTheme();
|
||||
const quizId = Number(useParams().quizId);
|
||||
const { listQuestions } = questionStore();
|
||||
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 (
|
||||
<Box
|
||||
sx={{
|
||||
@ -94,7 +97,7 @@ export default function TypeQuestions({ totalIndex }: Props) {
|
||||
padding: "8px 20px 20px",
|
||||
}}
|
||||
>
|
||||
{buttonTypeQuestions.map(({ icon, title, value }) => (
|
||||
{BUTTON_TYPE_QUESTIONS.map(({ icon, title, value }) => (
|
||||
<QuestionsMiniButton
|
||||
key={title}
|
||||
onClick={() => {
|
||||
|
@ -78,6 +78,73 @@ interface QuestionStore {
|
||||
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>()(
|
||||
persist<QuestionStore>(
|
||||
() => ({
|
||||
@ -135,73 +202,7 @@ export const createQuestion = (quizId: number, placeIndex = -1) => {
|
||||
newData[quizId].splice(
|
||||
placeIndex < 0 ? newData[quizId].length : placeIndex,
|
||||
0,
|
||||
{
|
||||
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,
|
||||
}
|
||||
{ ...DEFAULT_QUESTION, id }
|
||||
);
|
||||
|
||||
questionStore.setState({ listQuestions: newData });
|
||||
|
Loading…
Reference in New Issue
Block a user