feat: cancel questin deleting

This commit is contained in:
IlyaDoronin 2023-09-27 17:14:48 +03:00
parent 0c1279b37d
commit b4f1e4857d
6 changed files with 193 additions and 39 deletions

@ -1,4 +1,4 @@
import { useState } from "react"; import { useState, useEffect } from "react";
import MiniButtonSetting from "@ui_kit/MiniButtonSetting"; import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import SettingIcon from "../../assets/icons/questionsPage/settingIcon"; import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
@ -20,6 +20,8 @@ import {
resetSomeField, resetSomeField,
copyQuestion, copyQuestion,
removeQuestion, removeQuestion,
removeQuestionForce,
updateQuestionsList,
} from "@root/questions"; } from "@root/questions";
import { DoubleTick } from "@icons/questionsPage/DoubleTick"; import { DoubleTick } from "@icons/questionsPage/DoubleTick";
import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight"; import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight";
@ -37,10 +39,16 @@ export default function ButtonsOptions({
totalIndex, totalIndex,
}: Props) { }: Props) {
const quizId = Number(useParams().quizId); const quizId = Number(useParams().quizId);
const { openedModalSettings } = questionStore(); const { openedModalSettings, listQuestions } = questionStore();
const [openedReallyChangingModal, setOpenedReallyChangingModal] = const [openedReallyChangingModal, setOpenedReallyChangingModal] =
useState<boolean>(false); useState<boolean>(false);
useEffect(() => {
if (listQuestions[quizId][totalIndex].deleteTimeoutId) {
clearTimeout(listQuestions[quizId][totalIndex].deleteTimeoutId);
}
}, [listQuestions]);
const openedModal = () => { const openedModal = () => {
resetSomeField({ openedModalSettings: "open" }); resetSomeField({ openedModalSettings: "open" });
console.log(openedModalSettings); console.log(openedModalSettings);
@ -50,6 +58,7 @@ export default function ButtonsOptions({
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 isWrappMiniButtonSetting = useMediaQuery(theme.breakpoints.down(920)); const isWrappMiniButtonSetting = useMediaQuery(theme.breakpoints.down(920));
const buttonSetting: { const buttonSetting: {
icon: JSX.Element; icon: JSX.Element;
title: string; title: string;
@ -241,7 +250,23 @@ export default function ButtonsOptions({
</IconButton> </IconButton>
<IconButton <IconButton
sx={{ borderRadius: "6px", padding: "2px" }} sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => removeQuestion(quizId, totalIndex)} onClick={() => {
const removedId = listQuestions[quizId][totalIndex].id;
if (listQuestions[quizId][totalIndex].deleteTimeoutId) {
clearTimeout(listQuestions[quizId][totalIndex].deleteTimeoutId);
}
removeQuestion(quizId, totalIndex);
const newTimeoutId = window.setTimeout(() => {
removeQuestionForce(quizId, removedId);
}, 5000);
updateQuestionsList(quizId, totalIndex, {
...listQuestions[quizId][totalIndex],
deleteTimeoutId: newTimeoutId,
});
}}
> >
<DeleteIcon color={"#4D4D4D"} /> <DeleteIcon color={"#4D4D4D"} />
</IconButton> </IconButton>

@ -1,4 +1,4 @@
import { useState } from "react"; import { useState, useEffect } from "react";
import MiniButtonSetting from "@ui_kit/MiniButtonSetting"; import MiniButtonSetting from "@ui_kit/MiniButtonSetting";
import SettingIcon from "../../assets/icons/questionsPage/settingIcon"; import SettingIcon from "../../assets/icons/questionsPage/settingIcon";
import Clue from "../../assets/icons/questionsPage/clue"; import Clue from "../../assets/icons/questionsPage/clue";
@ -21,13 +21,14 @@ import {
copyQuestion, copyQuestion,
removeQuestion, removeQuestion,
resetSomeField, resetSomeField,
removeQuestionForce,
updateQuestionsList,
} from "@root/questions"; } from "@root/questions";
import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight"; import { DoubleArrowRight } from "@icons/questionsPage/DoubleArrowRight";
import { DoubleTick } from "@icons/questionsPage/DoubleTick"; import { DoubleTick } from "@icons/questionsPage/DoubleTick";
import { VectorQuestions } from "@icons/questionsPage/VectorQuestions"; import { VectorQuestions } from "@icons/questionsPage/VectorQuestions";
import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal"; import { ReallyChangingModal } from "@ui_kit/Modal/ReallyChangingModal/ReallyChangingModal";
import "./ButtonsOptionsAndPict.css"; import "./ButtonsOptionsAndPict.css";
interface Props { interface Props {
@ -43,12 +44,19 @@ export default function ButtonsOptionsAndPict({
}: Props) { }: Props) {
const [buttonHover, setButtonHover] = useState<string>(""); const [buttonHover, setButtonHover] = useState<string>("");
const quizId = Number(useParams().quizId); const quizId = Number(useParams().quizId);
const { openedModalSettings } = questionStore(); const { listQuestions } = questionStore();
const [openedReallyChangingModal, setOpenedReallyChangingModal] = useState<boolean>(false); const [openedReallyChangingModal, setOpenedReallyChangingModal] =
useState<boolean>(false);
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790)); const isMobile = useMediaQuery(theme.breakpoints.down(790));
const isIconMobile = useMediaQuery(theme.breakpoints.down(1050)); const isIconMobile = useMediaQuery(theme.breakpoints.down(1050));
useEffect(() => {
if (listQuestions[quizId][totalIndex].deleteTimeoutId) {
clearTimeout(listQuestions[quizId][totalIndex].deleteTimeoutId);
}
}, [listQuestions]);
const openedModal = () => { const openedModal = () => {
resetSomeField({ openedModalSettings: "open" }); resetSomeField({ openedModalSettings: "open" });
}; };
@ -280,13 +288,32 @@ export default function ButtonsOptionsAndPict({
</IconButton> </IconButton>
<IconButton <IconButton
sx={{ borderRadius: "6px", padding: "2px" }} sx={{ borderRadius: "6px", padding: "2px" }}
onClick={() => removeQuestion(quizId, totalIndex)} onClick={() => {
const removedId = listQuestions[quizId][totalIndex].id;
if (listQuestions[quizId][totalIndex].deleteTimeoutId) {
clearTimeout(listQuestions[quizId][totalIndex].deleteTimeoutId);
}
removeQuestion(quizId, totalIndex);
const newTimeoutId = window.setTimeout(() => {
removeQuestionForce(quizId, removedId);
}, 5000);
updateQuestionsList(quizId, totalIndex, {
...listQuestions[quizId][totalIndex],
deleteTimeoutId: newTimeoutId,
});
}}
> >
<DeleteIcon color={"#4D4D4D"} /> <DeleteIcon color={"#4D4D4D"} />
</IconButton> </IconButton>
</Box> </Box>
<ReallyChangingModal opened={openedReallyChangingModal} onClose={() => setOpenedReallyChangingModal(false)} /> <ReallyChangingModal
opened={openedReallyChangingModal}
onClose={() => setOpenedReallyChangingModal(false)}
/>
</Box> </Box>
); );
} }

@ -1,8 +1,11 @@
import { useParams } from "react-router-dom";
import { Draggable } from "react-beautiful-dnd"; import { Draggable } from "react-beautiful-dnd";
import { Box, ListItem } from "@mui/material"; import { Box, ListItem, Typography, useTheme } from "@mui/material";
import QuestionsPageCard from "./QuestionPageCard"; import QuestionsPageCard from "./QuestionPageCard";
import { questionStore, updateQuestionsList } from "@root/questions";
type DraggableListItemProps = { type DraggableListItemProps = {
index: number; index: number;
isDragging: boolean; isDragging: boolean;
@ -11,23 +14,69 @@ type DraggableListItemProps = {
export const DraggableListItem = ({ export const DraggableListItem = ({
index, index,
isDragging, isDragging,
}: DraggableListItemProps) => ( }: DraggableListItemProps) => {
<Draggable draggableId={String(index)} index={index}> const quizId = Number(useParams().quizId);
{(provided) => ( const { listQuestions } = questionStore();
<ListItem const theme = useTheme();
ref={provided.innerRef}
{...provided.draggableProps} return (
sx={{ userSelect: "none", padding: 0 }} <Draggable draggableId={String(index)} index={index}>
> {(provided) => (
<Box sx={{ width: "100%", position: "relative" }}> <ListItem
<QuestionsPageCard ref={provided.innerRef}
key={index} {...provided.draggableProps}
totalIndex={index} sx={{ userSelect: "none", padding: 0 }}
draggableProps={provided.dragHandleProps} >
isDragging={isDragging} {listQuestions[quizId][index].deleted ? (
/> <Box
</Box> {...provided.dragHandleProps}
</ListItem> sx={{
)} width: "100%",
</Draggable> maxWidth: "800px",
); display: "flex",
justifyContent: "center",
marginBottom: "40px",
gap: "5px",
}}
>
<Typography
sx={{
fontSize: "16px",
color: theme.palette.grey2.main,
}}
>
Вопрос удалён.
</Typography>
<Typography
onClick={() => {
updateQuestionsList(quizId, index, {
...listQuestions[quizId][index],
deleted: false,
});
}}
sx={{
cursor: "pointer",
fontSize: "16px",
textDecoration: "underline",
color: theme.palette.brightPurple.main,
textDecorationColor: theme.palette.brightPurple.main,
}}
>
Восстановить?
</Typography>
</Box>
) : (
<Box sx={{ width: "100%", position: "relative" }}>
<QuestionsPageCard
key={index}
totalIndex={index}
draggableProps={provided.dragHandleProps}
isDragging={isDragging}
/>
</Box>
)}
</ListItem>
)}
</Draggable>
);
};

@ -1,4 +1,4 @@
import { useState, useRef } from "react"; import { useState, useRef, useEffect } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { import {
Box, Box,
@ -24,6 +24,7 @@ import {
createQuestion, createQuestion,
copyQuestion, copyQuestion,
removeQuestion, removeQuestion,
removeQuestionForce,
} from "@root/questions"; } from "@root/questions";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
@ -157,6 +158,12 @@ export default function QuestionsPageCard({
updateQuestionsList(quizId, totalIndex, { title }); updateQuestionsList(quizId, totalIndex, { title });
}, 1000); }, 1000);
useEffect(() => {
if (listQuestions[quizId][totalIndex].deleteTimeoutId) {
clearTimeout(listQuestions[quizId][totalIndex].deleteTimeoutId);
}
}, [listQuestions]);
return ( return (
<> <>
<Paper <Paper
@ -288,7 +295,25 @@ export default function QuestionsPageCard({
borderRadius: "6px", borderRadius: "6px",
padding: "2px", padding: "2px",
}} }}
onClick={() => removeQuestion(quizId, totalIndex)} onClick={() => {
const removedId = listQuestions[quizId][totalIndex].id;
if (listQuestions[quizId][totalIndex].deleteTimeoutId) {
clearTimeout(
listQuestions[quizId][totalIndex].deleteTimeoutId
);
}
removeQuestion(quizId, totalIndex);
const newTimeoutId = window.setTimeout(() => {
removeQuestionForce(quizId, removedId);
}, 5000);
updateQuestionsList(quizId, totalIndex, {
...listQuestions[quizId][totalIndex],
deleteTimeoutId: newTimeoutId,
});
}}
> >
<DeleteIcon color={"white"} /> <DeleteIcon color={"white"} />
</IconButton> </IconButton>

@ -1,4 +1,3 @@
import { useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import { DragDropContext, Droppable } from "react-beautiful-dnd"; import { DragDropContext, Droppable } from "react-beautiful-dnd";

@ -29,7 +29,8 @@ export interface Question {
description: string; description: string;
type: string; type: string;
required: boolean; required: boolean;
deleted: true; deleted: boolean;
deleteTimeoutId: number;
page: number; page: number;
content: { content: {
variants: Variants[]; variants: Variants[];
@ -84,7 +85,8 @@ export const DEFAULT_QUESTION: Omit<Question, "id"> = {
description: "", description: "",
type: "", type: "",
required: true, required: true,
deleted: true, deleted: false,
deleteTimeoutId: 0,
page: 0, page: 0,
content: { content: {
largeCheck: false, largeCheck: false,
@ -147,15 +149,35 @@ export const DEFAULT_QUESTION: Omit<Question, "id"> = {
expanded: false, expanded: false,
}; };
let isFirstPartialize = true;
export const questionStore = create<QuestionStore>()( export const questionStore = create<QuestionStore>()(
persist<QuestionStore>( persist<QuestionStore>(
() => ({ () => ({
listQuestions: {}, listQuestions: {},
openedModalSettings: "", openedModalSettings: "",
}), }),
{ {
name: "question", name: "question",
partialize: (state: QuestionStore) => {
if (isFirstPartialize) {
isFirstPartialize = false;
Object.keys(state.listQuestions).forEach((quizId) => {
[...state.listQuestions[quizId]].forEach(({ id, deleted }) => {
if (deleted) {
const removedItemIndex = state.listQuestions[quizId].findIndex(
(item) => item.id === id
);
state.listQuestions[quizId].splice(removedItemIndex, 1);
}
});
});
}
return state;
},
} }
) )
); );
@ -222,11 +244,18 @@ export const copyQuestion = (quizId: number, copiedQuestionIndex: number) => {
questionStore.setState({ listQuestions }); questionStore.setState({ listQuestions });
}; };
export const removeQuestionForce = (quizId: number, removedId: number) => {
const questionListClone = { ...questionStore.getState()["listQuestions"] };
const removedItemIndex = questionListClone[quizId].findIndex(
({ id }) => id === removedId
);
questionListClone[quizId].splice(removedItemIndex, 1);
questionStore.setState({ listQuestions: questionListClone });
};
export const removeQuestion = (quizId: number, index: number) => { export const removeQuestion = (quizId: number, index: number) => {
const questionListClone = { ...questionStore.getState()["listQuestions"] }; const questionListClone = { ...questionStore.getState()["listQuestions"] };
questionListClone[quizId][index].deleted = true;
questionListClone[quizId].splice(index, 1);
questionStore.setState({ listQuestions: questionListClone }); questionStore.setState({ listQuestions: questionListClone });
}; };