2023-08-10 13:45:44 +00:00
|
|
|
import { create } from "zustand";
|
|
|
|
|
import { persist } from "zustand/middleware";
|
|
|
|
|
|
2023-10-02 19:43:07 +00:00
|
|
|
import { QuizQuestionEmoji } from "../model/questionTypes/emoji";
|
|
|
|
|
import { QuizQuestionImages } from "../model/questionTypes/images";
|
|
|
|
|
import { QuizQuestionVariant } from "../model/questionTypes/variant";
|
|
|
|
|
import { QuizQuestionVarImg } from "../model/questionTypes/varimg";
|
|
|
|
|
|
|
|
|
|
import type {
|
|
|
|
|
AnyQuizQuestion,
|
|
|
|
|
QuizQuestionType,
|
2023-10-03 14:03:57 +00:00
|
|
|
Variant,
|
2023-10-02 19:43:07 +00:00
|
|
|
} from "../model/questionTypes/shared";
|
|
|
|
|
|
2023-10-03 14:03:57 +00:00
|
|
|
import { QUIZ_QUESTION_BASE } from "../constants/base";
|
|
|
|
|
import { QUIZ_QUESTION_DATE } from "../constants/date";
|
|
|
|
|
import { QUIZ_QUESTION_EMOJI } from "../constants/emoji";
|
|
|
|
|
import { QUIZ_QUESTION_FILE } from "../constants/file";
|
|
|
|
|
import { QUIZ_QUESTION_IMAGES } from "../constants/images";
|
|
|
|
|
import { QUIZ_QUESTION_NUMBER } from "../constants/number";
|
|
|
|
|
import { QUIZ_QUESTION_PAGE } from "../constants/page";
|
|
|
|
|
import { QUIZ_QUESTION_RATING } from "../constants/rating";
|
|
|
|
|
import { QUIZ_QUESTION_SELECT } from "../constants/select";
|
|
|
|
|
import { QUIZ_QUESTION_TEXT } from "../constants/text";
|
|
|
|
|
import { QUIZ_QUESTION_VARIANT } from "../constants/variant";
|
|
|
|
|
import { QUIZ_QUESTION_VARIMG } from "../constants/varimg";
|
2023-07-20 22:02:20 +00:00
|
|
|
|
2023-08-24 11:09:47 +00:00
|
|
|
type Hint = {
|
|
|
|
|
text: string;
|
|
|
|
|
video: string;
|
|
|
|
|
};
|
|
|
|
|
|
2023-08-24 20:53:27 +00:00
|
|
|
type Rule = {
|
|
|
|
|
or: boolean;
|
|
|
|
|
show: boolean;
|
|
|
|
|
reqs: [
|
|
|
|
|
{
|
|
|
|
|
id: string;
|
|
|
|
|
vars: number[];
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-30 21:25:47 +00:00
|
|
|
export interface Question {
|
2023-07-27 17:30:55 +00:00
|
|
|
id: number;
|
2023-08-10 13:45:44 +00:00
|
|
|
title: string;
|
|
|
|
|
description: string;
|
|
|
|
|
type: string;
|
|
|
|
|
required: boolean;
|
2023-07-27 17:30:55 +00:00
|
|
|
deleted: true;
|
2023-08-10 13:45:44 +00:00
|
|
|
page: number;
|
2023-07-27 17:30:55 +00:00
|
|
|
content: {
|
2023-10-03 14:03:57 +00:00
|
|
|
variants: Variant[];
|
2023-08-24 11:09:47 +00:00
|
|
|
hint: Hint;
|
2023-08-24 20:53:27 +00:00
|
|
|
rule: Rule;
|
2023-08-28 08:20:09 +00:00
|
|
|
images: string[];
|
2023-09-05 08:25:47 +00:00
|
|
|
largeCheck: boolean;
|
|
|
|
|
large: string;
|
2023-07-27 17:30:55 +00:00
|
|
|
multi: boolean;
|
2023-08-24 09:09:43 +00:00
|
|
|
own: boolean;
|
2023-09-05 08:25:47 +00:00
|
|
|
innerNameCheck: boolean;
|
2023-08-24 09:09:43 +00:00
|
|
|
innerName: string;
|
2023-08-24 11:57:42 +00:00
|
|
|
back: string;
|
2023-08-25 08:29:42 +00:00
|
|
|
placeholder: string;
|
2023-08-25 09:14:53 +00:00
|
|
|
type: string;
|
2023-08-25 09:30:25 +00:00
|
|
|
autofill: boolean;
|
2023-08-25 10:27:43 +00:00
|
|
|
default: string;
|
2023-08-28 08:20:09 +00:00
|
|
|
single: boolean;
|
|
|
|
|
number: boolean;
|
2023-08-28 09:31:34 +00:00
|
|
|
xy: string;
|
|
|
|
|
format: "carousel" | "masonry";
|
2023-09-05 13:54:41 +00:00
|
|
|
text: string;
|
|
|
|
|
picture: string;
|
|
|
|
|
video: string;
|
2023-09-06 08:01:44 +00:00
|
|
|
dateRange: boolean;
|
2023-09-05 16:34:52 +00:00
|
|
|
time: boolean;
|
2023-09-06 06:47:23 +00:00
|
|
|
form: string;
|
|
|
|
|
steps: number;
|
2023-09-06 08:01:44 +00:00
|
|
|
range: string;
|
|
|
|
|
start: number;
|
|
|
|
|
step: number;
|
|
|
|
|
chooseRange: boolean;
|
2023-09-07 14:14:48 +00:00
|
|
|
required: boolean;
|
|
|
|
|
replText: string;
|
2023-09-12 09:56:15 +00:00
|
|
|
ratingExpanded: boolean;
|
|
|
|
|
ratingDescription: string;
|
2023-07-27 17:30:55 +00:00
|
|
|
};
|
2023-08-10 13:45:44 +00:00
|
|
|
version: number;
|
|
|
|
|
parent_ids: number[];
|
|
|
|
|
created_at: string;
|
|
|
|
|
updated_at: string;
|
2023-08-24 09:09:43 +00:00
|
|
|
expanded: boolean;
|
2023-07-20 22:02:20 +00:00
|
|
|
}
|
2023-06-28 23:32:43 +00:00
|
|
|
|
|
|
|
|
interface QuestionStore {
|
2023-10-02 19:43:07 +00:00
|
|
|
listQuestions: Record<string, AnyQuizQuestion[]>;
|
2023-07-27 17:30:55 +00:00
|
|
|
openedModalSettings: string;
|
2023-06-28 23:32:43 +00:00
|
|
|
}
|
|
|
|
|
|
2023-09-20 12:42:14 +00:00
|
|
|
export const DEFAULT_QUESTION: Omit<Question, "id"> = {
|
|
|
|
|
title: "",
|
|
|
|
|
description: "",
|
|
|
|
|
type: "",
|
|
|
|
|
required: true,
|
|
|
|
|
deleted: true,
|
|
|
|
|
page: 0,
|
|
|
|
|
content: {
|
|
|
|
|
largeCheck: false,
|
|
|
|
|
large: "",
|
|
|
|
|
multi: false,
|
|
|
|
|
own: false,
|
|
|
|
|
innerNameCheck: false,
|
|
|
|
|
innerName: "",
|
|
|
|
|
back: "",
|
|
|
|
|
placeholder: "",
|
|
|
|
|
type: "all",
|
|
|
|
|
autofill: true,
|
|
|
|
|
default: "",
|
|
|
|
|
images: [],
|
|
|
|
|
number: false,
|
|
|
|
|
single: false,
|
|
|
|
|
xy: "",
|
|
|
|
|
format: "carousel",
|
|
|
|
|
text: "",
|
|
|
|
|
picture: "",
|
|
|
|
|
video: "",
|
|
|
|
|
dateRange: false,
|
|
|
|
|
time: false,
|
|
|
|
|
form: "star",
|
|
|
|
|
steps: 5,
|
|
|
|
|
range: "0—100",
|
|
|
|
|
start: 50,
|
|
|
|
|
step: 1,
|
|
|
|
|
chooseRange: false,
|
|
|
|
|
required: false,
|
|
|
|
|
replText: "",
|
|
|
|
|
ratingExpanded: false,
|
|
|
|
|
ratingDescription: "",
|
|
|
|
|
variants: [
|
|
|
|
|
{
|
|
|
|
|
answer: "",
|
|
|
|
|
hints: "",
|
2023-10-03 14:03:57 +00:00
|
|
|
extendedText: "",
|
2023-09-20 12:42:14 +00:00
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
hint: {
|
|
|
|
|
text: "",
|
|
|
|
|
video: "",
|
|
|
|
|
},
|
|
|
|
|
rule: {
|
|
|
|
|
or: true,
|
|
|
|
|
show: true,
|
|
|
|
|
reqs: [
|
|
|
|
|
{
|
|
|
|
|
id: "",
|
|
|
|
|
vars: [],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
version: 0,
|
|
|
|
|
parent_ids: [0],
|
|
|
|
|
created_at: "",
|
|
|
|
|
updated_at: "",
|
|
|
|
|
expanded: false,
|
|
|
|
|
};
|
|
|
|
|
|
2023-06-28 23:32:43 +00:00
|
|
|
export const questionStore = create<QuestionStore>()(
|
2023-07-30 15:48:41 +00:00
|
|
|
persist<QuestionStore>(
|
2023-07-27 17:30:55 +00:00
|
|
|
() => ({
|
2023-09-06 11:51:08 +00:00
|
|
|
listQuestions: {},
|
2023-07-27 17:30:55 +00:00
|
|
|
openedModalSettings: "",
|
2023-08-10 13:45:44 +00:00
|
|
|
}),
|
2023-06-30 14:39:07 +00:00
|
|
|
|
2023-08-10 13:45:44 +00:00
|
|
|
{
|
|
|
|
|
name: "question",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
);
|
2023-10-02 19:43:07 +00:00
|
|
|
export const updateQuestionsList = <T = AnyQuizQuestion>(
|
2023-09-06 13:20:12 +00:00
|
|
|
quizId: number,
|
|
|
|
|
index: number,
|
2023-10-02 19:43:07 +00:00
|
|
|
data: Partial<T>
|
2023-09-06 11:51:08 +00:00
|
|
|
) => {
|
|
|
|
|
const questionListClone = { ...questionStore.getState()["listQuestions"] };
|
2023-09-06 13:20:12 +00:00
|
|
|
questionListClone[quizId][index] = {
|
|
|
|
|
...questionListClone[quizId][index],
|
|
|
|
|
...data,
|
|
|
|
|
};
|
2023-09-06 11:51:08 +00:00
|
|
|
questionStore.setState({ listQuestions: questionListClone });
|
2023-07-27 17:30:55 +00:00
|
|
|
};
|
|
|
|
|
|
2023-08-11 06:15:04 +00:00
|
|
|
export const updateQuestionsListDragAndDrop = (
|
2023-09-06 13:20:12 +00:00
|
|
|
quizId: number,
|
2023-10-03 14:03:57 +00:00
|
|
|
updatedQuestions: AnyQuizQuestion[]
|
2023-08-11 06:15:04 +00:00
|
|
|
) => {
|
2023-09-06 11:51:08 +00:00
|
|
|
const questionListClone = { ...questionStore.getState()["listQuestions"] };
|
|
|
|
|
questionStore.setState({
|
2023-09-06 13:20:12 +00:00
|
|
|
listQuestions: { ...questionListClone, [quizId]: updatedQuestions },
|
2023-09-06 11:51:08 +00:00
|
|
|
});
|
2023-07-27 17:30:55 +00:00
|
|
|
};
|
2023-07-20 22:02:20 +00:00
|
|
|
|
2023-09-06 11:51:08 +00:00
|
|
|
export const updateVariants = (
|
2023-09-06 13:20:12 +00:00
|
|
|
quizId: number,
|
2023-09-06 11:51:08 +00:00
|
|
|
index: number,
|
2023-10-03 14:03:57 +00:00
|
|
|
variants: Variant[]
|
2023-09-06 11:51:08 +00:00
|
|
|
) => {
|
|
|
|
|
const listQuestions = { ...questionStore.getState()["listQuestions"] };
|
2023-08-18 11:16:56 +00:00
|
|
|
|
2023-10-02 19:43:07 +00:00
|
|
|
switch (listQuestions[quizId][index].type) {
|
|
|
|
|
case "emoji":
|
|
|
|
|
const emojiState = listQuestions[quizId][index] as QuizQuestionEmoji;
|
|
|
|
|
emojiState.content.variants = variants;
|
|
|
|
|
return questionStore.setState({ listQuestions });
|
|
|
|
|
|
|
|
|
|
case "images":
|
|
|
|
|
const imagesState = listQuestions[quizId][index] as QuizQuestionImages;
|
|
|
|
|
imagesState.content.variants = variants;
|
|
|
|
|
return questionStore.setState({ listQuestions });
|
|
|
|
|
|
|
|
|
|
case "variant":
|
|
|
|
|
const variantState = listQuestions[quizId][index] as QuizQuestionVariant;
|
|
|
|
|
variantState.content.variants = variants;
|
|
|
|
|
return questionStore.setState({ listQuestions });
|
|
|
|
|
|
|
|
|
|
case "varimg":
|
|
|
|
|
const varImgState = listQuestions[quizId][index] as QuizQuestionVarImg;
|
|
|
|
|
varImgState.content.variants = variants;
|
|
|
|
|
return questionStore.setState({ listQuestions });
|
|
|
|
|
}
|
2023-08-18 11:16:56 +00:00
|
|
|
};
|
|
|
|
|
|
2023-10-02 19:43:07 +00:00
|
|
|
export const createQuestion = (
|
|
|
|
|
quizId: number,
|
2023-10-03 14:03:57 +00:00
|
|
|
questionType: QuizQuestionType = "",
|
2023-10-02 19:43:07 +00:00
|
|
|
placeIndex = -1
|
|
|
|
|
) => {
|
2023-09-06 11:51:08 +00:00
|
|
|
const id = getRandom(1000000, 10000000);
|
|
|
|
|
const newData = { ...questionStore.getState()["listQuestions"] };
|
|
|
|
|
|
2023-09-06 13:20:12 +00:00
|
|
|
if (!newData[quizId]) {
|
|
|
|
|
newData[quizId] = [];
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 19:43:07 +00:00
|
|
|
const defaultObject = [
|
2023-10-03 14:03:57 +00:00
|
|
|
QUIZ_QUESTION_BASE,
|
|
|
|
|
QUIZ_QUESTION_DATE,
|
|
|
|
|
QUIZ_QUESTION_EMOJI,
|
|
|
|
|
QUIZ_QUESTION_FILE,
|
|
|
|
|
QUIZ_QUESTION_IMAGES,
|
|
|
|
|
QUIZ_QUESTION_NUMBER,
|
|
|
|
|
QUIZ_QUESTION_PAGE,
|
|
|
|
|
QUIZ_QUESTION_RATING,
|
|
|
|
|
QUIZ_QUESTION_SELECT,
|
|
|
|
|
QUIZ_QUESTION_TEXT,
|
|
|
|
|
QUIZ_QUESTION_VARIANT,
|
|
|
|
|
QUIZ_QUESTION_VARIMG,
|
2023-10-02 19:43:07 +00:00
|
|
|
].find((defaultObjectItem) => defaultObjectItem.type === questionType);
|
|
|
|
|
|
|
|
|
|
if (defaultObject) {
|
|
|
|
|
newData[quizId].splice(
|
|
|
|
|
placeIndex < 0 ? newData[quizId].length : placeIndex,
|
|
|
|
|
0,
|
|
|
|
|
{ ...defaultObject, id }
|
|
|
|
|
);
|
2023-09-06 13:20:12 +00:00
|
|
|
|
2023-10-02 19:43:07 +00:00
|
|
|
questionStore.setState({ listQuestions: newData });
|
|
|
|
|
}
|
2023-07-27 17:30:55 +00:00
|
|
|
};
|
2023-07-20 22:02:20 +00:00
|
|
|
|
2023-09-06 13:20:12 +00:00
|
|
|
export const copyQuestion = (quizId: number, copiedQuestionIndex: number) => {
|
2023-09-06 11:51:08 +00:00
|
|
|
const listQuestions = { ...questionStore.getState()["listQuestions"] };
|
2023-08-11 07:25:28 +00:00
|
|
|
|
2023-09-08 11:24:09 +00:00
|
|
|
listQuestions[quizId].splice(
|
|
|
|
|
copiedQuestionIndex,
|
|
|
|
|
0,
|
|
|
|
|
listQuestions[quizId][copiedQuestionIndex]
|
|
|
|
|
);
|
2023-08-11 07:25:28 +00:00
|
|
|
|
|
|
|
|
questionStore.setState({ listQuestions });
|
|
|
|
|
};
|
|
|
|
|
|
2023-09-06 13:20:12 +00:00
|
|
|
export const removeQuestion = (quizId: number, index: number) => {
|
2023-09-06 11:51:08 +00:00
|
|
|
const questionListClone = { ...questionStore.getState()["listQuestions"] };
|
|
|
|
|
|
2023-09-06 13:20:12 +00:00
|
|
|
questionListClone[quizId].splice(index, 1);
|
2023-09-06 11:51:08 +00:00
|
|
|
|
|
|
|
|
questionStore.setState({ listQuestions: questionListClone });
|
2023-07-27 17:30:55 +00:00
|
|
|
};
|
2023-07-20 22:02:20 +00:00
|
|
|
|
2023-07-30 15:35:40 +00:00
|
|
|
export const resetSomeField = (data: Record<string, string>) => {
|
2023-07-27 17:30:55 +00:00
|
|
|
questionStore.setState(data);
|
|
|
|
|
};
|
2023-07-20 22:02:20 +00:00
|
|
|
|
2023-09-06 13:20:12 +00:00
|
|
|
export const findQuestionById = (quizId: number) => {
|
2023-07-27 17:30:55 +00:00
|
|
|
let found = null;
|
2023-08-11 06:15:04 +00:00
|
|
|
questionStore
|
|
|
|
|
.getState()
|
2023-10-02 19:43:07 +00:00
|
|
|
["listQuestions"][quizId].some((quiz: AnyQuizQuestion, index: number) => {
|
2023-09-06 13:20:12 +00:00
|
|
|
if (quiz.id === quizId) {
|
2023-08-11 06:15:04 +00:00
|
|
|
found = { quiz, index };
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-07-27 17:30:55 +00:00
|
|
|
return found;
|
|
|
|
|
};
|
2023-07-11 10:43:04 +00:00
|
|
|
|
|
|
|
|
function getRandom(min: number, max: number) {
|
2023-07-27 17:30:55 +00:00
|
|
|
min = Math.ceil(min);
|
|
|
|
|
max = Math.floor(max);
|
|
|
|
|
return Math.floor(Math.random() * (max - min)) + min;
|
|
|
|
|
}
|