Merge branch 'data-rollback' into dev
This commit is contained in:
commit
85c99344f1
@ -1,29 +1,24 @@
|
|||||||
import { MessageIcon } from "@icons/messagIcon";
|
|
||||||
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
import { PointsIcon } from "@icons/questionsPage/PointsIcon";
|
||||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||||
import { TextareaAutosize } from "@mui/base/TextareaAutosize";
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
FormControl,
|
FormControl,
|
||||||
IconButton,
|
IconButton,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
Popover,
|
|
||||||
TextField as MuiTextField,
|
TextField as MuiTextField,
|
||||||
|
TextFieldProps,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
TextFieldProps,
|
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {
|
import {
|
||||||
addQuestionVariant,
|
addQuestionVariant,
|
||||||
deleteQuestionVariant,
|
deleteQuestionVariant,
|
||||||
setQuestionVariantField,
|
setQuestionVariantField,
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
|
import { enqueueSnackbar } from "notistack";
|
||||||
import type { ChangeEvent, FC, KeyboardEvent, ReactNode } from "react";
|
import type { ChangeEvent, FC, KeyboardEvent, ReactNode } from "react";
|
||||||
import { useState } from "react";
|
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
import { Draggable } from "react-beautiful-dnd";
|
||||||
import type { QuestionVariant } from "../../../model/questionTypes/shared";
|
import type { QuestionVariant } from "../../../model/questionTypes/shared";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import { enqueueSnackbar } from "notistack";
|
|
||||||
|
|
||||||
const TextField = MuiTextField as unknown as FC<TextFieldProps>;
|
const TextField = MuiTextField as unknown as FC<TextFieldProps>;
|
||||||
|
|
||||||
@ -48,21 +43,6 @@ export const AnswerItem = ({
|
|||||||
}: AnswerItemProps) => {
|
}: AnswerItemProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(790));
|
const isTablet = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
|
||||||
const [inputValue, setInputValue] = useState(variant.answer);
|
|
||||||
const setQuestionVariantAnswer = useDebouncedCallback((value) => {
|
|
||||||
setQuestionVariantField(questionId, variant.id, "answer", value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
||||||
setAnchorEl(event.currentTarget);
|
|
||||||
setIsOpen(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
setIsOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable draggableId={String(index)} index={index}>
|
<Draggable draggableId={String(index)} index={index}>
|
||||||
@ -80,16 +60,20 @@ export const AnswerItem = ({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
value={inputValue}
|
value={variant.answer}
|
||||||
fullWidth
|
fullWidth
|
||||||
focused={false}
|
focused={false}
|
||||||
placeholder={"Добавьте ответ"}
|
placeholder={"Добавьте ответ"}
|
||||||
multiline={largeCheck}
|
multiline={largeCheck}
|
||||||
onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
|
onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (target.value.length <= 1000) {
|
if (target.value.length <= 1000) {
|
||||||
setInputValue(target.value);
|
setQuestionVariantField(
|
||||||
|
questionId,
|
||||||
|
variant.id,
|
||||||
|
"answer",
|
||||||
|
target.value || " ",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
setQuestionVariantAnswer(target.value || " ");
|
|
||||||
}}
|
}}
|
||||||
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
|
onKeyDown={(event: KeyboardEvent<HTMLInputElement>) => {
|
||||||
if (disableKeyDown) {
|
if (disableKeyDown) {
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight";
|
|
||||||
import { DoubleTick } from "@icons/questionsPage/DoubleTick";
|
|
||||||
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 { SxProps } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
@ -8,7 +5,6 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
IconButton,
|
IconButton,
|
||||||
Modal,
|
Modal,
|
||||||
Tooltip,
|
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
@ -17,27 +13,17 @@ import {
|
|||||||
copyQuestion,
|
copyQuestion,
|
||||||
deleteQuestion,
|
deleteQuestion,
|
||||||
deleteQuestionWithTimeout,
|
deleteQuestionWithTimeout,
|
||||||
clearRuleForAll,
|
|
||||||
updateQuestion,
|
|
||||||
getQuestionByContentId,
|
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
|
import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
|
||||||
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||||
|
import { DeleteFunction } from "@utils/deleteFunc";
|
||||||
|
import { useState } from "react";
|
||||||
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
||||||
import Branching from "../../assets/icons/questionsPage/branching";
|
import Branching from "../../assets/icons/questionsPage/branching";
|
||||||
import Clue from "../../assets/icons/questionsPage/clue";
|
|
||||||
import { HideIcon } from "../../assets/icons/questionsPage/hideIcon";
|
|
||||||
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
||||||
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
|
||||||
import { enqueueSnackbar } from "notistack";
|
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
|
||||||
import { updateOpenedModalSettingsId } from "@root/uiTools/actions";
|
|
||||||
import { updateRootContentId } from "@root/quizes/actions";
|
|
||||||
import { useUiTools } from "@root/uiTools/store";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { updateSomeWorkBackend } from "@root/uiTools/actions";
|
|
||||||
import { DeleteFunction } from "@utils/deleteFunc";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
switchState: string;
|
switchState: string;
|
||||||
@ -306,7 +292,7 @@ export default function ButtonsOptions({
|
|||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
} else {
|
} else {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -351,7 +337,7 @@ export default function ButtonsOptions({
|
|||||||
sx={{ minWidth: "150px" }}
|
sx={{ minWidth: "150px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight";
|
|
||||||
import { DoubleTick } from "@icons/questionsPage/DoubleTick";
|
|
||||||
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 { SxProps } from "@mui/material";
|
||||||
import {
|
import {
|
||||||
@ -8,7 +5,6 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
IconButton,
|
IconButton,
|
||||||
Modal,
|
Modal,
|
||||||
Tooltip,
|
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
@ -17,27 +13,17 @@ import {
|
|||||||
copyQuestion,
|
copyQuestion,
|
||||||
deleteQuestion,
|
deleteQuestion,
|
||||||
deleteQuestionWithTimeout,
|
deleteQuestionWithTimeout,
|
||||||
clearRuleForAll,
|
|
||||||
updateQuestion,
|
|
||||||
getQuestionByContentId,
|
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
|
import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
|
||||||
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||||
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
|
||||||
import Branching from "../../assets/icons/questionsPage/branching";
|
|
||||||
import Clue from "../../assets/icons/questionsPage/clue";
|
|
||||||
import { HideIcon } from "../../assets/icons/questionsPage/hideIcon";
|
|
||||||
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
|
||||||
import type { AnyTypedQuizQuestion } from "../../model/questionTypes/shared";
|
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
|
||||||
import { enqueueSnackbar } from "notistack";
|
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
|
||||||
import { updateOpenedModalSettingsId } from "@root/uiTools/actions";
|
|
||||||
import { updateRootContentId } from "@root/quizes/actions";
|
|
||||||
import { useUiTools } from "@root/uiTools/store";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { updateSomeWorkBackend } from "@root/uiTools/actions";
|
|
||||||
import { DeleteFunction } from "@utils/deleteFunc";
|
import { DeleteFunction } from "@utils/deleteFunc";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { CopyIcon } from "../../../assets/icons/questionsPage/CopyIcon";
|
||||||
|
import Branching from "../../../assets/icons/questionsPage/branching";
|
||||||
|
import SettingIcon from "../../../assets/icons/questionsPage/settingIcon";
|
||||||
|
import type { AnyTypedQuizQuestion } from "../../../model/questionTypes/shared";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
switchState: string;
|
switchState: string;
|
||||||
@ -213,7 +199,7 @@ export default function ButtonsOptions({
|
|||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
} else {
|
} else {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -258,7 +244,7 @@ export default function ButtonsOptions({
|
|||||||
sx={{ minWidth: "150px" }}
|
sx={{ minWidth: "150px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight";
|
import { QuizQuestionVariant } from "@model/questionTypes/variant";
|
||||||
import { DoubleTick } from "@icons/questionsPage/DoubleTick";
|
|
||||||
import { VectorQuestions } from "@icons/questionsPage/VectorQuestions";
|
|
||||||
import { QuizQuestionVarImg } from "@model/questionTypes/varimg";
|
import { QuizQuestionVarImg } from "@model/questionTypes/varimg";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
IconButton,
|
IconButton,
|
||||||
Modal,
|
Modal,
|
||||||
Tooltip,
|
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
@ -15,31 +12,20 @@ import {
|
|||||||
import {
|
import {
|
||||||
copyQuestion,
|
copyQuestion,
|
||||||
deleteQuestion,
|
deleteQuestion,
|
||||||
updateQuestion,
|
|
||||||
clearRuleForAll,
|
|
||||||
getQuestionByContentId,
|
|
||||||
deleteQuestionWithTimeout,
|
deleteQuestionWithTimeout,
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
|
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||||
|
import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
|
||||||
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
|
||||||
import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal";
|
import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal";
|
||||||
|
import { DeleteFunction } from "@utils/deleteFunc";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
import { CopyIcon } from "../../assets/icons/questionsPage/CopyIcon";
|
||||||
import Branching from "../../assets/icons/questionsPage/branching";
|
import Branching from "../../assets/icons/questionsPage/branching";
|
||||||
import Clue from "../../assets/icons/questionsPage/clue";
|
|
||||||
import { DeleteIcon } from "../../assets/icons/questionsPage/deleteIcon";
|
import { DeleteIcon } from "../../assets/icons/questionsPage/deleteIcon";
|
||||||
import { HideIcon } from "../../assets/icons/questionsPage/hideIcon";
|
|
||||||
import ImgIcon from "../../assets/icons/questionsPage/imgIcon";
|
import ImgIcon from "../../assets/icons/questionsPage/imgIcon";
|
||||||
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
|
||||||
import { QuizQuestionVariant } from "@model/questionTypes/variant";
|
|
||||||
import { updateOpenedModalSettingsId } from "@root/questions/actions";
|
|
||||||
import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
|
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
|
||||||
import { enqueueSnackbar } from "notistack";
|
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
|
||||||
import { updateRootContentId } from "@root/quizes/actions";
|
|
||||||
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
|
||||||
import { updateSomeWorkBackend } from "@root/uiTools/actions";
|
|
||||||
import { DeleteFunction } from "@utils/deleteFunc";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
switchState: string;
|
switchState: string;
|
||||||
@ -337,7 +323,7 @@ export default function ButtonsOptionsAndPict({
|
|||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
} else {
|
} else {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -382,7 +368,7 @@ export default function ButtonsOptionsAndPict({
|
|||||||
sx={{ minWidth: "150px" }}
|
sx={{ minWidth: "150px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionDate } from "../../../model/questionTypes/date";
|
import type { QuizQuestionDate } from "../../../model/questionTypes/date";
|
||||||
|
|
||||||
type SettingsDataProps = {
|
type SettingsDataProps = {
|
||||||
@ -22,10 +13,6 @@ export default function SettingsData({ question }: SettingsDataProps) {
|
|||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
|
||||||
const setInnerName = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -3,13 +3,12 @@ import {
|
|||||||
UntypedQuizQuestion,
|
UntypedQuizQuestion,
|
||||||
} from "@model/questionTypes/shared";
|
} from "@model/questionTypes/shared";
|
||||||
import { Box, ListItem, Typography, useTheme } from "@mui/material";
|
import { Box, ListItem, Typography, useTheme } from "@mui/material";
|
||||||
|
import { cancelQuestionDeletion } from "@root/questions/actions";
|
||||||
|
import { updateEditSomeQuestion } from "@root/uiTools/actions";
|
||||||
|
import { useUiTools } from "@root/uiTools/store";
|
||||||
import { memo, useEffect } from "react";
|
import { memo, useEffect } from "react";
|
||||||
import { Draggable } from "react-beautiful-dnd";
|
import { Draggable } from "react-beautiful-dnd";
|
||||||
import QuestionsPageCard from "./QuestionPageCard";
|
import QuestionsPageCard from "./QuestionPageCard";
|
||||||
import { cancelQuestionDeletion } from "@root/questions/actions";
|
|
||||||
import { updateEditSomeQuestion } from "@root/uiTools/actions";
|
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
|
||||||
import { useUiTools } from "@root/uiTools/store";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
||||||
@ -27,7 +26,7 @@ function DraggableListItem({
|
|||||||
setOpenBranchingPage,
|
setOpenBranchingPage,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { editSomeQuestion } = useUiTools();
|
const editSomeQuestion = useUiTools((state) => state.editSomeQuestion);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
|
@ -13,6 +13,7 @@ import OptionsPict from "@icons/questionsPage/options_pict";
|
|||||||
import Page from "@icons/questionsPage/page";
|
import Page from "@icons/questionsPage/page";
|
||||||
import RatingIcon from "@icons/questionsPage/rating";
|
import RatingIcon from "@icons/questionsPage/rating";
|
||||||
import Slider from "@icons/questionsPage/slider";
|
import Slider from "@icons/questionsPage/slider";
|
||||||
|
import { QuestionType } from "@model/question/question";
|
||||||
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@ -21,8 +22,9 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
Modal,
|
Modal,
|
||||||
|
TextField as MuiTextField,
|
||||||
Paper,
|
Paper,
|
||||||
TextField,
|
TextFieldProps,
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
@ -31,26 +33,24 @@ import {
|
|||||||
copyQuestion,
|
copyQuestion,
|
||||||
createUntypedQuestion,
|
createUntypedQuestion,
|
||||||
deleteQuestion,
|
deleteQuestion,
|
||||||
|
deleteQuestionWithTimeout,
|
||||||
toggleExpandQuestion,
|
toggleExpandQuestion,
|
||||||
updateQuestion,
|
updateQuestion,
|
||||||
updateUntypedQuestion,
|
updateUntypedQuestion,
|
||||||
deleteQuestionWithTimeout,
|
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
import { useRef, useState } from "react";
|
import { DeleteFunction } from "@utils/deleteFunc";
|
||||||
|
import { FC, useRef, useState } from "react";
|
||||||
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import { ReactComponent as PlusIcon } from "../../../assets/icons/plus.svg";
|
import { ReactComponent as PlusIcon } from "../../../assets/icons/plus.svg";
|
||||||
import type {
|
import type {
|
||||||
AnyTypedQuizQuestion,
|
AnyTypedQuizQuestion,
|
||||||
UntypedQuizQuestion,
|
UntypedQuizQuestion,
|
||||||
} from "../../../model/questionTypes/shared";
|
} from "../../../model/questionTypes/shared";
|
||||||
import SwitchQuestionsPage from "../SwitchQuestionsPage";
|
import SwitchQuestionsPage from "../SwitchQuestionsPage";
|
||||||
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
|
||||||
import TypeQuestions from "../TypeQuestions";
|
import TypeQuestions from "../TypeQuestions";
|
||||||
import { QuestionType } from "@model/question/question";
|
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
const TextField = MuiTextField as unknown as FC<TextFieldProps>;
|
||||||
import { DeleteFunction } from "@utils/deleteFunc";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
||||||
@ -71,7 +71,6 @@ export default function QuestionsPageCard({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const maxLengthTextField = 225;
|
const maxLengthTextField = 225;
|
||||||
|
|
||||||
const { questions } = useQuestionsStore();
|
|
||||||
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
const [plusVisible, setPlusVisible] = useState<boolean>(false);
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
@ -82,16 +81,15 @@ export default function QuestionsPageCard({
|
|||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const anchorRef = useRef(null);
|
const anchorRef = useRef(null);
|
||||||
const quiz = useCurrentQuiz();
|
|
||||||
|
|
||||||
const setTitle = useDebouncedCallback((title) => {
|
const setTitle = (title: string) => {
|
||||||
const updateQuestionFn =
|
const updateQuestionFn =
|
||||||
question.type === null ? updateUntypedQuestion : updateQuestion;
|
question.type === null ? updateUntypedQuestion : updateQuestion;
|
||||||
|
|
||||||
updateQuestionFn(question.id, (question) => {
|
updateQuestionFn(question.id, (question) => {
|
||||||
question.title = title;
|
question.title = title;
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
|
|
||||||
const handleInputFocus = () => {
|
const handleInputFocus = () => {
|
||||||
setIsTextFieldtActive(true);
|
setIsTextFieldtActive(true);
|
||||||
@ -134,11 +132,9 @@ export default function QuestionsPageCard({
|
|||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
id="questionTitle"
|
id="questionTitle"
|
||||||
defaultValue={question.title}
|
value={question.title}
|
||||||
placeholder={"Заголовок вопроса"}
|
placeholder={"Заголовок вопроса"}
|
||||||
onChange={({ target }: { target: HTMLInputElement }) =>
|
onChange={({ target }) => setTitle(target.value || " ")}
|
||||||
setTitle(target.value || " ")
|
|
||||||
}
|
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
inputProps={{
|
inputProps={{
|
||||||
@ -303,7 +299,7 @@ export default function QuestionsPageCard({
|
|||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
} else {
|
} else {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -350,7 +346,7 @@ export default function QuestionsPageCard({
|
|||||||
sx={{ minWidth: "150px" }}
|
sx={{ minWidth: "150px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,15 +1,7 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionSelect } from "../../../model/questionTypes/select";
|
import type { QuizQuestionSelect } from "../../../model/questionTypes/select";
|
||||||
|
|
||||||
type SettingDropDownProps = {
|
type SettingDropDownProps = {
|
||||||
@ -21,17 +13,13 @@ export default function SettingDropDown({ question }: SettingDropDownProps) {
|
|||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
const debounced = useDebouncedCallback((value) => {
|
const setContentDefault = (value: string) => {
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
const debounceAnswer = useDebouncedCallback((value) => {
|
|
||||||
updateQuestion(question.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
if (question.type !== "select") return;
|
if (question.type !== "select") return;
|
||||||
|
|
||||||
question.content.default = value;
|
question.content.default = value;
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -98,9 +86,9 @@ export default function SettingDropDown({ question }: SettingDropDownProps) {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
placeholder={"Выберите вариант"}
|
placeholder={"Выберите вариант"}
|
||||||
text={question.content.default}
|
value={question.content.default}
|
||||||
maxLength={60}
|
maxLength={60}
|
||||||
onChange={({ target }) => debounceAnswer(target.value)}
|
onChange={({ target }) => setContentDefault(target.value)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
@ -178,7 +166,7 @@ export default function SettingDropDown({ question }: SettingDropDownProps) {
|
|||||||
<CustomTextField
|
<CustomTextField
|
||||||
placeholder={"Выберите вариант"}
|
placeholder={"Выберите вариант"}
|
||||||
text={question.content.default}
|
text={question.content.default}
|
||||||
onChange={({ target }) => debounceAnswer(target.value)}
|
onChange={({ target }) => setContentDefault(target.value)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{/*{question.content.innerNameCheck && (*/}
|
{/*{question.content.innerNameCheck && (*/}
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji";
|
import type { QuizQuestionEmoji } from "../../../model/questionTypes/emoji";
|
||||||
|
|
||||||
type SettingEmojiProps = {
|
type SettingEmojiProps = {
|
||||||
@ -19,14 +10,9 @@ type SettingEmojiProps = {
|
|||||||
export default function SettingEmoji({ question }: SettingEmojiProps) {
|
export default function SettingEmoji({ question }: SettingEmojiProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(985));
|
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
const setInnerName = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -19,10 +19,11 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
Paper,
|
Paper,
|
||||||
TextField,
|
TextField as MuiTextField,
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
|
TextFieldProps,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import {
|
import {
|
||||||
copyQuestion,
|
copyQuestion,
|
||||||
@ -33,7 +34,7 @@ import {
|
|||||||
updateUntypedQuestion,
|
updateUntypedQuestion,
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import { useRef, useState } from "react";
|
import { FC, useRef, useState } from "react";
|
||||||
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
import type { DraggableProvidedDragHandleProps } from "react-beautiful-dnd";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
import type {
|
import type {
|
||||||
@ -55,6 +56,8 @@ import {
|
|||||||
SignalCellularNullOutlined,
|
SignalCellularNullOutlined,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
|
|
||||||
|
const TextField = MuiTextField as unknown as FC<TextFieldProps>;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
||||||
questionIndex: number;
|
questionIndex: number;
|
||||||
@ -74,14 +77,14 @@ export default function QuestionsPageCard({
|
|||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
const setTitle = useDebouncedCallback((title) => {
|
const setTitle = (title: string) => {
|
||||||
const updateQuestionFn =
|
const updateQuestionFn =
|
||||||
question.type === null ? updateUntypedQuestion : updateQuestion;
|
question.type === null ? updateUntypedQuestion : updateQuestion;
|
||||||
|
|
||||||
updateQuestionFn(question.id, (question) => {
|
updateQuestionFn(question.id, (question) => {
|
||||||
question.title = title;
|
question.title = title;
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
|
|
||||||
const handleInputFocus = () => {
|
const handleInputFocus = () => {
|
||||||
setIsTextFieldtActive(true);
|
setIsTextFieldtActive(true);
|
||||||
@ -134,10 +137,9 @@ export default function QuestionsPageCard({
|
|||||||
>
|
>
|
||||||
<TextField
|
<TextField
|
||||||
placeholder={`Заголовок ${questionIndex + 1} вопроса`}
|
placeholder={`Заголовок ${questionIndex + 1} вопроса`}
|
||||||
defaultValue={question.title}
|
value={question.title}
|
||||||
onChange={({ target }) => {
|
onChange={({ target }) => {
|
||||||
if ((target.value, toString().length <= 225))
|
if (target.value.length <= 225) setTitle(target.value);
|
||||||
setTitle(target.value);
|
|
||||||
}}
|
}}
|
||||||
onFocus={handleInputFocus}
|
onFocus={handleInputFocus}
|
||||||
onBlur={handleInputBlur}
|
onBlur={handleInputBlur}
|
||||||
|
@ -1,15 +1,7 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
|
import type { QuizQuestionVarImg } from "../../../model/questionTypes/varimg";
|
||||||
|
|
||||||
type SettingOptionsAndPictProps = {
|
type SettingOptionsAndPictProps = {
|
||||||
@ -24,17 +16,13 @@ export default function SettingOptionsAndPict({
|
|||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(680));
|
const isMobile = useMediaQuery(theme.breakpoints.down(680));
|
||||||
|
|
||||||
const setReplText = useDebouncedCallback((replText) => {
|
const setReplText = (replText: string) => {
|
||||||
updateQuestion(question.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
if (question.type !== "varimg") return;
|
if (question.type !== "varimg") return;
|
||||||
|
|
||||||
question.content.replText = replText;
|
question.content.replText = replText;
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
|
|
||||||
const setDescription = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Tooltip,
|
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import FormatIcon1 from "../../../assets/icons/questionsPage/FormatIcon1";
|
|
||||||
import FormatIcon2 from "../../../assets/icons/questionsPage/FormatIcon2";
|
|
||||||
import ProportionsIcon11 from "../../../assets/icons/questionsPage/ProportionsIcon11";
|
import ProportionsIcon11 from "../../../assets/icons/questionsPage/ProportionsIcon11";
|
||||||
import ProportionsIcon12 from "../../../assets/icons/questionsPage/ProportionsIcon12";
|
import ProportionsIcon12 from "../../../assets/icons/questionsPage/ProportionsIcon12";
|
||||||
import ProportionsIcon21 from "../../../assets/icons/questionsPage/ProportionsIcon21";
|
import ProportionsIcon21 from "../../../assets/icons/questionsPage/ProportionsIcon21";
|
||||||
@ -43,18 +37,6 @@ export default function SettingOpytionsPict({
|
|||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
|
||||||
const debounced = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
const updateProportions = (proportions: Proportion) => {
|
|
||||||
updateQuestion(question.id, (question) => {
|
|
||||||
if (question.type !== "images") return;
|
|
||||||
|
|
||||||
question.content.xy = proportions;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
|
@ -7,14 +7,12 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { updateQuestion } from "@root/questions/actions";
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
|
import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
import InfoIcon from "../../../assets/icons/InfoIcon";
|
||||||
import type { QuizQuestionText } from "../../../model/questionTypes/text";
|
import type { QuizQuestionText } from "../../../model/questionTypes/text";
|
||||||
import ButtonsOptions from "../ButtonsOptions";
|
|
||||||
import SwitchTextField from "./switchTextField";
|
|
||||||
import TooltipClickInfo from "@ui_kit/Toolbars/TooltipClickInfo";
|
|
||||||
import ButtonsOptionsAndPict from "../ButtonsOptionsAndPict";
|
import ButtonsOptionsAndPict from "../ButtonsOptionsAndPict";
|
||||||
|
import SwitchTextField from "./switchTextField";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: QuizQuestionText;
|
question: QuizQuestionText;
|
||||||
@ -32,13 +30,13 @@ export default function OwnTextField({
|
|||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
|
||||||
const setPlaceholder = useDebouncedCallback((value) => {
|
const setPlaceholder = (value: string) => {
|
||||||
updateQuestion(question.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
if (question.type !== "text") return;
|
if (question.type !== "text") return;
|
||||||
|
|
||||||
question.content.placeholder = value;
|
question.content.placeholder = value;
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
|
|
||||||
const SSHC = (data: string) => {
|
const SSHC = (data: string) => {
|
||||||
setSwitchState(data);
|
setSwitchState(data);
|
||||||
@ -60,7 +58,7 @@ export default function OwnTextField({
|
|||||||
>
|
>
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
placeholder={"Пример ответа"}
|
placeholder={"Пример ответа"}
|
||||||
text={question.content.placeholder}
|
value={question.content.placeholder}
|
||||||
onChange={({ target }) => setPlaceholder(target.value)}
|
onChange={({ target }) => setPlaceholder(target.value)}
|
||||||
sx={{
|
sx={{
|
||||||
maxWidth: isFigmaTablte ? "549px" : "640px",
|
maxWidth: isFigmaTablte ? "549px" : "640px",
|
||||||
|
@ -1,21 +1,6 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
FormControl,
|
|
||||||
FormControlLabel,
|
|
||||||
Radio,
|
|
||||||
RadioGroup,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import CheckedIcon from "@ui_kit/RadioCheck";
|
|
||||||
import CheckIcon from "@ui_kit/RadioIcon";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionText } from "../../../model/questionTypes/text";
|
import type { QuizQuestionText } from "../../../model/questionTypes/text";
|
||||||
|
|
||||||
type SettingTextFieldProps = {
|
type SettingTextFieldProps = {
|
||||||
@ -38,10 +23,6 @@ export default function SettingTextField({ question }: SettingTextFieldProps) {
|
|||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
|
|
||||||
const debounced = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -15,18 +15,12 @@ import {
|
|||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
import CustomTextField from "@ui_kit/CustomTextField";
|
||||||
|
|
||||||
import { useState } from "react";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import type { QuizQuestionPage } from "../../../model/questionTypes/page";
|
|
||||||
import ButtonsOptions from "../ButtonsOptions";
|
|
||||||
import SwitchPageOptions from "./switchPageOptions";
|
|
||||||
import { MediaSelectionAndDisplay } from "@ui_kit/MediaSelectionAndDisplay";
|
|
||||||
import { CopyIcon } from "@icons/questionsPage/CopyIcon";
|
import { CopyIcon } from "@icons/questionsPage/CopyIcon";
|
||||||
import { DeleteFunction } from "@utils/deleteFunc";
|
|
||||||
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
import { DeleteIcon } from "@icons/questionsPage/deleteIcon";
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
import { MediaSelectionAndDisplay } from "@ui_kit/MediaSelectionAndDisplay";
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
import { DeleteFunction } from "@utils/deleteFunc";
|
||||||
import { updateDesireToOpenABranchingModal } from "@root/uiTools/actions";
|
import { useState } from "react";
|
||||||
|
import type { QuizQuestionPage } from "../../../model/questionTypes/page";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
disableInput?: boolean;
|
disableInput?: boolean;
|
||||||
@ -36,30 +30,18 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function PageOptions({ disableInput, question }: Props) {
|
export default function PageOptions({ disableInput, question }: Props) {
|
||||||
const [switchState, setSwitchState] = useState("setting");
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(980));
|
const isTablet = useMediaQuery(theme.breakpoints.down(980));
|
||||||
const isFigmaTablet = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablet = useMediaQuery(theme.breakpoints.down(990));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(780));
|
const isMobile = useMediaQuery(theme.breakpoints.down(780));
|
||||||
|
const [openDelete, setOpenDelete] = useState<boolean>(false);
|
||||||
|
|
||||||
const setText = useDebouncedCallback((value) => {
|
const setText = (value: string) => {
|
||||||
updateQuestion(question.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
if (question.type !== "page") return;
|
if (question.type !== "page") return;
|
||||||
|
|
||||||
question.content.text = value;
|
question.content.text = value;
|
||||||
});
|
});
|
||||||
}, 200);
|
|
||||||
|
|
||||||
const quiz = useCurrentQuiz();
|
|
||||||
const { questions } = useQuestionsStore.getState();
|
|
||||||
const [openDelete, setOpenDelete] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const openedModal = () => {
|
|
||||||
updateDesireToOpenABranchingModal(question.content.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const SSHC = (data: string) => {
|
|
||||||
setSwitchState(data);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -82,7 +64,7 @@ export default function PageOptions({ disableInput, question }: Props) {
|
|||||||
<CustomTextField
|
<CustomTextField
|
||||||
id="addText"
|
id="addText"
|
||||||
placeholder={"Можно добавить текст"}
|
placeholder={"Можно добавить текст"}
|
||||||
text={question.content.text}
|
value={question.content.text}
|
||||||
onChange={({ target }) => setText(target.value)}
|
onChange={({ target }) => setText(target.value)}
|
||||||
maxLength={50}
|
maxLength={50}
|
||||||
/>
|
/>
|
||||||
@ -126,7 +108,7 @@ export default function PageOptions({ disableInput, question }: Props) {
|
|||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
} else {
|
} else {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@ -171,7 +153,7 @@ export default function PageOptions({ disableInput, question }: Props) {
|
|||||||
sx={{ minWidth: "150px" }}
|
sx={{ minWidth: "150px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
deleteQuestionWithTimeout(question.id, () =>
|
deleteQuestionWithTimeout(question.id, () =>
|
||||||
DeleteFunction(questions, question, quiz),
|
DeleteFunction(question),
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionPage } from "../../../model/questionTypes/page";
|
import type { QuizQuestionPage } from "../../../model/questionTypes/page";
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
|
|
||||||
type SettingPageOptionsProps = {
|
type SettingPageOptionsProps = {
|
||||||
question: QuizQuestionPage;
|
question: QuizQuestionPage;
|
||||||
@ -22,10 +11,6 @@ export default function SettingPageOptions({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
const setInnerName = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -1,14 +1,9 @@
|
|||||||
import { useEffect, useLayoutEffect } from "react";
|
|
||||||
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
import { Box, useMediaQuery, useTheme } from "@mui/material";
|
||||||
|
import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { BranchingMap } from "./BranchingMap";
|
||||||
import { DraggableList } from "./DraggableList";
|
import { DraggableList } from "./DraggableList";
|
||||||
import { SwitchBranchingPanel } from "./SwitchBranchingPanel";
|
import { SwitchBranchingPanel } from "./SwitchBranchingPanel";
|
||||||
import { BranchingMap } from "./BranchingMap";
|
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
|
||||||
import { useUiTools } from "@root/uiTools/store";
|
|
||||||
import { useQuestions } from "@root/questions/hooks";
|
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
|
||||||
|
|
||||||
import { deleteTimeoutedQuestions } from "@utils/deleteTimeoutedQuestions";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
openBranchingPage: boolean;
|
openBranchingPage: boolean;
|
||||||
@ -21,17 +16,15 @@ export const QuestionSwitchWindowTool = ({
|
|||||||
setOpenBranchingPage,
|
setOpenBranchingPage,
|
||||||
widthMain,
|
widthMain,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { questions } = useQuestionsStore.getState();
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
const isMobile = useMediaQuery(theme.breakpoints.down(600));
|
||||||
const quiz = useCurrentQuiz();
|
|
||||||
|
|
||||||
const openBranchingPageHC = () => {
|
const openBranchingPageHC = useCallback(() => {
|
||||||
if (!openBranchingPage) {
|
if (!openBranchingPage) {
|
||||||
deleteTimeoutedQuestions(questions, quiz);
|
deleteTimeoutedQuestions();
|
||||||
}
|
}
|
||||||
setOpenBranchingPage(!openBranchingPage);
|
setOpenBranchingPage(!openBranchingPage);
|
||||||
};
|
}, [openBranchingPage, setOpenBranchingPage]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
import { useState, useEffect, useRef } from "react";
|
|
||||||
import { useParams } from "react-router-dom";
|
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
|
TextField as MuiTextField,
|
||||||
|
TextFieldProps,
|
||||||
Typography,
|
Typography,
|
||||||
TextField,
|
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
|
import { FC, useLayoutEffect, useRef, useState } from "react";
|
||||||
|
import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon";
|
||||||
|
import StarIconMini from "../../../assets/icons/questionsPage/StarIconMini";
|
||||||
|
import HashtagIcon from "../../../assets/icons/questionsPage/hashtagIcon";
|
||||||
|
import HeartIcon from "../../../assets/icons/questionsPage/heartIcon";
|
||||||
|
import LightbulbIcon from "../../../assets/icons/questionsPage/lightbulbIcon";
|
||||||
|
import LikeIcon from "../../../assets/icons/questionsPage/likeIcon";
|
||||||
|
import TropfyIcon from "../../../assets/icons/questionsPage/tropfyIcon";
|
||||||
|
import type { QuizQuestionRating } from "../../../model/questionTypes/rating";
|
||||||
import ButtonsOptions from "../ButtonsOptions";
|
import ButtonsOptions from "../ButtonsOptions";
|
||||||
import SwitchRating from "./switchRating";
|
import SwitchRating from "./switchRating";
|
||||||
import TropfyIcon from "../../../assets/icons/questionsPage/tropfyIcon";
|
|
||||||
import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon";
|
const TextField = MuiTextField as unknown as FC<TextFieldProps>;
|
||||||
import HeartIcon from "../../../assets/icons/questionsPage/heartIcon";
|
|
||||||
import LikeIcon from "../../../assets/icons/questionsPage/likeIcon";
|
|
||||||
import LightbulbIcon from "../../../assets/icons/questionsPage/lightbulbIcon";
|
|
||||||
import HashtagIcon from "../../../assets/icons/questionsPage/hashtagIcon";
|
|
||||||
import StarIconMini from "../../../assets/icons/questionsPage/StarIconMini";
|
|
||||||
import type { QuizQuestionRating } from "../../../model/questionTypes/rating";
|
|
||||||
import { updateQuestion } from "@root/questions/actions";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
question: QuizQuestionRating;
|
question: QuizQuestionRating;
|
||||||
@ -37,43 +38,36 @@ export default function RatingOptions({
|
|||||||
setOpenBranchingPage,
|
setOpenBranchingPage,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [switchState, setSwitchState] = useState("setting");
|
const [switchState, setSwitchState] = useState("setting");
|
||||||
const [negativeText, setNegativeText] = useState<string>("");
|
|
||||||
const [positiveText, setPositiveText] = useState<string>("");
|
|
||||||
const [negativeTextWidth, setNegativeTextWidth] = useState<number>(0);
|
const [negativeTextWidth, setNegativeTextWidth] = useState<number>(0);
|
||||||
const [positiveTextWidth, setPositiveTextWidth] = useState<number>(0);
|
const [positiveTextWidth, setPositiveTextWidth] = useState<number>(0);
|
||||||
const quizId = Number(useParams().quizId);
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const negativeRef = useRef<HTMLDivElement>(null);
|
const negativeRef = useRef<HTMLDivElement>(null);
|
||||||
const positiveRef = useRef<HTMLDivElement>(null);
|
const positiveRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const debounceNegativeDescription = useDebouncedCallback((value) => {
|
const setNegativeDescription = (value: string) => {
|
||||||
updateQuestion(question.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
if (question.type !== "rating") return;
|
if (question.type !== "rating") return;
|
||||||
|
|
||||||
question.content.ratingNegativeDescription = value.substring(0, 15);
|
question.content.ratingNegativeDescription = value.substring(0, 15);
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
const debouncePositiveDescription = useDebouncedCallback((value) => {
|
|
||||||
|
const setPositiveDescription = (value: string) => {
|
||||||
updateQuestion(question.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
if (question.type !== "rating") return;
|
if (question.type !== "rating") return;
|
||||||
|
|
||||||
question.content.ratingPositiveDescription = value.substring(0, 15);
|
question.content.ratingPositiveDescription = value.substring(0, 15);
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setNegativeText(question.content.ratingNegativeDescription);
|
|
||||||
setPositiveText(question.content.ratingPositiveDescription);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setNegativeTextWidth(negativeRef.current?.offsetWidth || 0);
|
setNegativeTextWidth(negativeRef.current?.offsetWidth || 0);
|
||||||
}, [negativeText]);
|
}, [question.content.ratingNegativeDescription]);
|
||||||
|
|
||||||
useEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setPositiveTextWidth(positiveRef.current?.offsetWidth || 0);
|
setPositiveTextWidth(positiveRef.current?.offsetWidth || 0);
|
||||||
}, [positiveText]);
|
}, [question.content.ratingPositiveDescription]);
|
||||||
|
|
||||||
const buttonRatingForm: ButtonRatingFrom[] = [
|
const buttonRatingForm: ButtonRatingFrom[] = [
|
||||||
{
|
{
|
||||||
@ -221,21 +215,17 @@ export default function RatingOptions({
|
|||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{negativeText}
|
{question.content.ratingNegativeDescription}
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
defaultValue={question.content.ratingNegativeDescription}
|
value={question.content.ratingNegativeDescription}
|
||||||
value={negativeText}
|
|
||||||
placeholder="Негативно"
|
placeholder="Негативно"
|
||||||
onChange={({ target }: { target: HTMLInputElement }) => {
|
onChange={({ target }) => {
|
||||||
if (target.value.length <= 15) {
|
if (target.value.length <= 15) {
|
||||||
setNegativeText(target.value);
|
setNegativeDescription(target.value);
|
||||||
debounceNegativeDescription(target.value);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onBlur={({ target }: { target: HTMLInputElement }) =>
|
onBlur={({ target }) => setNegativeDescription(target.value)}
|
||||||
debounceNegativeDescription(target.value)
|
|
||||||
}
|
|
||||||
sx={{
|
sx={{
|
||||||
width: negativeTextWidth + 10 + "px",
|
width: negativeTextWidth + 10 + "px",
|
||||||
maxWidth: isMobile ? "140px" : "230px",
|
maxWidth: isMobile ? "140px" : "230px",
|
||||||
@ -279,20 +269,17 @@ export default function RatingOptions({
|
|||||||
fontSize: "16px",
|
fontSize: "16px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{positiveText}
|
{question.content.ratingPositiveDescription}
|
||||||
</Typography>
|
</Typography>
|
||||||
<TextField
|
<TextField
|
||||||
value={positiveText}
|
value={question.content.ratingPositiveDescription}
|
||||||
placeholder="Позитивно"
|
placeholder="Позитивно"
|
||||||
onChange={({ target }: { target: HTMLInputElement }) => {
|
onChange={({ target }) => {
|
||||||
if (target.value.length <= 15) {
|
if (target.value.length <= 15) {
|
||||||
setPositiveText(target.value);
|
setPositiveDescription(target.value);
|
||||||
debouncePositiveDescription(target.value);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onBlur={({ target }: { target: HTMLInputElement }) =>
|
onBlur={({ target }) => setPositiveDescription(target.value)}
|
||||||
debouncePositiveDescription(target.value)
|
|
||||||
}
|
|
||||||
sx={{
|
sx={{
|
||||||
width: positiveTextWidth + 10 + "px",
|
width: positiveTextWidth + 10 + "px",
|
||||||
maxWidth: isMobile ? "140px" : "230px",
|
maxWidth: isMobile ? "140px" : "230px",
|
||||||
|
@ -3,16 +3,12 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
ButtonBase,
|
ButtonBase,
|
||||||
Slider,
|
Slider,
|
||||||
Tooltip,
|
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon";
|
import FlagIcon from "../../../assets/icons/questionsPage/FlagIcon";
|
||||||
import StarIconMini from "../../../assets/icons/questionsPage/StarIconMini";
|
import StarIconMini from "../../../assets/icons/questionsPage/StarIconMini";
|
||||||
import HashtagIcon from "../../../assets/icons/questionsPage/hashtagIcon";
|
import HashtagIcon from "../../../assets/icons/questionsPage/hashtagIcon";
|
||||||
@ -32,10 +28,6 @@ export default function SettingSlider({ question }: SettingSliderProps) {
|
|||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
const isWrappColumn = useMediaQuery(theme.breakpoints.down(980));
|
||||||
|
|
||||||
const setInnerName = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
const buttonRatingForm: ButtonRatingFrom[] = [
|
const buttonRatingForm: ButtonRatingFrom[] = [
|
||||||
{ name: "star", icon: <StarIconMini color={theme.palette.grey3.main} /> },
|
{ name: "star", icon: <StarIconMini color={theme.palette.grey3.main} /> },
|
||||||
{ name: "trophie", icon: <TropfyIcon color={theme.palette.grey3.main} /> },
|
{ name: "trophie", icon: <TropfyIcon color={theme.palette.grey3.main} /> },
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionNumber } from "../../../model/questionTypes/number";
|
import type { QuizQuestionNumber } from "../../../model/questionTypes/number";
|
||||||
|
|
||||||
type SettingSliderProps = {
|
type SettingSliderProps = {
|
||||||
@ -22,10 +13,6 @@ export default function SettingSlider({ question }: SettingSliderProps) {
|
|||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
const setInnerName = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -123,6 +123,9 @@ export default function SwitchQuestionsPage({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case "result":
|
||||||
|
return null;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
notReachable(question);
|
notReachable(question);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionFile } from "../../../model/questionTypes/file";
|
import type { QuizQuestionFile } from "../../../model/questionTypes/file";
|
||||||
|
|
||||||
type SettingsUploadProps = {
|
type SettingsUploadProps = {
|
||||||
@ -20,10 +11,6 @@ export default function SettingsUpload({ question }: SettingsUploadProps) {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
const setInnerName = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -1,15 +1,6 @@
|
|||||||
import {
|
import { Box, Typography, useMediaQuery, useTheme } from "@mui/material";
|
||||||
Box,
|
import { updateQuestion } from "@root/questions/actions";
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useMediaQuery,
|
|
||||||
useTheme,
|
|
||||||
} from "@mui/material";
|
|
||||||
import { setQuestionInnerName, updateQuestion } from "@root/questions/actions";
|
|
||||||
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
import CustomCheckbox from "@ui_kit/CustomCheckbox";
|
||||||
import CustomTextField from "@ui_kit/CustomTextField";
|
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import InfoIcon from "../../../assets/icons/InfoIcon";
|
|
||||||
import type { QuizQuestionVariant } from "../../../model/questionTypes/variant";
|
import type { QuizQuestionVariant } from "../../../model/questionTypes/variant";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -23,10 +14,6 @@ export default function ResponseSettings({ question }: Props) {
|
|||||||
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
const isFigmaTablte = useMediaQuery(theme.breakpoints.down(990));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
const isMobile = useMediaQuery(theme.breakpoints.down(790));
|
||||||
|
|
||||||
const updateQuestionInnerName = useDebouncedCallback((value) => {
|
|
||||||
setQuestionInnerName(question.id, value);
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -5,7 +5,6 @@ import CustomTextField from "@ui_kit/CustomTextField";
|
|||||||
import SelectableButton from "@ui_kit/SelectableButton";
|
import SelectableButton from "@ui_kit/SelectableButton";
|
||||||
import UploadBox from "@ui_kit/UploadBox";
|
import UploadBox from "@ui_kit/UploadBox";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
|
||||||
import UploadIcon from "../../assets/icons/UploadIcon";
|
import UploadIcon from "../../assets/icons/UploadIcon";
|
||||||
import { UploadVideoModal } from "./UploadVideoModal";
|
import { UploadVideoModal } from "./UploadVideoModal";
|
||||||
|
|
||||||
@ -19,11 +18,11 @@ export default function HelpQuestions({ question }: HelpQuestionsProps) {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [backgroundType, setBackgroundType] = useState<BackgroundType>("text");
|
const [backgroundType, setBackgroundType] = useState<BackgroundType>("text");
|
||||||
|
|
||||||
const updateQuestionHint = useDebouncedCallback((value) => {
|
const updateQuestionHint = (value: string) => {
|
||||||
updateQuestion(question.id, (question) => {
|
updateQuestion(question.id, (question) => {
|
||||||
question.content.hint.text = value;
|
question.content.hint.text = value;
|
||||||
});
|
});
|
||||||
}, 200);
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -60,7 +59,7 @@ export default function HelpQuestions({ question }: HelpQuestionsProps) {
|
|||||||
<>
|
<>
|
||||||
<CustomTextField
|
<CustomTextField
|
||||||
placeholder={"Текст консультанта"}
|
placeholder={"Текст консультанта"}
|
||||||
text={question.content.hint.text}
|
value={question.content.hint.text}
|
||||||
onChange={({ target }) => updateQuestionHint(target.value || " ")}
|
onChange={({ target }) => updateQuestionHint(target.value || " ")}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
/>
|
/>
|
||||||
|
@ -3,7 +3,7 @@ import Sidebar from "@ui_kit/Sidebar/Sidebar";
|
|||||||
import Box from "@mui/material/Box";
|
import Box from "@mui/material/Box";
|
||||||
import { useTheme, useMediaQuery, IconButton } from "@mui/material";
|
import { useTheme, useMediaQuery, IconButton } from "@mui/material";
|
||||||
import HeaderFull from "@ui_kit/Header/HeaderFull";
|
import HeaderFull from "@ui_kit/Header/HeaderFull";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { SidebarMobile } from "../ui_kit/Sidebar/SidebarMobile";
|
import { SidebarMobile } from "../ui_kit/Sidebar/SidebarMobile";
|
||||||
import { setShowConfirmLeaveModal } from "@root/uiTools/actions";
|
import { setShowConfirmLeaveModal } from "@root/uiTools/actions";
|
||||||
import { setCurrentStep, setQuizes } from "@root/quizes/actions";
|
import { setCurrentStep, setQuizes } from "@root/quizes/actions";
|
||||||
@ -35,7 +35,6 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const quizConfig = quiz?.config;
|
const quizConfig = quiz?.config;
|
||||||
const { questions } = useQuestionsStore();
|
|
||||||
const { editQuizId } = useQuizStore();
|
const { editQuizId } = useQuizStore();
|
||||||
const currentStep = useQuizStore((state) => state.currentStep);
|
const currentStep = useQuizStore((state) => state.currentStep);
|
||||||
const { isTestServer } = useDomainDefine();
|
const { isTestServer } = useDomainDefine();
|
||||||
@ -73,12 +72,12 @@ export default function Main({ sidebar, header, footer, Page }: Props) {
|
|||||||
const [nextStep, setNextStep] = useState<number>(0);
|
const [nextStep, setNextStep] = useState<number>(0);
|
||||||
const [openBranchingPage, setOpenBranchingPage] = useState<boolean>(false);
|
const [openBranchingPage, setOpenBranchingPage] = useState<boolean>(false);
|
||||||
|
|
||||||
const openBranchingPageHC = () => {
|
const openBranchingPageHC = useCallback(() => {
|
||||||
if (!openBranchingPage) {
|
if (!openBranchingPage) {
|
||||||
deleteTimeoutedQuestions(questions, quiz);
|
deleteTimeoutedQuestions();
|
||||||
}
|
}
|
||||||
setOpenBranchingPage((old) => !old);
|
setOpenBranchingPage((old) => !old);
|
||||||
};
|
}, [openBranchingPage, setOpenBranchingPage]);
|
||||||
|
|
||||||
const isConditionMet =
|
const isConditionMet =
|
||||||
[1].includes(currentStep) && quizConfig?.type !== "form";
|
[1].includes(currentStep) && quizConfig?.type !== "form";
|
||||||
|
@ -59,7 +59,7 @@ export default function EditPage({
|
|||||||
const quiz = useCurrentQuiz();
|
const quiz = useCurrentQuiz();
|
||||||
const { editQuizId } = useQuizStore();
|
const { editQuizId } = useQuizStore();
|
||||||
const { questions } = useQuestionsStore();
|
const { questions } = useQuestionsStore();
|
||||||
const { whyCantCreatePublic, showConfirmLeaveModal, nextStep } = useUiTools();
|
const { showConfirmLeaveModal, nextStep } = useUiTools();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const currentStep = useQuizStore((state) => state.currentStep);
|
const currentStep = useQuizStore((state) => state.currentStep);
|
||||||
|
@ -380,15 +380,15 @@ export const findQuestionById = (quizId: number) => {
|
|||||||
let found = null;
|
let found = null;
|
||||||
questionStore
|
questionStore
|
||||||
.getState()
|
.getState()
|
||||||
["listQuestions"][quizId].some(
|
[
|
||||||
(quiz: AnyTypedQuizQuestion, index: number) => {
|
"listQuestions"
|
||||||
if (quiz.backendId === quizId) {
|
][quizId].some((quiz: AnyTypedQuizQuestion, index: number) => {
|
||||||
found = { quiz, index };
|
if (quiz.backendId === quizId) {
|
||||||
return true;
|
found = { quiz, index };
|
||||||
}
|
return true;
|
||||||
return false;
|
}
|
||||||
},
|
return false;
|
||||||
);
|
});
|
||||||
return found;
|
return found;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,21 +13,14 @@ import {
|
|||||||
UntypedQuizQuestion,
|
UntypedQuizQuestion,
|
||||||
createQuestionVariant,
|
createQuestionVariant,
|
||||||
} from "@model/questionTypes/shared";
|
} from "@model/questionTypes/shared";
|
||||||
import { defaultQuestionByType } from "../../constants/default";
|
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
import { nanoid } from "nanoid";
|
import { nanoid } from "nanoid";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
import { defaultQuestionByType } from "../../constants/default";
|
||||||
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
||||||
import { RequestQueue } from "../../utils/requestQueue";
|
|
||||||
import { updateRootContentId } from "@root/quizes/actions";
|
|
||||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
|
||||||
import { QuestionsStore, useQuestionsStore } from "./store";
|
|
||||||
import { useUiTools } from "../uiTools/store";
|
|
||||||
import { withErrorBoundary } from "react-error-boundary";
|
|
||||||
import { QuizQuestionResult } from "@model/questionTypes/result";
|
|
||||||
import { replaceEmptyLinesToSpace } from "../../utils/replaceEmptyLinesToSpace";
|
import { replaceEmptyLinesToSpace } from "../../utils/replaceEmptyLinesToSpace";
|
||||||
import { useQuizPreviewStore } from "@root/quizPreview";
|
import { RequestQueue } from "../../utils/requestQueue";
|
||||||
import { useQuizStore } from "@root/quizes/store";
|
import { QuestionsStore, useQuestionsStore } from "./store";
|
||||||
|
|
||||||
export const setQuestions = (questions: RawQuestion[] | null | undefined) =>
|
export const setQuestions = (questions: RawQuestion[] | null | undefined) =>
|
||||||
setProducedState(
|
setProducedState(
|
||||||
@ -244,15 +237,16 @@ export const cancelQuestionDeletion = (questionId: string) =>
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const REQUEST_DEBOUNCE = 200;
|
|
||||||
const requestQueue = new RequestQueue();
|
const requestQueue = new RequestQueue();
|
||||||
let requestTimeoutId: ReturnType<typeof setTimeout>;
|
let rollbackQuestions: ReturnType<typeof useQuestionsStore.getState>;
|
||||||
|
|
||||||
export const updateQuestion = async <T = AnyTypedQuizQuestion>(
|
export const updateQuestion = async <T = AnyTypedQuizQuestion>(
|
||||||
questionId: string,
|
questionId: string,
|
||||||
updateFn: (question: T) => void,
|
updateFn: (question: T) => void,
|
||||||
skipQueue = false,
|
skipQueue = false,
|
||||||
) => {
|
) => {
|
||||||
|
if (!rollbackQuestions) rollbackQuestions = useQuestionsStore.getState();
|
||||||
|
|
||||||
setProducedState(
|
setProducedState(
|
||||||
(state) => {
|
(state) => {
|
||||||
const question =
|
const question =
|
||||||
@ -275,8 +269,6 @@ export const updateQuestion = async <T = AnyTypedQuizQuestion>(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// clearTimeout(requestTimeoutId);
|
|
||||||
|
|
||||||
const request = async () => {
|
const request = async () => {
|
||||||
const q =
|
const q =
|
||||||
useQuestionsStore.getState().questions.find((q) => q.id === questionId) ||
|
useQuestionsStore.getState().questions.find((q) => q.id === questionId) ||
|
||||||
@ -291,6 +283,7 @@ export const updateQuestion = async <T = AnyTypedQuizQuestion>(
|
|||||||
const response = await questionApi.edit(
|
const response = await questionApi.edit(
|
||||||
questionToEditQuestionRequest(replaceEmptyLinesToSpace(q)),
|
questionToEditQuestionRequest(replaceEmptyLinesToSpace(q)),
|
||||||
);
|
);
|
||||||
|
rollbackQuestions = useQuestionsStore.getState();
|
||||||
|
|
||||||
//Если мы делаем листочек веточкой - удаляем созданный к нему результ
|
//Если мы делаем листочек веточкой - удаляем созданный к нему результ
|
||||||
const questionResult = useQuestionsStore
|
const questionResult = useQuestionsStore
|
||||||
@ -311,6 +304,8 @@ export const updateQuestion = async <T = AnyTypedQuizQuestion>(
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (isAxiosCanceledError(error)) return;
|
if (isAxiosCanceledError(error)) return;
|
||||||
|
|
||||||
|
useQuestionsStore.setState(rollbackQuestions);
|
||||||
|
|
||||||
devlog("Error editing question", { error, questionId });
|
devlog("Error editing question", { error, questionId });
|
||||||
enqueueSnackbar("Не удалось сохранить вопрос");
|
enqueueSnackbar("Не удалось сохранить вопрос");
|
||||||
}
|
}
|
||||||
@ -321,9 +316,7 @@ export const updateQuestion = async <T = AnyTypedQuizQuestion>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// requestTimeoutId = setTimeout(() => {
|
requestQueue.enqueue(`updateQuestion-${questionId}`, request);
|
||||||
requestQueue.enqueue(request);
|
|
||||||
// }, REQUEST_DEBOUNCE);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const addQuestionVariant = (questionId: string) => {
|
export const addQuestionVariant = (questionId: string) => {
|
||||||
@ -453,7 +446,7 @@ export const createTypedQuestion = async (
|
|||||||
questionId: string,
|
questionId: string,
|
||||||
type: QuestionType,
|
type: QuestionType,
|
||||||
) =>
|
) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(`createTypedQuestion-${questionId}`, async () => {
|
||||||
const questions = useQuestionsStore.getState().questions;
|
const questions = useQuestionsStore.getState().questions;
|
||||||
const question = questions.find((q) => q.id === questionId);
|
const question = questions.find((q) => q.id === questionId);
|
||||||
if (!question) return;
|
if (!question) return;
|
||||||
@ -501,7 +494,7 @@ export const createTypedQuestion = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const deleteQuestion = async (questionId: string) =>
|
export const deleteQuestion = async (questionId: string) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(`deleteQuestion-${questionId}`, async () => {
|
||||||
const question = useQuestionsStore
|
const question = useQuestionsStore
|
||||||
.getState()
|
.getState()
|
||||||
.questions.find((q) => q.id === questionId);
|
.questions.find((q) => q.id === questionId);
|
||||||
@ -525,7 +518,7 @@ export const deleteQuestion = async (questionId: string) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const copyQuestion = async (questionId: string, quizId: number) =>
|
export const copyQuestion = async (questionId: string, quizId: number) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(`copyQuestion-${quizId}-${questionId}`, async () => {
|
||||||
const question = useQuestionsStore
|
const question = useQuestionsStore
|
||||||
.getState()
|
.getState()
|
||||||
.questions.find((q) => q.id === questionId);
|
.questions.find((q) => q.id === questionId);
|
||||||
@ -585,7 +578,7 @@ export const copyQuestion = async (questionId: string, quizId: number) =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function setProducedState<A extends string | { type: unknown }>(
|
function setProducedState<A extends string | { type: string }>(
|
||||||
recipe: (state: QuestionsStore) => void,
|
recipe: (state: QuestionsStore) => void,
|
||||||
action?: A,
|
action?: A,
|
||||||
) {
|
) {
|
||||||
@ -635,7 +628,7 @@ export const createResult = async (
|
|||||||
quizId: number | null | undefined,
|
quizId: number | null | undefined,
|
||||||
parentContentId?: string,
|
parentContentId?: string,
|
||||||
) =>
|
) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(`createResult-${quizId}`, async () => {
|
||||||
if (!quizId || !parentContentId) {
|
if (!quizId || !parentContentId) {
|
||||||
console.error(
|
console.error(
|
||||||
"Нет данных для создания результата. quizId: ",
|
"Нет данных для создания результата. quizId: ",
|
||||||
|
@ -3,15 +3,14 @@ import { devlog, getMessageFromFetchError } from "@frontend/kitui";
|
|||||||
import { quizToEditQuizRequest } from "@model/quiz/edit";
|
import { quizToEditQuizRequest } from "@model/quiz/edit";
|
||||||
import { Quiz, RawQuiz, rawQuizToQuiz } from "@model/quiz/quiz";
|
import { Quiz, RawQuiz, rawQuizToQuiz } from "@model/quiz/quiz";
|
||||||
import { QuizConfig, maxQuizSetupSteps } from "@model/quizSettings";
|
import { QuizConfig, maxQuizSetupSteps } from "@model/quizSettings";
|
||||||
|
import { createUntypedQuestion, updateQuestion } from "@root/questions/actions";
|
||||||
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import { NavigateFunction } from "react-router-dom";
|
import { NavigateFunction } from "react-router-dom";
|
||||||
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
||||||
import { RequestQueue } from "../../utils/requestQueue";
|
import { RequestQueue } from "../../utils/requestQueue";
|
||||||
import { QuizStore, useQuizStore } from "./store";
|
import { QuizStore, useQuizStore } from "./store";
|
||||||
import { createUntypedQuestion, updateQuestion } from "@root/questions/actions";
|
|
||||||
import { useCurrentQuiz } from "./hooks";
|
|
||||||
import { useQuestionsStore } from "@root/questions/store";
|
|
||||||
|
|
||||||
export const setEditQuizId = (quizId: number | null) =>
|
export const setEditQuizId = (quizId: number | null) =>
|
||||||
setProducedState(
|
setProducedState(
|
||||||
@ -157,7 +156,7 @@ export const updateQuiz = (
|
|||||||
clearTimeout(requestTimeoutId);
|
clearTimeout(requestTimeoutId);
|
||||||
requestTimeoutId = setTimeout(async () => {
|
requestTimeoutId = setTimeout(async () => {
|
||||||
requestQueue
|
requestQueue
|
||||||
.enqueue(async () => {
|
.enqueue(`updateQuiz-${quizId}`, async () => {
|
||||||
const quiz = useQuizStore
|
const quiz = useQuizStore
|
||||||
.getState()
|
.getState()
|
||||||
.quizes.find((q) => q.id === quizId);
|
.quizes.find((q) => q.id === quizId);
|
||||||
@ -178,7 +177,7 @@ export const updateQuiz = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const createQuiz = async (navigate: NavigateFunction) =>
|
export const createQuiz = async (navigate: NavigateFunction) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue("createQuiz", async () => {
|
||||||
try {
|
try {
|
||||||
const rawQuiz = await quizApi.create();
|
const rawQuiz = await quizApi.create();
|
||||||
const quiz = rawQuizToQuiz(rawQuiz);
|
const quiz = rawQuizToQuiz(rawQuiz);
|
||||||
@ -196,7 +195,7 @@ export const createQuiz = async (navigate: NavigateFunction) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const deleteQuiz = async (quizId: string) =>
|
export const deleteQuiz = async (quizId: string) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(`deleteQuiz-${quizId}`, async () => {
|
||||||
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
|
const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
|
||||||
if (!quiz) return;
|
if (!quiz) return;
|
||||||
|
|
||||||
|
@ -34,3 +34,11 @@ export function useCurrentQuiz() {
|
|||||||
|
|
||||||
return quiz;
|
return quiz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCurrentQuiz() {
|
||||||
|
const { quizes, editQuizId } = useQuizStore.getState();
|
||||||
|
|
||||||
|
const quiz = quizes.find((q) => q.backendId === editQuizId);
|
||||||
|
|
||||||
|
return quiz;
|
||||||
|
}
|
||||||
|
@ -35,7 +35,7 @@ const removeResult = (resultId: string) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const deleteResult = async (resultId: number) =>
|
export const deleteResult = async (resultId: number) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(`deleteResult-${resultId}`, async () => {
|
||||||
const result = useResultStore
|
const result = useResultStore
|
||||||
.getState()
|
.getState()
|
||||||
.results.find((r) => r.id === resultId);
|
.results.find((r) => r.id === resultId);
|
||||||
@ -56,32 +56,35 @@ export const obsolescenceResult = async (
|
|||||||
resultId: string,
|
resultId: string,
|
||||||
editQuizId: number,
|
editQuizId: number,
|
||||||
) =>
|
) =>
|
||||||
requestQueue.enqueue(async () => {
|
requestQueue.enqueue(
|
||||||
const result = useResultStore
|
`obsolescenceResult-${resultId}-${editQuizId}`,
|
||||||
.getState()
|
async () => {
|
||||||
.results.find((r) => r.id === resultId);
|
const result = useResultStore
|
||||||
if (!result) return;
|
.getState()
|
||||||
if (result.new === false) return;
|
.results.find((r) => r.id === resultId);
|
||||||
let lossDebouncer: null | ReturnType<typeof setTimeout> = null;
|
if (!result) return;
|
||||||
let lossId: string[] = [] as string[];
|
if (result.new === false) return;
|
||||||
if (!lossId.includes(resultId)) lossId.push(resultId);
|
let lossDebouncer: null | ReturnType<typeof setTimeout> = null;
|
||||||
if (typeof lossDebouncer === "number") clearTimeout(lossDebouncer);
|
let lossId: string[] = [] as string[];
|
||||||
lossDebouncer = setTimeout(async () => {
|
if (!lossId.includes(resultId)) lossId.push(resultId);
|
||||||
//стреляем на лишение новизны
|
if (typeof lossDebouncer === "number") clearTimeout(lossDebouncer);
|
||||||
try {
|
lossDebouncer = setTimeout(async () => {
|
||||||
await resultApi.obsolescence(lossId);
|
//стреляем на лишение новизны
|
||||||
//сбрасываем массив
|
try {
|
||||||
lossId = [];
|
await resultApi.obsolescence(lossId);
|
||||||
} catch (error) {
|
//сбрасываем массив
|
||||||
devlog("Error", error);
|
lossId = [];
|
||||||
|
} catch (error) {
|
||||||
|
devlog("Error", error);
|
||||||
|
|
||||||
const message = getMessageFromFetchError(error) ?? "";
|
const message = getMessageFromFetchError(error) ?? "";
|
||||||
enqueueSnackbar(`Ошибка. ${message}`);
|
enqueueSnackbar(`Ошибка. ${message}`);
|
||||||
}
|
}
|
||||||
}, 3000);
|
}, 3000);
|
||||||
const resultList = await resultApi.getList(editQuizId);
|
const resultList = await resultApi.getList(editQuizId);
|
||||||
setResults(resultList);
|
setResults(resultList);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const ExportResults = async (
|
export const ExportResults = async (
|
||||||
filterNew: string,
|
filterNew: string,
|
||||||
@ -110,7 +113,7 @@ export const ExportResults = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function setProducedState<A extends string | { type: unknown }>(
|
function setProducedState<A extends string | { type: string }>(
|
||||||
recipe: (state: ResultStore) => void,
|
recipe: (state: ResultStore) => void,
|
||||||
action?: A,
|
action?: A,
|
||||||
) {
|
) {
|
||||||
|
@ -6,15 +6,17 @@ import {
|
|||||||
getQuestionByContentId,
|
getQuestionByContentId,
|
||||||
updateQuestion,
|
updateQuestion,
|
||||||
} from "@root/questions/actions";
|
} from "@root/questions/actions";
|
||||||
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
import { updateRootContentId } from "@root/quizes/actions";
|
import { updateRootContentId } from "@root/quizes/actions";
|
||||||
|
import { getCurrentQuiz } from "@root/quizes/hooks";
|
||||||
|
|
||||||
//Всё здесь нужно сделать последовательно. И пусть весь мир ждёт.
|
//Всё здесь нужно сделать последовательно. И пусть весь мир ждёт.
|
||||||
|
|
||||||
export const DeleteFunction = async (
|
export const DeleteFunction = async (question: any) => {
|
||||||
questions: any,
|
const questions = useQuestionsStore.getState().questions;
|
||||||
question: any,
|
const quiz = getCurrentQuiz();
|
||||||
quiz: any,
|
if (!quiz) throw new Error("Quiz is null");
|
||||||
) => {
|
|
||||||
if (question.type !== null) {
|
if (question.type !== null) {
|
||||||
if (question.content.rule.parentId === "root") {
|
if (question.content.rule.parentId === "root") {
|
||||||
//удалить из стора root и очистить rule всем вопросам
|
//удалить из стора root и очистить rule всем вопросам
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
import {
|
import { AnyTypedQuizQuestion } from "@model/questionTypes/shared";
|
||||||
AnyTypedQuizQuestion,
|
import { useQuestionsStore } from "@root/questions/store";
|
||||||
UntypedQuizQuestion,
|
|
||||||
} from "@model/questionTypes/shared";
|
|
||||||
import { Quiz } from "@model/quiz/quiz";
|
|
||||||
import { updateSomeWorkBackend } from "@root/uiTools/actions";
|
import { updateSomeWorkBackend } from "@root/uiTools/actions";
|
||||||
import { DeleteFunction } from "@utils/deleteFunc";
|
import { DeleteFunction } from "@utils/deleteFunc";
|
||||||
|
|
||||||
type allQuestionsTypes = AnyTypedQuizQuestion | UntypedQuizQuestion;
|
export const deleteTimeoutedQuestions = async () => {
|
||||||
|
const questions = useQuestionsStore.getState().questions;
|
||||||
|
|
||||||
export const deleteTimeoutedQuestions = async (
|
|
||||||
questions: allQuestionsTypes[],
|
|
||||||
quiz: Quiz | undefined,
|
|
||||||
) => {
|
|
||||||
const questionsForDeletion = questions.filter(
|
const questionsForDeletion = questions.filter(
|
||||||
({ type, deleted }) => type && type !== "result" && deleted,
|
({ type, deleted }) => type && type !== "result" && deleted,
|
||||||
) as AnyTypedQuizQuestion[];
|
) as AnyTypedQuizQuestion[];
|
||||||
@ -19,9 +13,7 @@ export const deleteTimeoutedQuestions = async (
|
|||||||
updateSomeWorkBackend(true);
|
updateSomeWorkBackend(true);
|
||||||
|
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(
|
||||||
questionsForDeletion.map((question) =>
|
questionsForDeletion.map((question) => DeleteFunction(question)),
|
||||||
DeleteFunction(questions, question, quiz),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
updateSomeWorkBackend(false);
|
updateSomeWorkBackend(false);
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
export class RequestQueue<T = unknown> {
|
export class RequestQueue<IdType, T = unknown> {
|
||||||
private pendingPromise = false;
|
private pendingPromise = false;
|
||||||
private items: Array<{
|
private items: Array<{
|
||||||
|
id: IdType;
|
||||||
action: () => Promise<T>;
|
action: () => Promise<T>;
|
||||||
resolve: (value: T) => void;
|
resolve: (value: T) => void;
|
||||||
reject: (reason?: any) => void;
|
reject: (reason?: any) => void;
|
||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
enqueue(action: () => Promise<T>) {
|
enqueue(id: IdType, action: () => Promise<T>) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.items.push({ action, resolve, reject });
|
this.items.push({ action, resolve, reject, id });
|
||||||
this.dequeue();
|
this.dequeue();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -19,6 +20,9 @@ export class RequestQueue<T = unknown> {
|
|||||||
const item = this.items.shift();
|
const item = this.items.shift();
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
|
// remove tasks with same id since they are outdated
|
||||||
|
this.items = this.items.filter((i) => i.id !== item.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.pendingPromise = true;
|
this.pendingPromise = true;
|
||||||
const payload = await item.action();
|
const payload = await item.action();
|
||||||
|
Loading…
Reference in New Issue
Block a user