Navigation rework, added prompt edit to components that were missing
This commit is contained in:
180
src/stores/exam/index.ts
Normal file
180
src/stores/exam/index.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
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",
|
||||
currentSolution: undefined,
|
||||
user: undefined,
|
||||
navigation: {
|
||||
previousDisabled: false,
|
||||
nextDisabled: false,
|
||||
previousLoading: false,
|
||||
nextLoading: false,
|
||||
},
|
||||
flags: {
|
||||
timeIsUp: false,
|
||||
reviewAll: false,
|
||||
finalizeModule: false,
|
||||
finalizeExam: 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 })),
|
||||
|
||||
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 () => {},
|
||||
|
||||
reset: () => set(() => initialState),
|
||||
dispatch: (action) => set((state) => rootReducer(state, action))
|
||||
|
||||
})),
|
||||
{
|
||||
name: 'persistent-exam-store',
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
partialize: (state) => ({ ...state }),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
export default useExamStore;
|
||||
161
src/stores/exam/reducers/index.ts
Normal file
161
src/stores/exam/reducers/index.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
import { Module } from "@/interfaces";
|
||||
import { ExamState } from "../types";
|
||||
import { SESSION_ACTIONS, SessionActions, sessionReducer } from "./session";
|
||||
import { Exam, UserSolution } from "@/interfaces/exam";
|
||||
import { updateExamWithUserSolutions } from "../utils";
|
||||
import { defaultExamUserSolutions } from "@/utils/exams";
|
||||
import { Assignment } from "@/interfaces/results";
|
||||
import { Stat } from "@/interfaces/user";
|
||||
import { convertToUserSolutions } from "@/utils/stats";
|
||||
|
||||
export type RootActions =
|
||||
{ type: 'INIT_EXAM'; payload: { exams: Exam[], modules: Module[], assignment?: Assignment } } |
|
||||
{ type: 'INIT_SOLUTIONS'; payload: { exams: Exam[], modules: Module[], stats: Stat[], timeSpent?: number, inactivity?: number } } |
|
||||
{ type: 'UPDATE_TIMERS'; payload: { timeSpent: number; inactivity: number; timeSpentCurrentModule: number;} } |
|
||||
{ type: 'FINALIZE_MODULE'; payload: { updateTimers: boolean } } |
|
||||
{ type: 'FINALIZE_MODULE_SOLUTIONS' }
|
||||
|
||||
|
||||
export type Action = RootActions | SessionActions;
|
||||
|
||||
export const rootReducer = (
|
||||
state: ExamState,
|
||||
action: Action
|
||||
): Partial<ExamState> => {
|
||||
|
||||
if (SESSION_ACTIONS.includes(action.type as any)) {
|
||||
return sessionReducer(action as SessionActions);
|
||||
}
|
||||
|
||||
switch (action.type) {
|
||||
case 'INIT_EXAM': {
|
||||
const { exams, modules, assignment } = action.payload;
|
||||
|
||||
let examAndSolutions = {}
|
||||
|
||||
// A new exam is about to start,
|
||||
// fill the first module with defaultUserSolutions
|
||||
let defaultSolutions = exams.map(defaultExamUserSolutions).flat();
|
||||
examAndSolutions = {
|
||||
userSolutions: defaultSolutions,
|
||||
exam: updateExamWithUserSolutions(exams[0], defaultSolutions)
|
||||
}
|
||||
|
||||
if (assignment) {
|
||||
examAndSolutions = { ...examAndSolutions, assignment }
|
||||
}
|
||||
|
||||
// now all the modules start at 0 since navigation
|
||||
// is now handled at the module page's and no re-renders
|
||||
// reset the initial render caused by the timers
|
||||
// no need to do all that weird chainning with -1
|
||||
// on some modules and triggering next() to update final solution
|
||||
// with hasExamEnded flag
|
||||
return {
|
||||
moduleIndex: 0,
|
||||
partIndex: 0,
|
||||
exerciseIndex: 0,
|
||||
questionIndex: 0,
|
||||
exams: exams,
|
||||
selectedModules: modules,
|
||||
showSolutions: false,
|
||||
...examAndSolutions
|
||||
}
|
||||
};
|
||||
case 'INIT_SOLUTIONS': {
|
||||
const { exams, modules, stats, timeSpent, inactivity } = action.payload;
|
||||
|
||||
let time = {}
|
||||
if (timeSpent) time = { timeSpent }
|
||||
if (inactivity) time = { ...time, inactivity }
|
||||
|
||||
return {
|
||||
moduleIndex: -1,
|
||||
partIndex: 0,
|
||||
exerciseIndex: 0,
|
||||
questionIndex: 0,
|
||||
exams: exams,
|
||||
selectedModules: modules,
|
||||
showSolutions: true,
|
||||
userSolutions: convertToUserSolutions(stats),
|
||||
...time
|
||||
}
|
||||
}
|
||||
case 'UPDATE_TIMERS': {
|
||||
// Just assigning the timers at once instead of two different calls
|
||||
const { timeSpent, inactivity, timeSpentCurrentModule } = action.payload;
|
||||
return {
|
||||
timeSpentCurrentModule,
|
||||
timeSpent,
|
||||
inactivity
|
||||
}
|
||||
};
|
||||
case 'FINALIZE_MODULE': {
|
||||
const { updateTimers } = action.payload;
|
||||
|
||||
// To finalize a module first flag the timers to be updated
|
||||
if (updateTimers) {
|
||||
return {
|
||||
flags: { ...state.flags, finalizeModule: true }
|
||||
}
|
||||
} else {
|
||||
// then check whether there are more modules in the exam, if there are
|
||||
// setup the next module
|
||||
if (state.moduleIndex + 1 < state.selectedModules.length) {
|
||||
return {
|
||||
moduleIndex: state.moduleIndex + 1,
|
||||
partIndex: 0,
|
||||
exerciseIndex: 0,
|
||||
questionIndex: 0,
|
||||
exam: updateExamWithUserSolutions(state.exams[state.moduleIndex + 1], state.userSolutions),
|
||||
flags: {
|
||||
...state.flags,
|
||||
finalizeModule: false,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if there are no modules left, flag finalizeExam
|
||||
// so that the stats are uploaded in ExamPage
|
||||
// and the Finish view is set there, no need to
|
||||
// dispatch another init
|
||||
return {
|
||||
flags: {
|
||||
...state.flags,
|
||||
finalizeModule: false,
|
||||
finalizeExam: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'FINALIZE_MODULE_SOLUTIONS': {
|
||||
if (state.flags.reviewAll) {
|
||||
const notLastModule = state.moduleIndex < state.selectedModules.length;
|
||||
const moduleIndex = notLastModule ? state.moduleIndex + 1 : -1;
|
||||
if (notLastModule) {
|
||||
return {
|
||||
questionIndex: 0,
|
||||
exerciseIndex: 0,
|
||||
partIndex: 0,
|
||||
exam: state.exams[moduleIndex + 1],
|
||||
moduleIndex: moduleIndex
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
questionIndex: 0,
|
||||
exerciseIndex: 0,
|
||||
partIndex: 0,
|
||||
moduleIndex: -1
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return {
|
||||
moduleIndex: -1
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
34
src/stores/exam/reducers/session.ts
Normal file
34
src/stores/exam/reducers/session.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Session } from "@/hooks/useSessions";
|
||||
import { ExamState } from "../types";
|
||||
|
||||
export type SessionActions =
|
||||
{ type: 'SET_SESSION'; payload: { session: Session } }
|
||||
|
||||
export const SESSION_ACTIONS = [
|
||||
'SET_SESSION'
|
||||
];
|
||||
|
||||
export const sessionReducer = (action: SessionActions): Partial<ExamState> => {
|
||||
switch (action.type) {
|
||||
case 'SET_SESSION':
|
||||
const { session } = action.payload;
|
||||
return {
|
||||
shuffles: session.userSolutions.map((x) => ({ exerciseID: x.exercise, shuffles: x.shuffleMaps ? x.shuffleMaps : [] })),
|
||||
selectedModules: session.selectedModules,
|
||||
exam: session.exam,
|
||||
exams: session.exams,
|
||||
sessionId: session.sessionId,
|
||||
assignment: session.assignment,
|
||||
exerciseIndex: session.exerciseIndex,
|
||||
partIndex: session.partIndex,
|
||||
moduleIndex: session.moduleIndex,
|
||||
timeSpent: session.timeSpent,
|
||||
userSolutions: session.userSolutions,
|
||||
timeSpentCurrentModule: session.timeSpentCurrentModule !== undefined ? session.timeSpentCurrentModule : session.timeSpent,
|
||||
showSolutions: false,
|
||||
questionIndex: session.questionIndex
|
||||
};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
76
src/stores/exam/types.ts
Normal file
76
src/stores/exam/types.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Module } from "@/interfaces";
|
||||
import { Exam, Shuffles, UserSolution } from "@/interfaces/exam";
|
||||
import { Assignment } from "@/interfaces/results";
|
||||
import { Action } from "./reducers";
|
||||
|
||||
|
||||
export interface Navigation {
|
||||
previousDisabled: boolean;
|
||||
nextDisabled: boolean;
|
||||
previousLoading: boolean;
|
||||
nextLoading: boolean;
|
||||
}
|
||||
|
||||
export interface StateFlags {
|
||||
timeIsUp: boolean;
|
||||
reviewAll: boolean;
|
||||
finalizeModule: boolean;
|
||||
finalizeExam: boolean;
|
||||
}
|
||||
|
||||
export interface ExamState {
|
||||
exams: Exam[];
|
||||
userSolutions: UserSolution[];
|
||||
showSolutions: boolean;
|
||||
selectedModules: Module[];
|
||||
assignment?: Assignment;
|
||||
timeSpent: number;
|
||||
timeSpentCurrentModule: number;
|
||||
sessionId: string;
|
||||
moduleIndex: number;
|
||||
exam?: Exam;
|
||||
partIndex: number;
|
||||
exerciseIndex: number;
|
||||
questionIndex: number;
|
||||
inactivity: number;
|
||||
shuffles: Shuffles[];
|
||||
bgColor: string;
|
||||
user: undefined | string;
|
||||
currentSolution?: UserSolution | undefined;
|
||||
navigation: Navigation;
|
||||
flags: StateFlags,
|
||||
}
|
||||
|
||||
|
||||
export interface ExamFunctions {
|
||||
setUser: (user: string) => void;
|
||||
|
||||
setShowSolutions: (showSolutions: boolean) => void;
|
||||
setExams: (exams: Exam[]) => void;
|
||||
setSelectedModules: (modules: Module[]) => void;
|
||||
setModuleIndex: (moduleIndex: number) => void;
|
||||
setExam: (exam?: Exam) => void;
|
||||
|
||||
setPartIndex: (partIndex: number) => void;
|
||||
setExerciseIndex: (exerciseIndex: number) => void;
|
||||
setQuestionIndex: (questionIndex: number) => void;
|
||||
setBgColor: (bgColor: string) => void;
|
||||
|
||||
setShuffles: (shuffles: Shuffles[]) => void;
|
||||
|
||||
setSessionId: (sessionId: string) => void;
|
||||
setUserSolutions: (userSolutions: UserSolution[]) => void;
|
||||
|
||||
setTimeIsUp: (timeIsUp: boolean) => void;
|
||||
|
||||
saveSession: () => Promise<void>;
|
||||
|
||||
saveStats: () => Promise<void>;
|
||||
|
||||
setNavigation: (updates: Partial<Navigation>) => void;
|
||||
setFlags: (updates: Partial<StateFlags>) => void;
|
||||
|
||||
reset: () => void;
|
||||
|
||||
dispatch: (action: Action) => void;
|
||||
}
|
||||
27
src/stores/exam/utils.ts
Normal file
27
src/stores/exam/utils.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Exam, ExerciseOnlyExam, PartExam, UserSolution } from "@/interfaces/exam";
|
||||
|
||||
const updateExamWithUserSolutions = (exam: Exam, userSolutions: UserSolution[]): Exam => {
|
||||
if (["reading", "listening", "level"].includes(exam.module)) {
|
||||
const parts = (exam as PartExam).parts.map((p) =>
|
||||
Object.assign(p, {
|
||||
exercises: p.exercises.map((x) =>
|
||||
Object.assign(x, {
|
||||
userSolutions: userSolutions.find((y) => x.id === y.exercise)?.solutions,
|
||||
}),
|
||||
),
|
||||
}),
|
||||
);
|
||||
return Object.assign(exam, { parts });
|
||||
}
|
||||
|
||||
const exercises = (exam as ExerciseOnlyExam).exercises.map((x) =>
|
||||
Object.assign(x, {
|
||||
userSolutions: userSolutions.find((y) => x.id === y.exercise)?.solutions,
|
||||
}),
|
||||
);
|
||||
return Object.assign(exam, { exercises });
|
||||
};
|
||||
|
||||
export {
|
||||
updateExamWithUserSolutions,
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import { Module } from "@/interfaces";
|
||||
import { Exam, Shuffles, UserSolution } from "@/interfaces/exam";
|
||||
import { Assignment } from "@/interfaces/results";
|
||||
import { create } from "zustand";
|
||||
import { createJSONStorage, persist } from "zustand/middleware";
|
||||
import { immer } from "zustand/middleware/immer";
|
||||
|
||||
export interface ExamState {
|
||||
exams: Exam[];
|
||||
userSolutions: UserSolution[];
|
||||
showSolutions: boolean;
|
||||
hasExamEnded: boolean;
|
||||
selectedModules: Module[];
|
||||
assignment?: Assignment;
|
||||
timeSpent: number;
|
||||
sessionId: string;
|
||||
moduleIndex: number;
|
||||
exam?: Exam;
|
||||
partIndex: number;
|
||||
exerciseIndex: number;
|
||||
questionIndex: number;
|
||||
inactivity: number;
|
||||
shuffles: Shuffles[];
|
||||
bgColor: string;
|
||||
currentSolution?: UserSolution | undefined;
|
||||
}
|
||||
|
||||
export interface ExamFunctions {
|
||||
setExams: (exams: Exam[]) => void;
|
||||
setUserSolutions: (userSolutions: UserSolution[]) => void;
|
||||
setShowSolutions: (showSolutions: boolean) => void;
|
||||
setHasExamEnded: (hasExamEnded: boolean) => void;
|
||||
setSelectedModules: (modules: Module[]) => void;
|
||||
setAssignment: (assignment?: Assignment) => void;
|
||||
setTimeSpent: (timeSpent: number) => void;
|
||||
setSessionId: (sessionId: string) => void;
|
||||
setModuleIndex: (moduleIndex: number) => void;
|
||||
setExam: (exam?: Exam) => void;
|
||||
setPartIndex: (partIndex: number) => void;
|
||||
setExerciseIndex: (exerciseIndex: number) => void;
|
||||
setQuestionIndex: (questionIndex: number) => void;
|
||||
setInactivity: (inactivity: number) => void;
|
||||
setShuffles: (shuffles: Shuffles[]) => void;
|
||||
setBgColor: (bgColor: string) => void;
|
||||
setCurrentSolution: (currentSolution: UserSolution | undefined) => void;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
export const initialState: ExamState = {
|
||||
exams: [],
|
||||
userSolutions: [],
|
||||
showSolutions: false,
|
||||
selectedModules: [],
|
||||
hasExamEnded: false,
|
||||
assignment: undefined,
|
||||
timeSpent: 0,
|
||||
sessionId: "",
|
||||
exam: undefined,
|
||||
moduleIndex: 0,
|
||||
partIndex: -1,
|
||||
exerciseIndex: -1,
|
||||
questionIndex: 0,
|
||||
inactivity: 0,
|
||||
shuffles: [],
|
||||
bgColor: "bg-white",
|
||||
currentSolution: undefined
|
||||
};
|
||||
|
||||
const useExamStore = create<ExamState & ExamFunctions>((set) => ({
|
||||
...initialState,
|
||||
|
||||
setUserSolutions: (userSolutions: UserSolution[]) => set(() => ({ userSolutions })),
|
||||
setExams: (exams: Exam[]) => set(() => ({ exams })),
|
||||
setShowSolutions: (showSolutions: boolean) => set(() => ({ showSolutions })),
|
||||
setSelectedModules: (modules: Module[]) => set(() => ({ selectedModules: modules })),
|
||||
setHasExamEnded: (hasExamEnded: boolean) => set(() => ({ hasExamEnded })),
|
||||
setAssignment: (assignment?: Assignment) => set(() => ({ assignment })),
|
||||
setTimeSpent: (timeSpent) => set(() => ({ timeSpent })),
|
||||
setSessionId: (sessionId: string) => set(() => ({ sessionId })),
|
||||
setExam: (exam?: Exam) => set(() => ({ exam })),
|
||||
setModuleIndex: (moduleIndex: number) => set(() => ({ moduleIndex })),
|
||||
setPartIndex: (partIndex: number) => set(() => ({ partIndex })),
|
||||
setExerciseIndex: (exerciseIndex: number) => set(() => ({ exerciseIndex })),
|
||||
setQuestionIndex: (questionIndex: number) => set(() => ({ questionIndex })),
|
||||
setInactivity: (inactivity: number) => set(() => ({ inactivity })),
|
||||
setShuffles: (shuffles: Shuffles[]) => set(() => ({ shuffles })),
|
||||
setBgColor: (bgColor) => set(() => ({ bgColor })),
|
||||
setCurrentSolution: (currentSolution: UserSolution | undefined) => set(() => ({ currentSolution })),
|
||||
|
||||
reset: () => set(() => initialState),
|
||||
}));
|
||||
|
||||
export default useExamStore;
|
||||
|
||||
|
||||
export const usePersistentExamStore = create<ExamState & ExamFunctions>()(
|
||||
persist(
|
||||
immer((set) => ({
|
||||
...initialState,
|
||||
setUserSolutions: (userSolutions: UserSolution[]) => set(() => ({ userSolutions })),
|
||||
setExams: (exams: Exam[]) => set(() => ({ exams })),
|
||||
setShowSolutions: (showSolutions: boolean) => set(() => ({ showSolutions })),
|
||||
setSelectedModules: (modules: Module[]) => set(() => ({ selectedModules: modules })),
|
||||
setHasExamEnded: (hasExamEnded: boolean) => set(() => ({ hasExamEnded })),
|
||||
setAssignment: (assignment?: Assignment) => set(() => ({ assignment })),
|
||||
setTimeSpent: (timeSpent) => set(() => ({ timeSpent })),
|
||||
setSessionId: (sessionId: string) => set(() => ({ sessionId })),
|
||||
setExam: (exam?: Exam) => set(() => ({ exam })),
|
||||
setModuleIndex: (moduleIndex: number) => set(() => ({ moduleIndex })),
|
||||
setPartIndex: (partIndex: number) => set(() => ({ partIndex })),
|
||||
setExerciseIndex: (exerciseIndex: number) => set(() => ({ exerciseIndex })),
|
||||
setQuestionIndex: (questionIndex: number) => set(() => ({ questionIndex })),
|
||||
setInactivity: (inactivity: number) => set(() => ({ inactivity })),
|
||||
setShuffles: (shuffles: Shuffles[]) => set(() => ({ shuffles })),
|
||||
setBgColor: (bgColor) => set(() => ({ bgColor })),
|
||||
setCurrentSolution: (currentSolution: UserSolution | undefined) => set(() => ({ currentSolution })),
|
||||
|
||||
reset: () => set(() => initialState),
|
||||
})),
|
||||
{
|
||||
name: 'persistent-exam-store',
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
partialize: (state) => ({ ...state }),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user