VIAplanner/via-timetable

View on GitHub
src/store/index.js

Summary

Maintainability
F
2 wks
Test Coverage
import Vue from 'vue';
import Vuex from 'vuex';
import genColor from 'color-generator';
import { generateTimetables } from '../timetable-planner/index2';
// import colorDiff from "color-difference"

Vue.use(Vuex);
const darkSaturation = 0.4;
const darkLightness = 0.3;
const lightSaturation = 0.8;
const lightLightness = 0.85;
const addHistory = (state, history) => {
    if (state.historyIndex !== 0) {
      state.history = state.history.slice(0, state.history.length + state.historyIndex);
      state.historyIndex = 0;
    }
    state.history.push(history);
};
const saveState = (state) => {
  addHistory(state, JSON.stringify({
      fallSelectedCourses: state.fallSelectedCourses,
      winterSelectedCourses: state.winterSelectedCourses,
      fallTimetable: state.fallTimetable,
      winterTimetable: state.winterTimetable,
      fallLockedSections: state.fallLockedSections,
      winterLockedSections: state.winterLockedSections,
      deliveryMethod: state.deliveryMethod,
      allowedConflictCourses: state.allowedConflictCourses,
      darkMode: state.darkMode,
    }));
};
const regenerateColors = (state) => {
  Object.values(state.fallSelectedCourses).forEach((course) => {
    course.color = genColor(state.darkMode ? darkSaturation : lightSaturation, state.darkMode ? darkLightness : lightLightness).hexString();
  });
  Object.values(state.winterSelectedCourses).forEach((course) => {
    course.color = genColor(state.darkMode ? darkSaturation : lightSaturation, state.darkMode ? darkLightness : lightLightness).hexString();
  });
};
export default new Vuex.Store({
  state: {
    darkMode: localStorage.darkMode === 'true',
    // change this number to clear storage
    clearStorage: '2',
    allowedConflictCourses: !localStorage.allowedConflictCourses
      ? []
      : JSON.parse(localStorage.allowedConflictCourses),
    fallLockedHourStatus: !localStorage.fallLockedHourStatus
      ? {
          '8 AM': false,
          '9 AM': false,
          '10 AM': false,
          '11 AM': false,
          '12 PM': false,
          '1 PM': false,
          '2 PM': false,
          '3 PM': false,
          '4 PM': false,
          '5 PM': false,
          '6 PM': false,
          '7 PM': false,
          '8 PM': false,
          '9 PM': false,
        }
      : JSON.parse(localStorage.fallLockedHourStatus),
    fallLockedDayStatus: !localStorage.fallLockedDayStatus
      ? {
          Monday: false,
          Tuesday: false,
          Wednesday: false,
          Thursday: false,
          Friday: false,
        }
      : JSON.parse(localStorage.fallLockedDayStatus),
    fallSelectedCourses: !localStorage.fallSelectedCourses
      ? {}
      : JSON.parse(localStorage.fallSelectedCourses),
    fallLockedSections: !localStorage.fallLockedSections
      ? []
      : JSON.parse(localStorage.fallLockedSections),
    fallTimetable: !localStorage.fallTimetable
      ? {
          MONDAY: [],
          TUESDAY: [],
          WEDNESDAY: [],
          THURSDAY: [],
          FRIDAY: [],
        }
      : JSON.parse(localStorage.fallTimetable),
    winterLockedHourStatus: !localStorage.winterLockedHourStatus
      ? {
          '8 AM': false,
          '9 AM': false,
          '10 AM': false,
          '11 AM': false,
          '12 PM': false,
          '1 PM': false,
          '2 PM': false,
          '3 PM': false,
          '4 PM': false,
          '5 PM': false,
          '6 PM': false,
          '7 PM': false,
          '8 PM': false,
          '9 PM': false,
        }
      : JSON.parse(localStorage.winterLockedHourStatus),
    winterLockedDayStatus: !localStorage.winterLockedDayStatus
      ? {
          Monday: false,
          Tuesday: false,
          Wednesday: false,
          Thursday: false,
          Friday: false,
        }
      : JSON.parse(localStorage.winterLockedDayStatus),
    winterSelectedCourses: !localStorage.winterSelectedCourses
      ? {}
      : JSON.parse(localStorage.winterSelectedCourses),
    winterLockedSections: !localStorage.winterLockedSections
      ? []
      : JSON.parse(localStorage.winterLockedSections),
    winterTimetable: !localStorage.winterTimetable
      ? {
          MONDAY: [],
          TUESDAY: [],
          WEDNESDAY: [],
          THURSDAY: [],
          FRIDAY: [],
        }
      : JSON.parse(localStorage.winterTimetable),
    exportOverlay: false,
    conflictPopup: false,
    searchBarValue: null,
    savedFallTimetable: {},
    savedWinterTimetable: {},
    savedFallSelectedCourses: {},
    savedWinterSelectedCourses: {},
    savedFallLockedSections: [],
    savedWinterLockedSections: [],
    savedLockedHourStatus: {
      '8 AM': false,
      '9 AM': false,
      '10 AM': false,
      '11 AM': false,
      '12 PM': false,
      '1 PM': false,
      '2 PM': false,
      '3 PM': false,
      '4 PM': false,
      '5 PM': false,
      '6 PM': false,
      '7 PM': false,
      '8 PM': false,
      '9 PM': false,
    },
    savedLockedDayStatus: {
      MONDAY: false,
      TUESDAY: false,
      WEDNESDAY: false,
      THURSDAY: false,
      FRIDAY: false,
    },
    semesterStatus: 'F',
    noTimetablePopup: false,
    shareLinkPopup: false,
    shareLink:'',
    overwriteLockedSectionPopup: false,
    tutorialPopup: !localStorage.visited,
    deliveryMethod: 'Mixed',
    globalAllowConflicts: false,
    history:  [],
    // index is reversed, 0 is the latest, 1 is the second latest etc...
    historyIndex: 0,
  },
  mutations: {
    setDarkMode(state, payload) {
      state.darkMode = payload;
      regenerateColors(state);
      saveState(state);
    },
    setExportOverlay(state, payload) {
      state.exportOverlay = payload;
    },
    setLockedHourStatus(state, payload) {
      if (state.semesterStatus === 'F') {
        state.fallLockedHourStatus[payload] = !state.fallLockedHourStatus[
          payload
        ];
      } else {
        state.winterLockedHourStatus[payload] = !state.winterLockedHourStatus[
          payload
        ];
      }
    },
    setLockedDayStatus(state, payload) {
      if (state.semesterStatus === 'F') {
        state.fallLockedDayStatus[payload] = !state.fallLockedDayStatus[
          payload
        ];
      } else {
        state.winterLockedDayStatus[payload] = !state.winterLockedDayStatus[
          payload
        ];
      }
    },
    setTutorialPopup(state, payload) {
      state.tutorialPopup = payload;
    },
    setSemesterStatus(state, payload) {
      state.semesterStatus = payload;
    },
    setSearchBarValue(state, payload) {
      state.searchBarValue = payload;
    },
    setTimetables(state, payload) {
      [state.fallTimetable, state.winterTimetable] = payload;
    },
    setNoTimetablePopup(state, payload) {
      state.noTimetablePopup = payload;
    },
    setShareLinkPopup(state, payload) {
      state.shareLinkPopup = payload;
    },
    setShareLink(state, payload) {
      state.shareLink = payload;
    },
    setOverwriteLockedSectionPopup(state, payload) {
      state.overwriteLockedSectionPopup = payload;
    },
    addCourse(state, payload) {
      if(state.globalAllowConflicts){
        state.allowedConflictCourses.push({code:payload.course.courseCode});
      }
      if (payload.course.courseCode.slice(0, 4) === 'Lock') {
        const whichDay = payload.course.meeting_sections[0].times[0].day;

        if (state.semesterStatus === 'F') {
          // already in the timetable
          if (payload.course.courseCode in state.fallSelectedCourses) {
            return;
          }

          state.fallSelectedCourses[payload.course.courseCode] = payload.course;

          // Add new section into timetable
          state.fallTimetable[whichDay].push({
            code: payload.course.courseCode,
            sectionCode: payload.course.meeting_sections[0].sectionCode,
            instructors: payload.course.meeting_sections[0].instructors[0],
            ...payload.course.meeting_sections[0].times[0],
          });

          // sort it
          state.fallTimetable[whichDay].sort((a, b) => a.start - b.start);
        } else {
          // already in the timetable
          if (payload.course.courseCode in state.winterSelectedCourses) {
            return;
          }

          state.winterSelectedCourses[payload.course.courseCode] =
            payload.course;

          // Add new section into timetable
          state.winterTimetable[whichDay].push({
            code: payload.course.courseCode,
            sectionCode: payload.course.meeting_sections[0].sectionCode,
            instructors: payload.course.meeting_sections[0].instructors[0],
            ...payload.course.meeting_sections[0].times[0],
          });

          // sort it
          state.winterTimetable[whichDay].sort((a, b) => a.start - b.start);
        }
      } else if (payload.course.courseCode[8] === 'F') {
        state.fallSelectedCourses[payload.course.courseCode] = payload.course;
      } else if (payload.course.courseCode[8] === 'S') {
        state.winterSelectedCourses[payload.course.courseCode] = payload.course;
      } else if (payload.course.courseCode[8] === 'Y') {
        state.fallSelectedCourses[payload.course.courseCode] = payload.course;
        state.winterSelectedCourses[payload.course.courseCode] = payload.course;
      }
    },
    removeCourse(state, payload) {
      if (payload.code.slice(0, 4) === 'Lock') {
        if (payload.code[4] === 'F') {
          Vue.delete(state.fallSelectedCourses, payload.code);
        } else {
          Vue.delete(state.winterSelectedCourses, payload.code);
        }
      } else if (payload.code[8] === 'F') {
        Vue.delete(state.fallSelectedCourses, payload.code);
      } else if (payload.code[8] === 'S') {
        Vue.delete(state.winterSelectedCourses, payload.code);
      } else if (payload.code[8] === 'Y') {
        Vue.delete(state.fallSelectedCourses, payload.code);
        Vue.delete(state.winterSelectedCourses, payload.code);
      }
    },
    // Todo
    setLockedSections(state, payload) {
      [state.fallLockedSections, state.winterLockedSections] = payload;
    },
    // Todo
    setSelectedCourses(state, payload) {
      [state.fallSelectedCourses, state.winterSelectedCourses] = payload;
    },
    addOrRemoveConflictCourse(state, payload) {
      const index = state.allowedConflictCourses.findIndex(
        course => course.code === payload.code,
      );
      if (index === -1) {
        state.allowedConflictCourses.push(payload);
      } else {
        state.allowedConflictCourses.splice(index, 1);
      }
    },
    lockSection(state, payload) {
      let index;
      if (payload.slice(0, 4) === 'Lock') {
        if (payload[4] === 'F') {
          index = state.fallLockedSections.indexOf(payload);
          if (index === -1) {
            state.fallLockedSections.push(payload);
          }
        } else {
          index = state.winterLockedSections.indexOf(payload);
          if (index === -1) {
            state.winterLockedSections.push(payload);
          }
        }
      } else if (payload[8] === 'F') {
        index = state.fallLockedSections.indexOf(payload);
        if (index === -1) {
          state.fallLockedSections.push(payload);
        }
      } else if (payload[8] === 'S') {
        index = state.winterLockedSections.indexOf(payload);
        if (index === -1) {
          state.winterLockedSections.push(payload);
        }
      } else if (payload[8] === 'Y') {
        index = state.fallLockedSections.indexOf(payload);
        if (index === -1) {
          state.fallLockedSections.push(payload);
          state.winterLockedSections.push(payload);
        }
      }
      saveState(state);
    },
    unlockSection(state, payload) {
      let index;
      if (payload.slice(0, 4) === 'Lock') {
        // Block hour
        if (payload[4] === 'F') {
          index = state.fallLockedSections.indexOf(payload);
          if (index !== -1) {
            state.fallLockedSections.splice(index, 1);
          }
        } else {
          index = state.winterLockedSections.indexOf(payload);
          if (index !== -1) {
            state.winterLockedSections.splice(index, 1);
          }
        }
      } else if (payload[8] === 'F') {
        // Fall
        index = state.fallLockedSections.indexOf(payload);
        if (index !== -1) {
          state.fallLockedSections.splice(index, 1);
        }
      } else if (payload[8] === 'S') {
        // Winter
        index = state.winterLockedSections.indexOf(payload);
        if (index !== -1) {
          state.winterLockedSections.splice(index, 1);
        }
      } else if (payload[8] === 'Y') {
        // Year
        index = state.fallLockedSections.indexOf(payload);
        if (index !== -1) {
          state.fallLockedSections.splice(index, 1);
          index = state.winterLockedSections.indexOf(payload);
          state.winterLockedSections.splice(index, 1);
        }
      }
    },
    setPreferredDeliveryMethod(state, payload) {
      state.deliveryMethod = payload;
    },
    setGlobalAllowConflicts(state, payload) {
      state.globalAllowConflicts = payload;
    },
    addHistory(state, payload) {
      addHistory(state, payload);
    },
    saveState(state){
      saveState(state);
    },
    loadState(state, payload) {
      const newState = JSON.parse(payload);
      state.fallSelectedCourses = newState.fallSelectedCourses;
      state.winterSelectedCourses = newState.winterSelectedCourses;
      state.fallTimetable = newState.fallTimetable;
      state.winterTimetable = newState.winterTimetable;
      state.fallLockedSections = newState.fallLockedSections;
      state.winterLockedSections = newState.winterLockedSections;
      state.deliveryMethod = newState.deliveryMethod;
      state.allowedConflictCourses = newState.allowedConflictCourses;
      state.searchBarValue = '';
      if(state.darkMode !== newState.darkMode) {
        regenerateColors(state);
      }
    },
    undo(state) {
      state.historyIndex -= 1;
    },
    redo(state) {
      state.historyIndex += 1;
    },
    regenerateColors(state) {
      regenerateColors(state);
    },
  },
  actions: {
    clearStorage(context) {
      context.state.fallLockedHourStatus = {
        '8 AM': false,
        '9 AM': false,
        '10 AM': false,
        '11 AM': false,
        '12 PM': false,
        '1 PM': false,
        '2 PM': false,
        '3 PM': false,
        '4 PM': false,
        '5 PM': false,
        '6 PM': false,
        '7 PM': false,
        '8 PM': false,
        '9 PM': false,
      };
      context.state.fallLockedDayStatus = {
        Monday: false,
        Tuesday: false,
        Wednesday: false,
        Thursday: false,
        Friday: false,
      };
      context.state.fallSelectedCourses = {};
      context.state.fallLockedSections = [];
      context.state.fallTimetable = {
        MONDAY: [],
        TUESDAY: [],
        WEDNESDAY: [],
        THURSDAY: [],
        FRIDAY: [],
      };
      context.state.winterLockedHourStatus = {
        '8 AM': false,
        '9 AM': false,
        '10 AM': false,
        '11 AM': false,
        '12 PM': false,
        '1 PM': false,
        '2 PM': false,
        '3 PM': false,
        '4 PM': false,
        '5 PM': false,
        '6 PM': false,
        '7 PM': false,
        '8 PM': false,
        '9 PM': false,
      };
      context.state.winterLockedDayStatus = {
        Monday: false,
        Tuesday: false,
        Wednesday: false,
        Thursday: false,
        Friday: false,
      };
      context.state.winterSelectedCourses = {};
      context.state.winterLockedSections = [];
      context.state.winterTimetable = {
        MONDAY: [],
        TUESDAY: [],
        WEDNESDAY: [],
        THURSDAY: [],
        FRIDAY: [],
      };
      context.state.tutorialPopup = false;
    },
    saveTimetable(context) {
      context.state.savedFallTimetable = JSON.parse(
        JSON.stringify(context.state.fallTimetable),
      );
      context.state.savedWinterTimetable = JSON.parse(
        JSON.stringify(context.state.winterTimetable),
      );
      context.state.savedFallSelectedCourses = JSON.parse(
        JSON.stringify(context.state.fallSelectedCourses),
      );
      context.state.savedWinterSelectedCourses = JSON.parse(
        JSON.stringify(context.state.winterSelectedCourses),
      );
      context.state.savedFallLockedSections = [
        ...context.state.fallLockedSections,
      ];
      context.state.savedWinterLockedSections = [
        ...context.state.winterLockedSections,
      ];
    },
    saveLockedDayStatus(context) {
      if (context.state.semesterStatus === 'F') {
        context.state.savedLockedDayStatus = JSON.parse(
          JSON.stringify(context.state.fallLockedDayStatus),
        );
      } else {
        context.state.savedLockedDayStatus = JSON.parse(
          JSON.stringify(context.state.winterLockedDayStatus),
        );
      }
    },
    saveLockedHourStatus(context) {
      if (context.state.semesterStatus === 'F') {
        context.state.savedLockedHourStatus = JSON.parse(
          JSON.stringify(context.state.fallLockedHourStatus),
        );
      } else {
        context.state.savedLockedHourStatus = JSON.parse(
          JSON.stringify(context.state.winterLockedHourStatus),
        );
      }
    },
    revertTimetable(context) {
      context.commit('setTimetables', [
        context.state.savedFallTimetable,
        context.state.savedWinterTimetable,
      ]);
      context.commit('setSelectedCourses', [
        context.state.savedFallSelectedCourses,
        context.state.savedWinterSelectedCourses,
      ]);
      context.commit('setLockedSections', [
        context.state.savedFallLockedSections,
        context.state.savedWinterLockedSections,
      ]);
      if (context.state.semesterStatus === 'F') {
        context.state.fallLockedHourStatus =
          context.state.savedLockedHourStatus;
        context.state.fallLockedDayStatus = context.state.savedLockedDayStatus;
      } else {
        context.state.winterLockedHourStatus =
          context.state.savedLockedHourStatus;
        context.state.winterLockedDayStatus =
          context.state.savedLockedDayStatus;
      }
    },
    validateTimetable(context, payload) {
      if (payload === null) {
        context.commit('setSearchBarValue', null);
        context.commit('setNoTimetablePopup', true);
        context.dispatch('revertTimetable');
      } else {
        context.commit('setTimetables', payload);
      }
    },
    selectCourse(context, payload) {
      // save the previous timetable by default
      if (!payload.noSave) {
        context.dispatch('saveTimetable');
      }

      // generate a color
      const color = genColor(context.state.darkMode ? darkSaturation : lightSaturation, context.state.darkMode ? darkLightness : lightLightness).hexString();
      // let currSemCourses

      // if (context.state.semesterStatus === "F") {
      //     currSemCourses = context.state.fallSelectedCourses;
      // } else {
      //     currSemCourses = context.state.winterSelectedCourses;
      // }

      // let inValid = true
      // while (inValid) {
      //     inValid = false
      //     for (let courseCode in currSemCourses) {
      //         if (colorDiff.compare(color, currSemCourses[courseCode].color) < 50) {
      //             inValid = true
      //             color = genColor(0.7, 0.85).hexString();
      //             break
      //         }
      //     }
      // }

      // Add the course
      context.commit('addCourse', {
        course: {
          color,
          ...payload.course,
        },
      });

      const fallCourses = Object.keys(context.state.fallSelectedCourses).map(
        code => context.state.fallSelectedCourses[code],
      );
      const winterCourses = Object.keys(
        context.state.winterSelectedCourses,
      ).map(code => context.state.winterSelectedCourses[code]);

      const timetables = generateTimetables(
        fallCourses,
        context.state.fallLockedSections,
        winterCourses,
        context.state.winterLockedSections,
        context.state.deliveryMethod,
        context.state.allowedConflictCourses,
      );

      context.dispatch('validateTimetable', timetables);
      context.dispatch('saveState');
    },
    deleteCourse(context, payload) {
      // resets search bar value if the deleted course is the last searched course
      if (
        context.state.searchBarValue !== null &&
        context.state.searchBarValue.includes(payload.code)
      ) {
        context.commit('setSearchBarValue', null);
      }

      // Remove course
      context.commit('removeCourse', payload);

      // Remove from allowed conflict courses
      if (
        context.state.allowedConflictCourses.findIndex(
          course => course.code === payload.code,
        ) !== -1
      ) {
        context.commit('addOrRemoveConflictCourse', payload);
      }

      // Unlock all sections of the deleted course
      for (const lockedSection of context.state.fallLockedSections) {
        if (lockedSection.includes(payload.code)) {
          context.commit('unlockSection', lockedSection);
        }
      }
      for (const lockedSection of context.state.winterLockedSections) {
        if (lockedSection.includes(payload.code)) {
          context.commit('unlockSection', lockedSection);
        }
      }

      // Remove all sections of the deleted course from the correct timetable
      if (payload.code.includes('Lock')) {
        if (payload.code[4] === 'F') {
          for (const day in context.state.fallTimetable) {
            const dayEvents = context.state.fallTimetable[day];
            for (let i = dayEvents.length - 1; i >= 0; i -= 1) {
              if (dayEvents[i].code === payload.code) {
                dayEvents.splice(i, 1);
                break;
              }
            }
          }
        } else {
          for (const day in context.state.winterTimetable) {
            const dayEvents = context.state.winterTimetable[day];
            for (let i = dayEvents.length - 1; i >= 0; i -= 1) {
              if (dayEvents[i].code === payload.code) {
                dayEvents.splice(i, 1);
                break;
              }
            }
          }
        }
      } else {
        for (const day in context.state.fallTimetable) {
          const dayEvents = context.state.fallTimetable[day];
          for (let i = dayEvents.length - 1; i >= 0; i -= 1) {
            if (dayEvents[i].code === payload.code) {
              dayEvents.splice(i, 1);
            }
          }
        }
        for (const day in context.state.winterTimetable) {
          const dayEvents = context.state.winterTimetable[day];
          for (let i = dayEvents.length - 1; i >= 0; i -= 1) {
            if (dayEvents[i].code === payload.code) {
              dayEvents.splice(i, 1);
            }
          }
        }
      }
      context.dispatch('saveState');
    },
    // Recalculate timetable when switching sections with conflict
    resetTimetable(context, payload) {
      if (!payload) {
        context.dispatch('saveTimetable');
      }

      const fallCourses = Object.keys(context.state.fallSelectedCourses).map(
        code => context.state.fallSelectedCourses[code],
      );
      const winterCourses = Object.keys(
        context.state.winterSelectedCourses,
      ).map(code => context.state.winterSelectedCourses[code]);

      const bothTimetables = generateTimetables(
        fallCourses,
        context.state.fallLockedSections,
        winterCourses,
        context.state.winterLockedSections,
        context.state.deliveryMethod,
        context.state.allowedConflictCourses,
      );

      context.dispatch('validateTimetable', bothTimetables);
    },
    // Switch a section of a course when there is no conflict
    switchSection(context, payload) {
      // Remove old section from locked sections
      context.commit(
        'unlockSection',
        `${payload.old.courseCode}${payload.old.sectionCode}`,
      );

      const whichSemesters = [];
      if (payload.old.courseCode[8] === 'F') {
        whichSemesters.push(context.state.fallTimetable);
      } else if (payload.old.courseCode[8] === 'S') {
        whichSemesters.push(context.state.winterTimetable);
      } else {
        whichSemesters.push(context.state.fallTimetable);
        whichSemesters.push(context.state.winterTimetable);
      }

      for (const semester of whichSemesters) {
        // Remove old section from timetable
        for (const d in semester) {
          const day = semester[d];
          for (let i = day.length - 1; i >= 0; i -= 1) {
            if (
              `${day[i].code}${day[i].sectionCode}` ===
              `${payload.old.courseCode}${payload.old.sectionCode}`
            ) {
              day.splice(i, 1);
            }
          }
        }
        // Add new section into timetable
        for (const time of payload.new.times) {
          semester[time.day].push({
            code: payload.old.courseCode,
            sectionCode: payload.new.sectionCode,
            instructors: payload.new.instructors,
            ...time,
          });
          semester[time.day].sort((a, b) => a.start - b.start);
        }
      }
    },
    saveState({commit}) {
      commit('saveState');
    },
    undo(context) {
      if (context.state.history.length - 1 + context.state.historyIndex > 0) {
        context.commit('undo');
        context.commit('loadState', context.state.history[context.state.history.length - 1 + context.state.historyIndex]);
      }
    },
    redo(context) {
      if (context.state.historyIndex < 0) {
        const state=  context.state.history[context.state.history.length + context.state.historyIndex];
        context.commit('redo');
        context.commit('loadState',state );
      }
    },
  },
  modules: {},
  getters: {
    getSerializedState: state => state.history[state.history.length - 1 + state.historyIndex],
    getExportOverlay: state => state.exportOverlay,
    getNoTimetablePopup: state => state.noTimetablePopup,
    getShareLinkPopup: state => state.shareLinkPopup,
    getShareLink: state => state.shareLink,
    getOverwriteLockedSectionPopup: state => state.overwriteLockedSectionPopup,
    getTutorialPopup(state) {
      return state.tutorialPopup;
    },
    timetable: state => {
      if (state.semesterStatus === 'F') {
        return state.fallTimetable;
      } else {
        return state.winterTimetable;
      }
    },
    fallTimetable: state => state.fallTimetable,
    winterTimetable: state => state.winterTimetable,
    selectedCourses: state => whichSemester => {
      if (whichSemester === 'F') {
        return state.fallSelectedCourses;
      } else if (whichSemester === 'S') {
        return state.winterSelectedCourses;
      }
      if (state.semesterStatus === 'F') {
        return state.fallSelectedCourses;
      } else {
        return state.winterSelectedCourses;
      }
    },
    isConflictedCourse: state => courseCode =>
      state.allowedConflictCourses.findIndex(
        curCourse => curCourse.code === courseCode,
      ) !== -1,
    fallSelectedCourses: state => state.fallSelectedCourses,
    winterSelectedCourses: state => state.winterSelectedCourses,
    getLockedSections: state => {
      if (state.semesterStatus === 'F') {
        return state.fallLockedSections;
      } else {
        return state.winterLockedSections;
      }
    },
    fallLockedSections: state => state.fallLockedSections,
    allowedConflictCourses: state => state.allowedConflictCourses,
    winterLockedSections: state => state.winterLockedSections,
    getCourseColor: state => code => {
      if (code[8] === 'F') {
        return state.fallSelectedCourses[code].color;
      } else {
        return state.winterSelectedCourses[code].color;
      }
    },
    getSearchBarValue: state => state.searchBarValue,
    getSemesterStatus: state => state.semesterStatus,
    getLockedDayStatus: state => {
      if (state.semesterStatus === 'F') {
        return state.fallLockedDayStatus;
      } else {
        return state.winterLockedDayStatus;
      }
    },
    getLockedHourStatus: state => {
      if (state.semesterStatus === 'F') {
        return state.fallLockedHourStatus;
      } else {
        return state.winterLockedHourStatus;
      }
    },
    getFallLockedHourStatus: state => state.fallLockedHourStatus,
    getWinterLockedHourStatus: state => state.winterLockedHourStatus,
    getFallLockedDayStatus: state => state.fallLockedDayStatus,
    getWinterLockedDayStatus: state => state.winterLockedDayStatus,
    getClearStorage: state => state.clearStorage,
    getGlobalAllowConflicts: state => state.globalAllowConflicts,
    getHistoryLength: state => state.history.length,
    getWarningSections: state => {
      const timetable = state.semesterStatus === 'F' ? state.fallTimetable : state.winterTimetable;
      const selected = state.semesterStatus === 'F' ? state.fallSelectedCourses : state.winterSelectedCourses;
      const sections = new Set();
      Object.values(timetable).forEach(arr =>{
        arr.forEach(section => sections.add(`${section.code} ${section.sectionCode}`));
      })
      const warningSections = [];
      sections.forEach(x=>{
        const splitted = x.split(' ');
        if (selected[splitted[0]].meeting_sections.find(section => section.sectionCode === splitted[1]).openLimitInd === 'C') {
          warningSections.push(x);
        }
      })
      return warningSections.map(x => {
        const splitted = x.split(' ');
        return { code: splitted[0], sectionCode: splitted[1] };
      });
    }
  },
});