2023-11-02 16:45:28 +00:00
|
|
|
|
import { questionApi } from "@api/question";
|
|
|
|
|
import { devlog } from "@frontend/kitui";
|
2023-11-27 23:07:24 +00:00
|
|
|
|
import { questionToEditQuestionRequest } from "@model/question/edit";
|
2023-12-01 14:33:55 +00:00
|
|
|
|
import {
|
|
|
|
|
QuestionType,
|
|
|
|
|
RawQuestion,
|
|
|
|
|
rawQuestionToQuestion,
|
|
|
|
|
} from "@model/question/question";
|
|
|
|
|
import {
|
|
|
|
|
AnyTypedQuizQuestion,
|
|
|
|
|
QuestionVariant,
|
|
|
|
|
UntypedQuizQuestion,
|
|
|
|
|
createQuestionVariant,
|
|
|
|
|
} from "@model/questionTypes/shared";
|
2023-11-29 13:49:52 +00:00
|
|
|
|
import { defaultQuestionByType } from "../../constants/default";
|
2023-11-02 16:45:28 +00:00
|
|
|
|
import { produce } from "immer";
|
2023-11-28 19:16:00 +00:00
|
|
|
|
import { nanoid } from "nanoid";
|
2023-11-02 16:45:28 +00:00
|
|
|
|
import { enqueueSnackbar } from "notistack";
|
2023-11-14 16:44:27 +00:00
|
|
|
|
import { isAxiosCanceledError } from "../../utils/isAxiosCanceledError";
|
2023-11-23 19:07:57 +00:00
|
|
|
|
import { RequestQueue } from "../../utils/requestQueue";
|
2023-11-27 23:07:24 +00:00
|
|
|
|
import { QuestionsStore, useQuestionsStore } from "./store";
|
2023-12-01 14:33:55 +00:00
|
|
|
|
import { QUESTIONS_DUMMY } from "../../constants/questions.dummy";
|
|
|
|
|
|
|
|
|
|
export const setDefaultState = (quizId: number) =>
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
QUESTIONS_DUMMY.forEach((question) => {
|
|
|
|
|
state.questions.push(question);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "setDefaultState",
|
|
|
|
|
quizId,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export const setQuestions = (questions: RawQuestion[] | null) =>
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const untypedQuestions = state.questions.filter((q) => q.type === null);
|
|
|
|
|
|
|
|
|
|
state.questions = questions?.map(rawQuestionToQuestion) ?? [];
|
|
|
|
|
state.questions.push(...untypedQuestions);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "setQuestions",
|
|
|
|
|
questions,
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-02 16:45:28 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const createUntypedQuestion = (quizId: number) =>
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
state.questions.push({
|
2023-11-29 13:49:52 +00:00
|
|
|
|
id: nanoid(),
|
|
|
|
|
quizId,
|
|
|
|
|
type: null,
|
|
|
|
|
title: "",
|
|
|
|
|
description: "",
|
|
|
|
|
deleted: false,
|
|
|
|
|
expanded: true,
|
2023-12-01 14:33:55 +00:00
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "createUntypedQuestion",
|
|
|
|
|
quizId,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const removeQuestion = (questionId: string) =>
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const index = state.questions.findIndex((q) => q.id === questionId);
|
|
|
|
|
if (index === -1) return;
|
|
|
|
|
|
|
|
|
|
state.questions.splice(index, 1);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "removeQuestion",
|
|
|
|
|
questionId,
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-15 18:38:02 +00:00
|
|
|
|
|
2023-11-29 13:49:52 +00:00
|
|
|
|
export const updateUntypedQuestion = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
updateFn: (question: UntypedQuizQuestion) => void
|
2023-11-29 13:49:52 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const question = state.questions.find((q) => q.id === questionId);
|
|
|
|
|
if (!question) return;
|
|
|
|
|
if (question.type !== null)
|
|
|
|
|
throw new Error(
|
|
|
|
|
"Cannot update typed question, use 'updateQuestion' instead"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
updateFn(question);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "updateUntypedQuestion",
|
|
|
|
|
questionId,
|
|
|
|
|
updateFn: updateFn.toString(),
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-29 13:49:52 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const cleanQuestions = () =>
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
state.questions = [];
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "cleanQuestions",
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const setQuestionBackendId = (questionId: string, backendId: number) =>
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const question = state.questions.find((q) => q.id === questionId);
|
|
|
|
|
if (!question) return;
|
|
|
|
|
if (question.type === null)
|
|
|
|
|
throw new Error("Cannot set backend id for untyped question");
|
|
|
|
|
|
|
|
|
|
question.backendId = backendId;
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "setQuestionBackendId",
|
|
|
|
|
questionId: questionId,
|
|
|
|
|
backendId,
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-02 16:45:28 +00:00
|
|
|
|
|
2023-11-16 16:41:25 +00:00
|
|
|
|
export const reorderQuestions = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
sourceIndex: number,
|
|
|
|
|
destinationIndex: number
|
2023-11-16 16:41:25 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (sourceIndex === destinationIndex) return;
|
|
|
|
|
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const [removed] = state.questions.splice(sourceIndex, 1);
|
|
|
|
|
state.questions.splice(destinationIndex, 0, removed);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "reorderQuestions",
|
|
|
|
|
sourceIndex,
|
|
|
|
|
destinationIndex,
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-16 16:41:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const toggleExpandQuestion = (questionId: string) =>
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const question = state.questions.find((q) => q.id === questionId);
|
|
|
|
|
if (!question) return;
|
|
|
|
|
|
|
|
|
|
question.expanded = !question.expanded;
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "toggleExpandQuestion",
|
|
|
|
|
questionId,
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-29 13:49:52 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const collapseAllQuestions = () =>
|
|
|
|
|
setProducedState((state) => {
|
|
|
|
|
state.questions.forEach((question) => (question.expanded = false));
|
|
|
|
|
}, "collapseAllQuestions");
|
2023-11-29 13:49:52 +00:00
|
|
|
|
|
|
|
|
|
const REQUEST_DEBOUNCE = 200;
|
|
|
|
|
const requestQueue = new RequestQueue();
|
|
|
|
|
let requestTimeoutId: ReturnType<typeof setTimeout>;
|
|
|
|
|
|
|
|
|
|
export const updateQuestion = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
updateFn: (question: AnyTypedQuizQuestion) => void
|
2023-11-29 13:49:52 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const question = state.questions.find((q) => q.id === questionId);
|
|
|
|
|
if (!question) return;
|
|
|
|
|
if (question.type === null)
|
|
|
|
|
throw new Error(
|
|
|
|
|
"Cannot update untyped question, use 'updateUntypedQuestion' instead"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
updateFn(question);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "updateQuestion",
|
|
|
|
|
questionId,
|
|
|
|
|
updateFn: updateFn.toString(),
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
clearTimeout(requestTimeoutId);
|
|
|
|
|
requestTimeoutId = setTimeout(() => {
|
|
|
|
|
requestQueue
|
|
|
|
|
.enqueue(async () => {
|
|
|
|
|
const q = useQuestionsStore
|
|
|
|
|
.getState()
|
|
|
|
|
.questions.find((q) => q.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)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setQuestionBackendId(questionId, response.updated);
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
if (isAxiosCanceledError(error)) return;
|
|
|
|
|
|
|
|
|
|
devlog("Error editing question", { error, questionId });
|
|
|
|
|
enqueueSnackbar("Не удалось сохранить вопрос");
|
|
|
|
|
});
|
|
|
|
|
}, REQUEST_DEBOUNCE);
|
2023-11-29 13:49:52 +00:00
|
|
|
|
};
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-11-27 23:07:24 +00:00
|
|
|
|
export const addQuestionVariant = (questionId: string) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
switch (question.type) {
|
|
|
|
|
case "variant":
|
|
|
|
|
case "emoji":
|
|
|
|
|
case "select":
|
|
|
|
|
case "images":
|
|
|
|
|
case "varimg":
|
|
|
|
|
question.content.variants.push(createQuestionVariant());
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw new Error(
|
|
|
|
|
`Cannot add variant to question of type "${question.type}"`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-11-15 18:38:02 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const deleteQuestionVariant = (
|
|
|
|
|
questionId: string,
|
|
|
|
|
variantId: string
|
|
|
|
|
) => {
|
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (!("variants" in question.content)) return;
|
2023-11-15 18:38:02 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
const variantIndex = question.content.variants.findIndex(
|
|
|
|
|
(variant) => variant.id === variantId
|
|
|
|
|
);
|
|
|
|
|
if (variantIndex === -1) return;
|
2023-11-15 18:38:02 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
question.content.variants.splice(variantIndex, 1);
|
|
|
|
|
});
|
2023-11-15 18:38:02 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const setQuestionVariantField = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
variantId: string,
|
|
|
|
|
field: keyof QuestionVariant,
|
|
|
|
|
value: QuestionVariant[keyof QuestionVariant]
|
2023-11-15 18:38:02 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (!("variants" in question.content)) return;
|
|
|
|
|
|
|
|
|
|
const variantIndex = question.content.variants.findIndex(
|
|
|
|
|
(variant) => variant.id === variantId
|
|
|
|
|
);
|
|
|
|
|
if (variantIndex === -1) return;
|
|
|
|
|
|
|
|
|
|
const variant = question.content.variants[variantIndex];
|
|
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
|
variant[field] = value;
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-11-15 18:38:02 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const reorderQuestionVariants = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
sourceIndex: number,
|
|
|
|
|
destinationIndex: number
|
2023-11-15 18:38:02 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (sourceIndex === destinationIndex) return;
|
2023-11-15 18:38:02 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (!("variants" in question.content)) return;
|
2023-11-15 18:38:02 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
const [removed] = question.content.variants.splice(sourceIndex, 1);
|
|
|
|
|
question.content.variants.splice(destinationIndex, 0, removed);
|
|
|
|
|
});
|
2023-11-15 18:38:02 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const setQuestionBackgroundImage = (questionId: string, url: string) => {
|
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (question.content.back === url) return;
|
|
|
|
|
|
|
|
|
|
if (question.content.back !== question.content.originalBack)
|
|
|
|
|
URL.revokeObjectURL(question.content.back);
|
|
|
|
|
question.content.back = url;
|
|
|
|
|
});
|
2023-11-15 18:38:02 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const setQuestionOriginalBackgroundImage = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
url: string
|
2023-11-15 18:38:02 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (question.content.originalBack === url) return;
|
2023-11-15 18:38:02 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
URL.revokeObjectURL(question.content.originalBack);
|
|
|
|
|
question.content.originalBack = url;
|
|
|
|
|
});
|
2023-11-15 18:38:02 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-11-16 16:41:25 +00:00
|
|
|
|
export const setVariantImageUrl = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
variantId: string,
|
|
|
|
|
url: string
|
2023-11-16 16:41:25 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (!("variants" in question.content)) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
const variant = question.content.variants.find(
|
|
|
|
|
(variant) => variant.id === variantId
|
|
|
|
|
);
|
|
|
|
|
if (!variant) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (variant.extendedText === url) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (variant.extendedText !== variant.originalImageUrl)
|
|
|
|
|
URL.revokeObjectURL(variant.extendedText);
|
|
|
|
|
variant.extendedText = url;
|
|
|
|
|
});
|
2023-11-16 16:41:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const setVariantOriginalImageUrl = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
variantId: string,
|
|
|
|
|
url: string
|
2023-11-16 16:41:25 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (!("variants" in question.content)) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
const variant = question.content.variants.find(
|
|
|
|
|
(variant) => variant.id === variantId
|
|
|
|
|
) as QuestionVariant | undefined;
|
|
|
|
|
if (!variant) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (variant.originalImageUrl === url) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (variant.originalImageUrl) {
|
|
|
|
|
URL.revokeObjectURL(variant.originalImageUrl);
|
|
|
|
|
}
|
|
|
|
|
variant.originalImageUrl = url;
|
|
|
|
|
});
|
2023-11-16 16:41:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const setPageQuestionPicture = (questionId: string, url: string) => {
|
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (question.type !== "page") return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (question.content.picture === url) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (question.content.picture !== question.content.originalPicture)
|
|
|
|
|
URL.revokeObjectURL(question.content.picture);
|
|
|
|
|
question.content.picture = url;
|
|
|
|
|
});
|
2023-11-16 16:41:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const setPageQuestionOriginalPicture = (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
url: string
|
2023-11-16 16:41:25 +00:00
|
|
|
|
) => {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
if (question.type !== "page") return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (question.content.originalPicture === url) return;
|
2023-11-16 16:41:25 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
URL.revokeObjectURL(question.content.originalPicture);
|
|
|
|
|
question.content.originalPicture = url;
|
|
|
|
|
});
|
2023-11-16 16:41:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const setQuestionInnerName = (questionId: string, name: string) => {
|
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
question.content.innerName = name;
|
|
|
|
|
});
|
2023-11-16 16:41:25 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const changeQuestionType = (questionId: string, type: QuestionType) => {
|
|
|
|
|
updateQuestion(questionId, (question) => {
|
|
|
|
|
question.type = type;
|
|
|
|
|
question.content = defaultQuestionByType[type].content;
|
|
|
|
|
});
|
2023-11-02 16:45:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-11-29 13:49:52 +00:00
|
|
|
|
export const createTypedQuestion = async (
|
2023-12-01 14:33:55 +00:00
|
|
|
|
questionId: string,
|
|
|
|
|
type: QuestionType
|
|
|
|
|
) =>
|
|
|
|
|
requestQueue.enqueue(async () => {
|
|
|
|
|
const question = useQuestionsStore
|
|
|
|
|
.getState()
|
|
|
|
|
.questions.find((q) => q.id === questionId);
|
2023-11-29 13:49:52 +00:00
|
|
|
|
if (!question) return;
|
2023-12-01 14:33:55 +00:00
|
|
|
|
if (question.type !== null)
|
|
|
|
|
throw new Error("Cannot upgrade already typed question");
|
2023-11-29 13:49:52 +00:00
|
|
|
|
|
2023-11-02 16:45:28 +00:00
|
|
|
|
try {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
const createdQuestion = await questionApi.create({
|
|
|
|
|
quiz_id: question.quizId,
|
|
|
|
|
type,
|
|
|
|
|
title: question.title,
|
|
|
|
|
description: question.description,
|
|
|
|
|
page: 0,
|
|
|
|
|
required: true,
|
|
|
|
|
content: JSON.stringify(defaultQuestionByType[type].content),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
const questionIndex = state.questions.findIndex(
|
|
|
|
|
(q) => q.id === questionId
|
|
|
|
|
);
|
|
|
|
|
if (questionIndex !== -1)
|
|
|
|
|
state.questions.splice(
|
|
|
|
|
questionIndex,
|
|
|
|
|
1,
|
|
|
|
|
rawQuestionToQuestion(createdQuestion)
|
2023-11-29 13:49:52 +00:00
|
|
|
|
);
|
2023-12-01 14:33:55 +00:00
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "createTypedQuestion",
|
|
|
|
|
question,
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-02 16:45:28 +00:00
|
|
|
|
} catch (error) {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
devlog("Error creating question", error);
|
|
|
|
|
enqueueSnackbar("Не удалось создать вопрос");
|
2023-11-02 16:45:28 +00:00
|
|
|
|
}
|
2023-12-01 14:33:55 +00:00
|
|
|
|
});
|
2023-11-27 23:07:24 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const deleteQuestion = async (questionId: string) =>
|
|
|
|
|
requestQueue.enqueue(async () => {
|
|
|
|
|
const question = useQuestionsStore
|
|
|
|
|
.getState()
|
|
|
|
|
.questions.find((q) => q.id === questionId);
|
2023-11-27 23:07:24 +00:00
|
|
|
|
if (!question) return;
|
2023-11-02 16:45:28 +00:00
|
|
|
|
|
2023-11-29 13:49:52 +00:00
|
|
|
|
if (question.type === null) {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
removeQuestion(questionId);
|
|
|
|
|
return;
|
2023-11-29 13:49:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-02 16:45:28 +00:00
|
|
|
|
try {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
await questionApi.delete(question.backendId);
|
2023-11-02 16:45:28 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
removeQuestion(questionId);
|
2023-11-02 16:45:28 +00:00
|
|
|
|
} catch (error) {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
devlog("Error deleting question", error);
|
|
|
|
|
enqueueSnackbar("Не удалось удалить вопрос");
|
2023-11-02 16:45:28 +00:00
|
|
|
|
}
|
2023-12-01 14:33:55 +00:00
|
|
|
|
});
|
2023-11-27 23:07:24 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
export const copyQuestion = async (questionId: string, quizId: number) =>
|
|
|
|
|
requestQueue.enqueue(async () => {
|
|
|
|
|
const question = useQuestionsStore
|
|
|
|
|
.getState()
|
|
|
|
|
.questions.find((q) => q.id === questionId);
|
2023-11-27 23:07:24 +00:00
|
|
|
|
if (!question) return;
|
2023-11-02 16:45:28 +00:00
|
|
|
|
|
2023-11-29 13:49:52 +00:00
|
|
|
|
if (question.type === null) {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
const copiedQuestion = structuredClone(question);
|
|
|
|
|
copiedQuestion.id = nanoid();
|
|
|
|
|
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
state.questions.push(copiedQuestion);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "copyQuestion",
|
|
|
|
|
questionId,
|
|
|
|
|
quizId,
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return;
|
2023-11-29 13:49:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-15 18:38:02 +00:00
|
|
|
|
try {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
const { updated: newQuestionId } = await questionApi.copy(
|
|
|
|
|
question.backendId,
|
|
|
|
|
quizId
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const copiedQuestion = structuredClone(question);
|
|
|
|
|
copiedQuestion.backendId = newQuestionId;
|
|
|
|
|
copiedQuestion.id = nanoid();
|
|
|
|
|
|
|
|
|
|
setProducedState(
|
|
|
|
|
(state) => {
|
|
|
|
|
state.questions.push(copiedQuestion);
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
type: "copyQuestion",
|
|
|
|
|
questionId,
|
|
|
|
|
quizId,
|
|
|
|
|
}
|
|
|
|
|
);
|
2023-11-15 18:38:02 +00:00
|
|
|
|
} catch (error) {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
devlog("Error copying question", error);
|
|
|
|
|
enqueueSnackbar("Не удалось скопировать вопрос");
|
2023-11-15 18:38:02 +00:00
|
|
|
|
}
|
2023-12-01 14:33:55 +00:00
|
|
|
|
});
|
2023-11-02 16:45:28 +00:00
|
|
|
|
|
2023-12-01 14:33:55 +00:00
|
|
|
|
function setProducedState<A extends string | { type: unknown }>(
|
|
|
|
|
recipe: (state: QuestionsStore) => void,
|
|
|
|
|
action?: A
|
2023-11-02 16:45:28 +00:00
|
|
|
|
) {
|
2023-12-01 14:33:55 +00:00
|
|
|
|
useQuestionsStore.setState((state) => produce(state, recipe), false, action);
|
2023-11-02 16:45:28 +00:00
|
|
|
|
}
|