166 lines
5.8 KiB
TypeScript
166 lines
5.8 KiB
TypeScript
import { QuestionVariant } from "@model/questionTypes/shared";
|
||
import { QuizStep } from "@model/settingsData";
|
||
import type { Moment } from "moment";
|
||
import { nanoid } from "nanoid";
|
||
import { createContext, useContext } from "react";
|
||
import { createStore, useStore } from "zustand";
|
||
import { immer } from "zustand/middleware/immer";
|
||
import { devtools } from "zustand/middleware";
|
||
|
||
export type Answer = string | string[] | Moment;
|
||
|
||
export type QuestionAnswer = {
|
||
questionId: string;
|
||
answer: Answer;
|
||
};
|
||
|
||
export type OwnVariant = {
|
||
id: string;
|
||
variant: QuestionVariant;
|
||
};
|
||
|
||
interface QuizViewStore {
|
||
answers: QuestionAnswer[];
|
||
ownVariants: OwnVariant[];
|
||
pointsSum: number;
|
||
points: Record<string, number>;
|
||
currentQuizStep: QuizStep;
|
||
}
|
||
|
||
interface QuizViewActions {
|
||
updateAnswer: (questionId: string, answer: string | string[] | Moment, points: number) => void;
|
||
deleteAnswer: (questionId: string) => void;
|
||
updateOwnVariant: (
|
||
id: string, //
|
||
answer: string | null, //
|
||
extendedText?: string, //
|
||
originalImageUrl?: string, //
|
||
localImageUrl?: string //
|
||
) => void;
|
||
deleteOwnVariant: (id: string) => void;
|
||
setCurrentQuizStep: (step: QuizStep) => void;
|
||
}
|
||
|
||
export const QuizViewContext = createContext<ReturnType<typeof createQuizViewStore> | null>(null);
|
||
|
||
export function useQuizViewStore<U>(selector: (state: QuizViewStore & QuizViewActions) => U): U {
|
||
const store = useContext(QuizViewContext);
|
||
if (!store) throw new Error("QuizViewStore context is null");
|
||
|
||
return useStore(store, selector);
|
||
}
|
||
|
||
export const createQuizViewStore = () =>
|
||
createStore<QuizViewStore & QuizViewActions>()(
|
||
immer(
|
||
devtools(
|
||
(set, get) => ({
|
||
answers: [], //Массив вообще всех ответов. Объекты хранят инфо о id вопроса и списке выбранных ответов
|
||
ownVariants: [], //Подробное описание ответов для особенных. Здесь подробно расписана вся кастомизация ответов в own вариантах
|
||
points: {},
|
||
pointsSum: 0,
|
||
currentQuizStep: "startpage",
|
||
updateAnswer(questionId, answer, points) {
|
||
set(
|
||
(state) => {
|
||
const index = state.answers.findIndex((answer) => questionId === answer.questionId);
|
||
|
||
if (index < 0) {
|
||
state.answers.push({ questionId, answer });
|
||
} else {
|
||
state.answers[index] = { questionId, answer };
|
||
}
|
||
|
||
state.points = { ...state.points, ...{ [questionId]: points } };
|
||
|
||
state.pointsSum = Object.values(state.points).reduce((sum, value) => sum + value);
|
||
},
|
||
false,
|
||
{
|
||
type: "updateAnswer",
|
||
questionId,
|
||
answer,
|
||
points,
|
||
}
|
||
);
|
||
},
|
||
deleteAnswer(questionId) {
|
||
set(
|
||
(state) => {
|
||
state.answers = state.answers.filter((answer) => questionId !== answer.questionId);
|
||
},
|
||
false,
|
||
{
|
||
type: "deleteAnswer",
|
||
questionId,
|
||
}
|
||
);
|
||
},
|
||
updateOwnVariant(id, answer, extendedText, originalImageUrl, localImageUrl) {
|
||
set(
|
||
(state) => {
|
||
console.log("!!! STORE !!! ___ Случился вызов варианта свой ответ. Вот что я получил:");
|
||
console.log(id, answer, extendedText, originalImageUrl, localImageUrl);
|
||
const index = state.ownVariants.findIndex((variant) => variant.id === id);
|
||
|
||
if (index < 0) {
|
||
state.ownVariants.push({
|
||
id,
|
||
variant: {
|
||
id: id,
|
||
answer: answer === null ? state.ownVariants[index].variant.answer : answer,
|
||
extendedText: extendedText || "",
|
||
hints: "",
|
||
originalImageUrl: originalImageUrl || "",
|
||
localImageUrl: localImageUrl || "",
|
||
},
|
||
});
|
||
} else {
|
||
if (answer !== null) state.ownVariants[index].variant.answer = answer;
|
||
if (extendedText !== undefined) {
|
||
state.ownVariants[index].variant.extendedText = extendedText;
|
||
}
|
||
if (originalImageUrl !== undefined) {
|
||
state.ownVariants[index].variant.originalImageUrl = originalImageUrl;
|
||
}
|
||
if (localImageUrl !== undefined) {
|
||
state.ownVariants[index].variant.localImageUrl = localImageUrl;
|
||
}
|
||
}
|
||
},
|
||
false,
|
||
{
|
||
type: "updateOwnVariant",
|
||
id,
|
||
answer,
|
||
}
|
||
);
|
||
},
|
||
deleteOwnVariant(id) {
|
||
set(
|
||
(state) => {
|
||
state.ownVariants = state.ownVariants.filter((variant) => variant.id !== id);
|
||
},
|
||
false,
|
||
{
|
||
type: "deleteOwnVariant",
|
||
id,
|
||
}
|
||
);
|
||
},
|
||
setCurrentQuizStep(step) {
|
||
set({ currentQuizStep: step }, false, {
|
||
type: "setCurrentQuizStep",
|
||
step,
|
||
});
|
||
},
|
||
}),
|
||
{
|
||
name: "QuizViewStore-" + nanoid(4),
|
||
enabled: import.meta.env.DEV,
|
||
trace: import.meta.env.DEV,
|
||
}
|
||
)
|
||
)
|
||
);
|