save order of questions
This commit is contained in:
parent
a5e76a20ea
commit
6fb6b7dae3
@ -39,7 +39,7 @@ import SwitchQuestionsPage from "../SwitchQuestionsPage";
|
||||
import { ChooseAnswerModal } from "./ChooseAnswerModal";
|
||||
import TypeQuestions from "../TypeQuestions";
|
||||
import { QuestionType } from "@model/question/question";
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks"
|
||||
import { useCurrentQuiz } from "@root/quizes/hooks";
|
||||
|
||||
interface Props {
|
||||
question: AnyTypedQuizQuestion | UntypedQuizQuestion;
|
||||
@ -98,7 +98,7 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
||||
<TextField
|
||||
defaultValue={question.title}
|
||||
placeholder={"Заголовок вопроса"}
|
||||
onChange={({ target }: { target: HTMLInputElement }) => setTitle(target.value)}
|
||||
onChange={({ target }: { target: HTMLInputElement; }) => setTitle(target.value)}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<Box>
|
||||
@ -238,7 +238,7 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
||||
margin: "0 5px 0 10px",
|
||||
}}
|
||||
onClick={() => { // TODO
|
||||
const removedId = question.id;
|
||||
const removedId = question.id;
|
||||
// if (question.deleteTimeoutId) {
|
||||
// clearTimeout(question.deleteTimeoutId);
|
||||
// }
|
||||
@ -264,26 +264,28 @@ export default function QuestionsPageCard({ question, draggableProps, isDragging
|
||||
</IconButton>
|
||||
</Box>
|
||||
)}
|
||||
<Box
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: "30px",
|
||||
width: "30px",
|
||||
marginLeft: "3px",
|
||||
borderRadius: "50%",
|
||||
fontSize: "16px",
|
||||
color: question.expanded
|
||||
? theme.palette.brightPurple.main
|
||||
: "#FFF",
|
||||
background: question.expanded
|
||||
? "#EEE4FC"
|
||||
: theme.palette.brightPurple.main,
|
||||
}}
|
||||
>
|
||||
{index + 1}
|
||||
</Box>
|
||||
{question.type !== null &&
|
||||
<Box
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: "30px",
|
||||
width: "30px",
|
||||
marginLeft: "3px",
|
||||
borderRadius: "50%",
|
||||
fontSize: "16px",
|
||||
color: question.expanded
|
||||
? theme.palette.brightPurple.main
|
||||
: "#FFF",
|
||||
background: question.expanded
|
||||
? "#EEE4FC"
|
||||
: theme.palette.brightPurple.main,
|
||||
}}
|
||||
>
|
||||
{question.page + 1}
|
||||
</Box>
|
||||
}
|
||||
<IconButton
|
||||
disableRipple
|
||||
sx={{
|
||||
|
@ -4,14 +4,13 @@ import { devlog } from "@frontend/kitui";
|
||||
import { questionToEditQuestionRequest } from "@model/question/edit";
|
||||
import { QuestionType, RawQuestion, rawQuestionToQuestion } from "@model/question/question";
|
||||
import { AnyTypedQuizQuestion, QuestionVariant, UntypedQuizQuestion, createQuestionVariant } from "@model/questionTypes/shared";
|
||||
import { defaultQuestionByType } from "../../constants/default";
|
||||
import { updateRootContentId } from "@root/quizes/actions";
|
||||
import { produce } from "immer";
|
||||
import { nanoid } from "nanoid";
|
||||
import { enqueueSnackbar } from "notistack";
|
||||
import { defaultQuestionByType } from "../../constants/default";
|
||||
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";
|
||||
|
||||
|
||||
@ -85,6 +84,18 @@ const setQuestionBackendId = (questionId: string, backendId: number) => setProdu
|
||||
backendId,
|
||||
});
|
||||
|
||||
const updateQuestionOrders = () => {
|
||||
const questions = useQuestionsStore.getState().questions.filter(
|
||||
(question): question is AnyTypedQuizQuestion => question.type !== null
|
||||
);
|
||||
|
||||
questions.forEach((question, index) => {
|
||||
updateQuestion(question.id, question => {
|
||||
question.page = index;
|
||||
}, true);
|
||||
});
|
||||
};
|
||||
|
||||
export const reorderQuestions = (
|
||||
sourceIndex: number,
|
||||
destinationIndex: number,
|
||||
@ -99,6 +110,8 @@ export const reorderQuestions = (
|
||||
sourceIndex,
|
||||
destinationIndex,
|
||||
});
|
||||
|
||||
updateQuestionOrders();
|
||||
};
|
||||
|
||||
export const toggleExpandQuestion = (questionId: string) => setProducedState(state => {
|
||||
@ -123,6 +136,7 @@ let requestTimeoutId: ReturnType<typeof setTimeout>;
|
||||
export const updateQuestion = (
|
||||
questionId: string,
|
||||
updateFn: (question: AnyTypedQuizQuestion) => void,
|
||||
skipQueue = false,
|
||||
) => {
|
||||
setProducedState(state => {
|
||||
const question = state.questions.find(q => q.id === questionId) || state.questions.find(q => q.type !== null && q.content.id === questionId);
|
||||
@ -137,21 +151,31 @@ export const updateQuestion = (
|
||||
});
|
||||
|
||||
// clearTimeout(requestTimeoutId);
|
||||
// requestTimeoutId = setTimeout(() => {
|
||||
requestQueue.enqueue(async () => {
|
||||
|
||||
const request = async () => {
|
||||
const q = useQuestionsStore.getState().questions.find(q => q.id === questionId) || useQuestionsStore.getState().questions.find(q => q.type !== null && q.content.id === questionId);
|
||||
if (!q) return;
|
||||
if (q.type === null) throw new Error("Cannot send update request for untyped question");
|
||||
|
||||
const response = await questionApi.edit(questionToEditQuestionRequest(q));
|
||||
try {
|
||||
const response = await questionApi.edit(questionToEditQuestionRequest(q));
|
||||
|
||||
setQuestionBackendId(questionId, response.updated);
|
||||
}).catch(error => {
|
||||
if (isAxiosCanceledError(error)) return;
|
||||
setQuestionBackendId(questionId, response.updated);
|
||||
} catch (error) {
|
||||
if (isAxiosCanceledError(error)) return;
|
||||
|
||||
devlog("Error editing question", { error, questionId });
|
||||
enqueueSnackbar("Не удалось сохранить вопрос");
|
||||
});
|
||||
devlog("Error editing question", { error, questionId });
|
||||
enqueueSnackbar("Не удалось сохранить вопрос");
|
||||
}
|
||||
};
|
||||
|
||||
if (skipQueue) {
|
||||
request();
|
||||
return;
|
||||
}
|
||||
|
||||
// requestTimeoutId = setTimeout(() => {
|
||||
requestQueue.enqueue(request);
|
||||
// }, REQUEST_DEBOUNCE);
|
||||
};
|
||||
|
||||
@ -261,13 +285,13 @@ export const changeQuestionType = (
|
||||
type: QuestionType,
|
||||
) => {
|
||||
updateQuestion(questionId, question => {
|
||||
const oldId = question.content.id
|
||||
const oldRule = question.content.rule
|
||||
oldRule.main = []
|
||||
const oldId = question.content.id;
|
||||
const oldRule = question.content.rule;
|
||||
oldRule.main = [];
|
||||
question.type = type;
|
||||
question.content = defaultQuestionByType[type].content;
|
||||
question.content.id = oldId
|
||||
question.content.rule = oldRule
|
||||
question.content.id = oldId;
|
||||
question.content.rule = oldRule;
|
||||
});
|
||||
};
|
||||
|
||||
@ -275,7 +299,8 @@ export const createTypedQuestion = async (
|
||||
questionId: string,
|
||||
type: QuestionType,
|
||||
) => requestQueue.enqueue(async () => {
|
||||
const question = useQuestionsStore.getState().questions.find(q => q.id === questionId);
|
||||
const questions = useQuestionsStore.getState().questions;
|
||||
const question = questions.find(q => q.id === questionId);
|
||||
if (!question) return;
|
||||
if (question.type !== null) throw new Error("Cannot upgrade already typed question");
|
||||
|
||||
@ -285,7 +310,7 @@ export const createTypedQuestion = async (
|
||||
type,
|
||||
title: question.title,
|
||||
description: question.description,
|
||||
page: 0,
|
||||
page: questions.length,
|
||||
required: true,
|
||||
content: JSON.stringify(defaultQuestionByType[type].content),
|
||||
});
|
||||
@ -320,8 +345,8 @@ export const deleteQuestion = async (questionId: string, quizId: string) => requ
|
||||
try {
|
||||
await questionApi.delete(question.backendId);
|
||||
if (question.content.rule.parentId === "root") { //удалить из стора root и очистить rule всем вопросам
|
||||
updateRootContentId(quizId, "")
|
||||
clearRoleForAll()
|
||||
updateRootContentId(quizId, "");
|
||||
clearRoleForAll();
|
||||
}
|
||||
|
||||
removeQuestion(questionId);
|
||||
@ -338,8 +363,7 @@ export const copyQuestion = async (questionId: string, quizId: number) => reques
|
||||
const frontId = nanoid();
|
||||
if (question.type === null) {
|
||||
const copiedQuestion = structuredClone(question);
|
||||
copiedQuestion.id = frontId
|
||||
copiedQuestion.content.id = frontId
|
||||
copiedQuestion.id = frontId;
|
||||
|
||||
setProducedState(state => {
|
||||
state.questions.push(copiedQuestion);
|
||||
@ -357,9 +381,9 @@ export const copyQuestion = async (questionId: string, quizId: number) => reques
|
||||
|
||||
const copiedQuestion = structuredClone(question);
|
||||
copiedQuestion.backendId = newQuestionId;
|
||||
copiedQuestion.id = frontId
|
||||
copiedQuestion.content.id = frontId
|
||||
copiedQuestion.content.rule = { main: [], parentId: "", default: "" }
|
||||
copiedQuestion.id = frontId;
|
||||
copiedQuestion.content.id = frontId;
|
||||
copiedQuestion.content.rule = { main: [], parentId: "", default: "" };
|
||||
|
||||
setProducedState(state => {
|
||||
state.questions.push(copiedQuestion);
|
||||
@ -368,6 +392,8 @@ export const copyQuestion = async (questionId: string, quizId: number) => reques
|
||||
questionId,
|
||||
quizId,
|
||||
});
|
||||
|
||||
updateQuestionOrders();
|
||||
} catch (error) {
|
||||
devlog("Error copying question", error);
|
||||
enqueueSnackbar("Не удалось скопировать вопрос");
|
||||
@ -394,7 +420,7 @@ export const getQuestionByContentId = (questionContentId: string | null) => {
|
||||
if (questionContentId === null) return null;
|
||||
return useQuestionsStore.getState().questions.find(q => {
|
||||
if (q.type === null) return false;
|
||||
|
||||
|
||||
return (q.content.id === questionContentId);
|
||||
}) || null;
|
||||
};
|
||||
@ -402,19 +428,19 @@ export const getQuestionByContentId = (questionContentId: string | null) => {
|
||||
export const updateOpenedModalSettingsId = (id?: string) => useQuestionsStore.setState({ openedModalSettingsId: id ? id : null });
|
||||
export const updateDragQuestionContentId = (contentId?: string) => {
|
||||
useQuestionsStore.setState({ dragQuestionContentId: contentId ? contentId : null });
|
||||
}
|
||||
};
|
||||
|
||||
export const clearRoleForAll = () => {
|
||||
const { questions } = useQuestionsStore.getState()
|
||||
const { questions } = useQuestionsStore.getState();
|
||||
questions.forEach(question => {
|
||||
if (question.type !== null && (question.content.rule.main.length > 0 || question.content.rule.default.length > 0 || question.content.rule.parentId.length > 0)) {
|
||||
updateQuestion(question.content.id, question => {
|
||||
question.content.rule.parentId = ""
|
||||
question.content.rule.main = []
|
||||
question.content.rule.default = ""
|
||||
})
|
||||
question.content.rule.parentId = "";
|
||||
question.content.rule.main = [];
|
||||
question.content.rule.default = "";
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const updateOpenBranchingPanel = (value: boolean) => useQuestionsStore.setState({openBranchingPanel: !value});
|
||||
export const updateOpenBranchingPanel = (value: boolean) => useQuestionsStore.setState({ openBranchingPanel: !value });
|
||||
|
Loading…
Reference in New Issue
Block a user