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; currentQuizStep: QuizStep; } interface QuizViewActions { updateAnswer: (questionId: string, answer: string | string[] | Moment, points: number) => void; deleteAnswer: (questionId: string) => void; updateOwnVariant: ( id: string, answer: string, extendedText?: string, originalImageUrl?: string, localImageUrl?: string ) => void; deleteOwnVariant: (id: string) => void; setCurrentQuizStep: (step: QuizStep) => void; } export const QuizViewContext = createContext | null>(null); export function useQuizViewStore(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()( immer( devtools( (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); }, 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) => { const index = state.ownVariants.findIndex((variant) => variant.id === id); if (index < 0) { state.ownVariants.push({ id, variant: { id: id, answer, extendedText: extendedText || "", hints: "", originalImageUrl: originalImageUrl || "", localImageUrl: localImageUrl || "", }, }); } else { state.ownVariants[index].variant.answer = answer; if (extendedText) { state.ownVariants[index].variant.extendedText = extendedText; } if (originalImageUrl) { state.ownVariants[index].variant.originalImageUrl = originalImageUrl; } if (localImageUrl) { 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, } ) ) );