Navigation rework, added prompt edit to components that were missing
This commit is contained in:
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 {};
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user