183 lines
6.6 KiB
TypeScript
183 lines
6.6 KiB
TypeScript
import { create } from "zustand";
|
|
import { createJSONStorage, persist } from "zustand/middleware";
|
|
import { immer } from "zustand/middleware/immer";
|
|
import { ExamFunctions, ExamState, Navigation, StateFlags } from "./types";
|
|
import { rootReducer } from "./reducers";
|
|
import axios from "axios";
|
|
import { v4 } from "uuid";
|
|
import { Stat } from "@/interfaces/user";
|
|
import { Exam, Shuffles, UserSolution } from "@/interfaces/exam";
|
|
import { Module } from "@/interfaces";
|
|
|
|
export const initialState: ExamState = {
|
|
exams: [],
|
|
userSolutions: [],
|
|
showSolutions: false,
|
|
selectedModules: [],
|
|
assignment: undefined,
|
|
timeSpent: 0,
|
|
timeSpentCurrentModule: 0,
|
|
sessionId: "",
|
|
exam: undefined,
|
|
moduleIndex: 0,
|
|
partIndex: 0,
|
|
exerciseIndex: 0,
|
|
questionIndex: 0,
|
|
inactivity: 0,
|
|
shuffles: [],
|
|
bgColor: "bg-white",
|
|
evaluated: [],
|
|
user: undefined,
|
|
navigation: {
|
|
previousDisabled: false,
|
|
nextDisabled: false,
|
|
previousLoading: false,
|
|
nextLoading: false,
|
|
},
|
|
flags: {
|
|
timeIsUp: false,
|
|
reviewAll: false,
|
|
finalizeModule: false,
|
|
finalizeExam: false,
|
|
pendingEvaluation: false,
|
|
},
|
|
};
|
|
|
|
const useExamStore = create<ExamState & ExamFunctions>((set, get) => ({
|
|
...initialState,
|
|
setUser: (user: string) => set(() => ({ user })),
|
|
setShowSolutions: (showSolutions: boolean) => set(() => ({ showSolutions })),
|
|
setExams: (exams: Exam[]) => set(() => ({ exams })),
|
|
setExam: (exam?: Exam) => set(() => ({ exam })),
|
|
setModuleIndex: (moduleIndex: number) => set(() => ({ moduleIndex })),
|
|
setSelectedModules: (modules: Module[]) => set(() => ({ selectedModules: modules })),
|
|
|
|
setSessionId: (sessionId: string) => set(() => ({ sessionId })),
|
|
setUserSolutions: (userSolutions: UserSolution[]) => set(() => ({ userSolutions })),
|
|
|
|
setShuffles: (shuffles: Shuffles[]) => set(() => ({ shuffles })),
|
|
|
|
setPartIndex: (partIndex: number) => set(() => ({ partIndex })),
|
|
setExerciseIndex: (exerciseIndex: number) => set(() => ({ exerciseIndex })),
|
|
setQuestionIndex: (questionIndex: number) => set(() => ({ questionIndex })),
|
|
setBgColor: (bgColor: string) => set(() => ({ bgColor })),
|
|
|
|
setEvaluated: (evaluated: UserSolution[]) => set(() => ({ evaluated })),
|
|
|
|
setNavigation: (updates: Partial<Navigation>) => set((state) => ({
|
|
navigation: {
|
|
...state.navigation,
|
|
...updates
|
|
}
|
|
})),
|
|
|
|
setFlags: (updates: Partial<StateFlags>) => set((state) => ({
|
|
flags: {
|
|
...state.flags,
|
|
...updates
|
|
}
|
|
})),
|
|
|
|
setTimeIsUp: (timeIsUp: boolean) => set((state) => ({ flags: { ...state.flags, timeIsUp } })),
|
|
|
|
reset: () => set(() => initialState),
|
|
|
|
saveSession: async () => {
|
|
console.log("Saving your session...");
|
|
const state = get();
|
|
await axios.post("/api/sessions", {
|
|
id: state.sessionId,
|
|
sessionId: state.sessionId,
|
|
date: new Date().toISOString(),
|
|
userSolutions: state.userSolutions.filter((s) => s.type !== "speaking" && s.type !== "interactiveSpeaking"),
|
|
moduleIndex: state.moduleIndex,
|
|
selectedModules: state.selectedModules,
|
|
assignment: state.assignment,
|
|
timeSpent: state.timeSpent,
|
|
timeSpentCurrentModule: state.timeSpentCurrentModule,
|
|
inactivity: state.inactivity,
|
|
exams: state.exams,
|
|
exam: state.exam,
|
|
partIndex: state.partIndex,
|
|
exerciseIndex: state.exerciseIndex,
|
|
questionIndex: state.questionIndex,
|
|
user: state.user,
|
|
});
|
|
},
|
|
saveStats: async () => {
|
|
const state = get();
|
|
const newStats: Stat[] = state.userSolutions.map((solution) => ({
|
|
...solution,
|
|
id: solution.id || v4(),
|
|
timeSpent: state.timeSpent,
|
|
inactivity: state.inactivity,
|
|
session: state.sessionId,
|
|
exam: solution.exam!,
|
|
module: solution.module!,
|
|
user: state.user || "",
|
|
date: new Date().getTime(),
|
|
isDisabled: solution.isDisabled,
|
|
shuffleMaps: solution.shuffleMaps,
|
|
...(state.assignment ? { assignment: state.assignment.id } : {}),
|
|
isPractice: solution.isPractice
|
|
}));
|
|
await axios.post<{ ok: boolean }>("/api/stats", newStats);
|
|
},
|
|
dispatch: (action) => set((state) => rootReducer(state, action))
|
|
}));
|
|
|
|
export const usePersistentExamStore = create<ExamState & ExamFunctions>()(
|
|
persist(
|
|
immer((set) => ({
|
|
...initialState,
|
|
setUser: (user: string) => set(() => ({ user })),
|
|
setShowSolutions: (showSolutions: boolean) => set(() => ({ showSolutions })),
|
|
setExams: (exams: Exam[]) => set(() => ({ exams })),
|
|
setExam: (exam?: Exam) => set(() => ({ exam })),
|
|
setModuleIndex: (moduleIndex: number) => set(() => ({ moduleIndex })),
|
|
setSelectedModules: (modules: Module[]) => set(() => ({ selectedModules: modules })),
|
|
|
|
setSessionId: (sessionId: string) => set(() => ({ sessionId })),
|
|
setUserSolutions: (userSolutions: UserSolution[]) => set(() => ({ userSolutions })),
|
|
|
|
setShuffles: (shuffles: Shuffles[]) => set(() => ({ shuffles })),
|
|
|
|
setPartIndex: (partIndex: number) => set(() => ({ partIndex })),
|
|
setExerciseIndex: (exerciseIndex: number) => set(() => ({ exerciseIndex })),
|
|
setQuestionIndex: (questionIndex: number) => set(() => ({ questionIndex })),
|
|
setBgColor: (bgColor: string) => set(() => ({ bgColor })),
|
|
|
|
setNavigation: (updates: Partial<Navigation>) => set((state) => ({
|
|
navigation: {
|
|
...state.navigation,
|
|
...updates
|
|
}
|
|
})),
|
|
|
|
setFlags: (updates: Partial<StateFlags>) => set((state) => ({
|
|
flags: {
|
|
...state.flags,
|
|
...updates
|
|
}
|
|
})),
|
|
|
|
|
|
setTimeIsUp: (timeIsUp: boolean) => set((state) => ({ flags: { ...state.flags, timeIsUp } })),
|
|
|
|
saveStats: async () => { },
|
|
saveSession: async () => { },
|
|
setEvaluated: (evaluated: UserSolution[]) => {},
|
|
reset: () => set(() => initialState),
|
|
dispatch: (action) => set((state) => rootReducer(state, action))
|
|
|
|
})),
|
|
{
|
|
name: 'persistent-exam-store',
|
|
storage: createJSONStorage(() => localStorage),
|
|
partialize: (state) => ({ ...state }),
|
|
}
|
|
)
|
|
);
|
|
|
|
export default useExamStore;
|