frontAnswerer/lib/stores/quizView.ts
nflnkr 979d0e7138 make quiz view store component store
move design list to separate file
2024-04-03 15:42:12 +03:00

103 lines
3.6 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";
type QuestionAnswer = {
questionId: string;
answer: string | string[] | Moment;
};
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) => 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 context = useContext(QuizViewContext);
if (!context) throw new Error("QuizViewStore context is null");
return useStore(context, selector);
}
export const createQuizViewStore = () => createStore<QuizViewStore & QuizViewActions>()(
immer(
(set, get) => ({
answers: [],
ownVariants: [],
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);
});
},
deleteAnswer(questionId) {
set(state => {
state.answers = state.answers.filter(answer => questionId !== answer.questionId);
});
},
updateOwnVariant(id, answer) {
set(state => {
const index = state.ownVariants.findIndex((variant) => variant.id === id);
if (index < 0) {
state.ownVariants.push({
id,
variant: {
id: nanoid(),
answer,
extendedText: "",
hints: "",
originalImageUrl: "",
},
});
} else {
state.ownVariants[index].variant.answer = answer;
}
});
},
deleteOwnVariant(id) {
set(state => {
state.ownVariants = state.ownVariants.filter((variant) => variant.id !== id);
});
},
setCurrentQuizStep(step) {
set({ currentQuizStep: step });
},
})
)
);