feat: ChooseAnswerModal

This commit is contained in:
IlyaDoronin 2023-09-20 15:42:14 +03:00
parent 10f9a5adb1
commit add32f0b3f
4 changed files with 283 additions and 135 deletions

@ -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 });