diff --git a/package.json b/package.json
index 3f63c984..61d3022e 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,6 @@
"@testing-library/user-event": "^12.0.2",
"array-move": "^4.0.0",
"axios": "^0.24.0",
- "chart.js": "^3.7.0",
"color-hash": "^2.0.1",
"dotenv-defaults": "^3.0.0",
"focus-visible": "^5.2.0",
@@ -21,7 +20,6 @@
"moment": "^2.29.1",
"randomcolor": "^0.6.2",
"react": "^17.0.2",
- "react-chartjs-2": "^4.0.1",
"react-copy-to-clipboard": "^5.0.4",
"react-countdown-hook": "^1.1.1",
"react-dom": "^17.0.2",
@@ -30,7 +28,6 @@
"react-icons": "^3.0.0",
"react-loading-overlay": "^1.0.1",
"react-minimal-pie-chart": "^8.2.0",
- "react-redux": "^7.2.6",
"react-router-dom": "6",
"react-scripts": "4.0.3",
"react-scroll": "^1.8.4",
@@ -39,9 +36,8 @@
"react-spinners": "^0.11.0",
"react-table-drag-select": "^0.3.1",
"react-use": "^17.4.0",
- "redux": "^4.1.2",
- "redux-thunk": "^2.4.1",
"uuid": "^8.3.2",
+ "valtio": "^1.6.1",
"web-vitals": "^0.2.2"
},
"scripts": {
diff --git a/src/App.js b/src/App.js
index 1f66932c..85cab96f 100644
--- a/src/App.js
+++ b/src/App.js
@@ -15,6 +15,10 @@ import CourseInfoContainer from "containers/CourseInfoContainer";
import { useParams } from "react-router-dom";
import ReactGA from "react-ga";
import RecruitingPageContainer from "containers/RecruitingPageContainer";
+import { UserDataProvider } from "components/Providers/UserProvider";
+import { CourseSearchingProvider } from "components/Providers/CourseSearchingProvider";
+import { DisplayTagsProvider } from "components/Providers/DisplayTagsProvider";
+import { CourseTableProvider } from "components/Providers/CourseTableProvider";
dotenv.config();
@@ -59,11 +63,19 @@ function App(props) {
cacheLocation={"localstorage"}
>
-
-
- {content(props.route)}
-
-
+
+
+
+
+
+
+ {content(props.route)}
+
+
+
+
+
+
);
diff --git a/src/actions/course_tables.js b/src/actions/course_tables.js
deleted file mode 100644
index af6a5587..00000000
--- a/src/actions/course_tables.js
+++ /dev/null
@@ -1,159 +0,0 @@
-import { UPDATE_COURSE_TABLE } from "constants/action-types";
-import instance from "api/axios";
-
-const createCourseTable = (course_table_id, course_table_name, user_id, semester) => async (dispatch) => {
- try {
- const {
- data: { course_table },
- } = await instance.post(`/course_tables/`, { id: course_table_id, name: course_table_name, user_id: user_id, semester: semester });
- dispatch({ type: UPDATE_COURSE_TABLE, payload: course_table });
- return course_table;
- } catch (error) {
- // console.log(Error("Error in createCourseTable: "+error));
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const fetchCourseTable = (course_table_id) => async (dispatch) => {
- try {
- const {
- data: { course_table },
- } = await instance.get(`/course_tables/${course_table_id}`);
- dispatch({ type: UPDATE_COURSE_TABLE, payload: course_table });
- return course_table;
- } catch (error) {
- // console.log(Error("Error in fetchCourseTable: "+error));
-
- if (error.response) {
- if (error.response.status === 403 || error.response.status === 404) {
- // expired course_table
- // if fetch expired course_table, return null and handle it by frontend logic
- dispatch({ type: UPDATE_COURSE_TABLE, payload: null });
- return null;
- }
- } else {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
- }
-};
-
-const patchCourseTable = (course_table_id, course_table_name, user_id, expire_ts, courses) => async (dispatch) => {
- // filter out "" in courses
- const new_courses = courses.filter((course) => course !== "");
- try {
- const {
- data: { course_table },
- } = await instance.patch(`/course_tables/${course_table_id}`, {
- name: course_table_name,
- user_id: user_id,
- expire_ts: expire_ts,
- courses: new_courses,
- });
- dispatch({ type: UPDATE_COURSE_TABLE, payload: course_table });
- return course_table;
- } catch (error) {
- // console.log(Error("Error in patchCourseTable: "+error));
-
- // need to let frontend handle error, so change to return null
- if (error.response) {
- if (error.response.status === 403 && error.response.data.message === "Course table is expired") {
- // expired course_table
- // if fetch expired course_table, return null and handle it by frontend logic
- dispatch({ type: UPDATE_COURSE_TABLE, payload: null });
- return null;
- }
- } else {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
- }
-};
-
-export { createCourseTable, fetchCourseTable, patchCourseTable };
diff --git a/src/actions/courses.js b/src/actions/courses.js
deleted file mode 100644
index df87d17e..00000000
--- a/src/actions/courses.js
+++ /dev/null
@@ -1,469 +0,0 @@
-import {
- FETCH_SEARCH_RESULTS_FAILURE,
- FETCH_SEARCH_RESULTS_SUCCESS,
- FETCH_SEARCH_RESULTS_REQUEST,
- FETCH_SEARCH_IDS_FAILURE,
- FETCH_SEARCH_IDS_REQUEST,
- FETCH_SEARCH_IDS_SUCCESS,
- INCREMENT_OFFSET,
- UPDATE_TOTAL_COUNT,
-} from "constants/action-types";
-import instance from "api/axios";
-
-const fetchSearchIDs = (searchString, paths, filters_enable, filter_obj, batch_size, strict_match_bool) => async (dispatch) => {
- dispatch({ type: FETCH_SEARCH_IDS_REQUEST });
-
- try {
- const {
- data: { ids },
- } = await instance.post(`/courses/search`, { query: searchString, paths: paths });
- // console.log(ids); // checking receive array of courses
- dispatch({ type: FETCH_SEARCH_IDS_SUCCESS, payload: ids });
-
- // fetch batch 0 first
- dispatch({ type: FETCH_SEARCH_RESULTS_REQUEST });
- try {
- const search_filter = { ...filter_obj, strict_match: strict_match_bool };
- if (filters_enable.time === false) {
- search_filter.time = null;
- }
- if (filters_enable.department === false) {
- search_filter.department = null;
- }
- if (filters_enable.category === false) {
- search_filter.category = null;
- }
- if (filters_enable.enroll_method === false) {
- search_filter.enroll_method = null;
- }
- const {
- data: { courses, total_count },
- } = await instance.post(`/courses/ids`, { ids: ids, filter: search_filter, batch_size: batch_size, offset: 0 });
- dispatch({ type: FETCH_SEARCH_RESULTS_SUCCESS, payload: courses });
- // increment offset
- dispatch({ type: INCREMENT_OFFSET });
- // update total_results count
- dispatch({ type: UPDATE_TOTAL_COUNT, payload: total_count });
- } catch (error) {
- dispatch({ type: FETCH_SEARCH_RESULTS_FAILURE, payload: error });
- // console.log(Error("FETCH_SEARCH_RESULTS_FAILURE: "+error));
- throw error;
- }
-
- return ids;
- } catch (error) {
- dispatch({ type: FETCH_SEARCH_IDS_FAILURE, payload: error });
- // console.log(Error("FETCH_SEARCH_IDS_FAILURE: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const fetchSearchResults = (ids_arr, filters_enable, filter_obj, batch_size, offset, strict_match_bool) => async (dispatch) => {
- dispatch({ type: FETCH_SEARCH_RESULTS_REQUEST });
-
- try {
- const search_filter = { ...filter_obj, strict_match: strict_match_bool };
- if (filters_enable.time === false) {
- search_filter.time = null;
- }
- if (filters_enable.department === false) {
- search_filter.department = null;
- }
- if (filters_enable.category === false) {
- search_filter.category = null;
- }
- if (filters_enable.enroll_method === false) {
- search_filter.enroll_method = null;
- }
- const {
- data: { courses },
- } = await instance.post(`/courses/ids`, { ids: ids_arr, filter: search_filter, batch_size: batch_size, offset: offset });
- // console.log(courses); // checking receive array of courses
- dispatch({ type: FETCH_SEARCH_RESULTS_SUCCESS, payload: courses });
- // increment offset
- dispatch({ type: INCREMENT_OFFSET });
- return courses;
- } catch (error) {
- dispatch({ type: FETCH_SEARCH_RESULTS_FAILURE, payload: error });
- // console.log(Error("FETCH_SEARCH_RESULTS_FAILURE: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const fetchCourse = (id) => async (dispatch) => {
- try {
- const search_filter = { time: null, department: null, category: null, enroll_method: null, strict_match: false };
- const batch_size = 1;
- const offset = 0;
- const {
- data: { courses },
- } = await instance.post(`/courses/ids`, { ids: [id], filter: search_filter, batch_size: batch_size, offset: offset });
- const [course] = courses;
- return course;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const getCourseEnrollInfo = (token, course_id) => async (dispatch) => {
- try {
- const {
- data: { course_status },
- } = await instance.get(`/courses/${course_id}/enrollinfo`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- return course_status;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const getNTURatingData = (token, course_id) => async (dispatch) => {
- try {
- const {
- data: { course_rating },
- } = await instance.get(`/courses/${course_id}/rating`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- return course_rating;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const getPTTData = (token, course_id, type) => async (dispatch) => {
- try {
- const {
- data: { course_rating },
- } = await instance.get(`/courses/${course_id}/ptt/${type}`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- return course_rating;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const getCourseSyllabusData = (course_id) => async (dispatch) => {
- try {
- const {
- data: { course_syllabus },
- } = await instance.get(`/courses/${course_id}/syllabus`);
- return course_syllabus;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-// used in SideCourseTableContainer initialization, to fetch all course objects by ids
-const fetchCourseTableCoursesByIds = (ids_arr) => async (dispatch) => {
- try {
- const search_filter = { strict_match: false, time: null, department: null, category: null, enroll_method: null };
- const batch_size = 15000; // max batch size
- const offset = 0;
- const {
- data: { courses },
- } = await instance.post(`/courses/ids`, { ids: ids_arr, filter: search_filter, batch_size: batch_size, offset: offset });
- return courses;
- } catch (error) {
- // console.log(Error("Error in fetchCoursesByIds: "+error));
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-// used in userMyPage initialization, to fetch all favorite courses object by user's favorite courses ids
-const fetchFavoriteCourses = (ids_arr) => async (dispatch) => {
- try {
- const search_filter = { strict_match: false, time: null, department: null, category: null, enroll_method: null };
- const batch_size = 15000;
- const offset = 0;
- const {
- data: { courses },
- } = await instance.post(`/courses/ids`, { ids: ids_arr, filter: search_filter, batch_size: batch_size, offset: offset });
- return courses;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-export {
- fetchSearchIDs,
- fetchSearchResults,
- fetchCourse,
- getCourseEnrollInfo,
- getNTURatingData,
- getPTTData,
- getCourseSyllabusData,
- fetchCourseTableCoursesByIds,
- fetchFavoriteCourses,
-};
diff --git a/src/actions/index.js b/src/actions/index.js
deleted file mode 100644
index fe8dd4a3..00000000
--- a/src/actions/index.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import {
- SET_SEARCH_COLUMN,
- SET_SEARCH_SETTINGS,
- SET_BATCH_SIZE,
- SET_FILTERS,
- SET_FILTERS_ENABLE,
- UPDATE_COURSE_TABLE,
- LOG_IN_SUCCESS,
- LOG_OUT_SUCCESS,
- SET_DISPLAY_TAGS,
- SET_HOVER_COURSE,
-} from "constants/action-types";
-import instance from "api/axios";
-
-// normal actions
-const setSearchColumn = (col_name) => ({ type: SET_SEARCH_COLUMN, payload: col_name });
-const setSearchSettings = (setting_obj) => ({ type: SET_SEARCH_SETTINGS, payload: setting_obj });
-const setFilterEnable = (filter_name, enable) => ({ type: SET_FILTERS_ENABLE, filter_name: filter_name, payload: enable });
-const updateCourseTable = (course_table) => ({ type: UPDATE_COURSE_TABLE, payload: course_table });
-const logOut = () => ({ type: LOG_OUT_SUCCESS });
-const logIn = (user_data) => ({ type: LOG_IN_SUCCESS, payload: user_data });
-const setNewDisplayTags = (new_display_tags) => ({ type: SET_DISPLAY_TAGS, payload: new_display_tags });
-const setBatchSize = (new_batch_size) => ({ type: SET_BATCH_SIZE, payload: new_batch_size });
-const setHoveredCourse = (course) => ({ type: SET_HOVER_COURSE, payload: course });
-
-// data =
-// when filter_name == 'department', arr of dept_code (4-digits),
-// when filter_name == 'time', 2D array, each subarray have length == 15
-// when filter_name == 'category', arr of string (type of courses),
-// when filter_name == 'enroll_method', arr of string (type of enroll method)
-const setFilter = (filter_name, data) => ({ type: SET_FILTERS, filter_name: filter_name, payload: data });
-
-const verify_recaptcha = (captcha_token) => async (dispatch) => {
- const resp = await instance.post(`/recaptcha`, { captcha_token: captcha_token });
- return resp.data;
-};
-
-// add try catch block to handle timeout.
-const send_logs = (type, obj) => async (dispatch) => {
- if (process.env.REACT_APP_ENV === "prod") {
- const resp = await instance.post(`/logs/${type}`, obj);
- return resp.data;
- } else {
- console.log("[INFO] Logs are not sent to server in development mode.");
- }
-};
-
-export {
- setSearchColumn,
- setSearchSettings,
- logOut,
- logIn,
- updateCourseTable,
- verify_recaptcha,
- setNewDisplayTags,
- send_logs,
- setFilter,
- setFilterEnable,
- setBatchSize,
- setHoveredCourse,
-};
diff --git a/src/actions/social.js b/src/actions/social.js
deleted file mode 100644
index db8c5bc1..00000000
--- a/src/actions/social.js
+++ /dev/null
@@ -1,279 +0,0 @@
-import instance from "api/axios";
-
-const getSocialPostByCourseId = (token, course_id) => async (dispatch) => {
- try {
- const {
- data: { posts },
- } = await instance.get(`/social/courses/${course_id}/posts`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- return posts;
- } catch (error) {
- console.log(error.response.status);
- if (error.response && error.response.status === 404) {
- return [];
- } else if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const getSocialPostByPostId = (token, post_id) => async (dispatch) => {
- try {
- const {
- data: { post },
- } = await instance.get(`/social/posts/${post_id}`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- return post;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const createSocialPost = (token, course_id, post) => async (dispatch) => {
- try {
- await instance.post(
- `/social/courses/${course_id}/posts`,
- {
- post: post,
- // includes: content, post_type, user_type
- },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const reportSocialPost = (token, post_id, report) => async (dispatch) => {
- try {
- await instance.post(
- `/social/posts/${post_id}/report`,
- {
- report: report,
- // includes: content, post_type, user_type
- },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const voteSocialPost = (token, post_id, type) => async (dispatch) => {
- try {
- await instance.patch(
- `/social/posts/${post_id}/votes`,
- {
- type: type,
- // includes: content, post_type, user_type
- },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const deleteSocialPost = (token, post_id) => async (dispatch) => {
- try {
- await instance.delete(`/social/posts/${post_id}/`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-export { getSocialPostByCourseId, getSocialPostByPostId, createSocialPost, reportSocialPost, voteSocialPost, deleteSocialPost };
diff --git a/src/actions/users.js b/src/actions/users.js
deleted file mode 100644
index 8cc6cc31..00000000
--- a/src/actions/users.js
+++ /dev/null
@@ -1,373 +0,0 @@
-import { UPDATE_USER, LOG_OUT_SUCCESS } from "constants/action-types";
-import instance from "api/axios";
-
-const linkCoursetableToUser = (token, course_table_id, user_id) => async (dispatch) => {
- try {
- const {
- data: { user },
- } = await instance.post(
- `/users/${user_id}/course_table`,
- { course_table_id: course_table_id },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- dispatch({ type: UPDATE_USER, payload: user });
- } catch (error) {
- // console.log(Error("Error in linkCoursetableToUser: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const fetchUserById = (token, user_id) => async (dispatch) => {
- try {
- const {
- data: { user },
- } = await instance.get(`/users/${user_id}`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- // user contains user in db & auth0, either null (not found) or an object.
- return user;
- } catch (error) {
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const registerNewUser = (token, email) => async (dispatch) => {
- try {
- const {
- data: { user },
- } = await instance.post(
- `/users/`,
- { user: { email: email } },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- // either null (not found) or an object.
- return user;
- } catch (error) {
- // console.log(Error("Error in registerNewUser: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const addFavoriteCourse = (token, new_favorite_list) => async (dispatch) => {
- try {
- const {
- data: { user },
- } = await instance.patch(
- `/users/`,
- { user: { favorites: new_favorite_list } },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- dispatch({ type: UPDATE_USER, payload: user });
- } catch (error) {
- // console.log(Error("Error in addFavoriteCourse: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const patchUserInfo = (token, updateObject) => async (dispatch) => {
- try {
- const {
- data: { user },
- } = await instance.patch(
- `/users/`,
- { user: updateObject },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- dispatch({ type: UPDATE_USER, payload: user });
- } catch (error) {
- // console.log(Error("Error in patchUserInfo: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const deleteUserProfile = (token) => async (dispatch) => {
- try {
- await instance.delete(`/users/profile`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- } catch (error) {
- // console.log(Error("Error in deleteUserProfile: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const deleteUserAccount = (token) => async (dispatch) => {
- try {
- await instance.delete(`/users/account`, {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- });
- dispatch({ type: LOG_OUT_SUCCESS });
- } catch (error) {
- // console.log(Error("Error in deleteUserAccount: "+error))
-
- if (error.response) {
- // server did response, used for handle custom error msg
- const error_obj = {
- status_code: error.response.status,
- backend_msg: error.response.data.message,
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else if (error.request) {
- // The request was made but no response was received (server is downed)
- const status = 521; // Server is down
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- } else {
- // Something happened in setting up the request that triggered an Error
- const status = 400; // Bad request
- const error_obj = {
- status_code: status,
- backend_msg: "no",
- error_info: error.message,
- error_detail: Error(error).stack,
- };
- throw error_obj;
- }
- }
-};
-
-const request_otp_code = (token, student_id) => async (dispatch) => {
- const resp = await instance.post(
- `/users/student_id/link`,
- { student_id: student_id },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- return resp.data;
-};
-
-const use_otp_link_student_id = (token, student_id, otp_code) => async (dispatch) => {
- const resp = await instance.post(
- `/users/student_id/link`,
- { student_id: student_id, otp_code: otp_code },
- {
- headers: {
- Authorization: `Bearer ${token}`,
- },
- }
- );
- return resp.data;
-};
-
-export {
- linkCoursetableToUser,
- fetchUserById,
- registerNewUser,
- addFavoriteCourse,
- patchUserInfo,
- deleteUserProfile,
- deleteUserAccount,
- request_otp_code,
- use_otp_link_student_id,
-};
diff --git a/src/components/CourseInfoRow.js b/src/components/CourseInfoRow.js
index 240ec02f..8578f83c 100644
--- a/src/components/CourseInfoRow.js
+++ b/src/components/CourseInfoRow.js
@@ -25,12 +25,13 @@ import {
import { CourseDrawerContainer } from "containers/CourseDrawerContainer";
import { FaPlus, FaHeart, FaInfoCircle } from "react-icons/fa";
import { info_view_map } from "data/mapping_table";
-import { useDispatch, useSelector } from "react-redux";
-import { fetchCourseTable, patchCourseTable } from "actions/course_tables";
-import { addFavoriteCourse } from "actions/users";
import { hash_to_color_hex } from "utils/colorAgent";
import { useAuth0 } from "@auth0/auth0-react";
import { useNavigate } from "react-router-dom";
+import { useUserData } from "components/Providers/UserProvider";
+import { useCourseTable } from "components/Providers/CourseTableProvider";
+import { addFavoriteCourse } from "queries/user";
+import { fetchCourseTable, patchCourseTable } from "queries/courseTable";
const LOCAL_STORAGE_KEY = "NTU_CourseNeo_Course_Table_Key";
@@ -56,9 +57,9 @@ function DeptBadge({ course }) {
}
function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayTable }) {
- const dispatch = useDispatch();
+ const { setCourseTable } = useCourseTable();
const navigate = useNavigate();
- const userInfo = useSelector((state) => state.user);
+ const { user: userInfo, setUser } = useUserData();
const [addingCourse, setAddingCourse] = useState(false);
const [addingFavoriteCourse, setAddingFavoriteCourse] = useState(false);
@@ -87,10 +88,15 @@ function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayT
if (uuid) {
// fetch course table from server
- let course_table;
+ let courseTable;
try {
- course_table = await dispatch(fetchCourseTable(uuid));
+ courseTable = await fetchCourseTable(uuid);
+ setCourseTable(courseTable);
} catch (error) {
+ if (error?.response?.status === 403 || error?.response?.status === 404) {
+ // expired
+ setCourseTable(null);
+ }
toast({
title: "取得課表資料失敗",
status: "error",
@@ -100,7 +106,7 @@ function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayT
setAddingCourse(false);
return;
}
- if (course_table === null) {
+ if (courseTable === null) {
// get course_tables/:id return null (expired)
// show error and break the function
toast({
@@ -114,13 +120,18 @@ function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayT
// fetch course table success
let res_table;
let operation_str;
- if (course_table.courses.includes(course._id)) {
+ if (courseTable.courses.includes(course._id)) {
// course is already in course table, remove it.
operation_str = "刪除";
- const new_courses = course_table.courses.filter((id) => id !== course._id);
+ const new_courses = courseTable.courses.filter((id) => id !== course._id);
try {
- res_table = await dispatch(patchCourseTable(uuid, course_table.name, course_table.user_id, course_table.expire_ts, new_courses));
+ res_table = await patchCourseTable(uuid, courseTable.name, courseTable.user_id, courseTable.expire_ts, new_courses);
+ setCourseTable(res_table);
} catch (error) {
+ if (error?.response?.status === 403 || error?.response?.status === 404) {
+ // expired
+ setCourseTable(null);
+ }
toast({
title: `刪除 ${course.course_name} 失敗`,
status: "error",
@@ -133,10 +144,15 @@ function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayT
} else {
// course is not in course table, add it.
operation_str = "新增";
- const new_courses = [...course_table.courses, course._id];
+ const new_courses = [...courseTable.courses, course._id];
try {
- res_table = await dispatch(patchCourseTable(uuid, course_table.name, course_table.user_id, course_table.expire_ts, new_courses));
+ res_table = await patchCourseTable(uuid, courseTable.name, courseTable.user_id, courseTable.expire_ts, new_courses);
+ setCourseTable(res_table);
} catch (error) {
+ if (error?.response?.status === 403 || error?.response?.status === 404) {
+ // expired
+ setCourseTable(null);
+ }
toast({
title: `新增 ${course.course_name} 失敗`,
status: "error",
@@ -150,7 +166,7 @@ function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayT
if (res_table) {
toast({
title: `已${operation_str} ${course.course_name}`,
- description: `課表: ${course_table.name}`,
+ description: `課表: ${courseTable.name}`,
status: "success",
duration: 3000,
isClosable: true,
@@ -191,7 +207,8 @@ function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayT
// API call
try {
const token = await getAccessTokenSilently();
- await dispatch(addFavoriteCourse(token, new_favorite_list, userInfo.db._id));
+ const updatedUser = await addFavoriteCourse(token, new_favorite_list, userInfo.db._id);
+ setUser(updatedUser);
toast({
title: `${op_name}最愛課程成功`,
//description: `請稍後再試`,
@@ -314,7 +331,7 @@ function CourseInfoRow({ courseInfo, selected, isfavorite, displayTags, displayT
- {"map" in info_view_map[tag] ? info_view_map[tag].map[courseInfo[tag]] : courseInfo[tag]}
+ {info_view_map?.[tag]?.map?.[courseInfo?.[tag]] ?? courseInfo?.[tag] ?? "未知"}
);
diff --git a/src/components/CourseSearchInput.js b/src/components/CourseSearchInput.js
index 246dea08..90e1cdc5 100644
--- a/src/components/CourseSearchInput.js
+++ b/src/components/CourseSearchInput.js
@@ -31,41 +31,53 @@ import {
} from "@chakra-ui/react";
import { Search2Icon, ChevronDownIcon } from "@chakra-ui/icons";
import { FaSearch, FaPlus, FaMinus, FaChevronDown } from "react-icons/fa";
-import { setSearchColumn, setSearchSettings, setFilter, setFilterEnable, setNewDisplayTags } from "actions/index";
-import { fetchSearchIDs } from "actions/courses";
import TimeFilterModal from "components/FilterModals/TimeFilterModal";
import DeptFilterModal from "components/FilterModals/DeptFilterModal";
import CategoryFilterModal from "components/FilterModals/CategoryFilterModal";
-import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { mapStateToTimeTable, mapStateToIntervals } from "utils/timeTableConverter";
import { info_view_map } from "data/mapping_table";
import { useMount } from "react-use";
+import { useCourseSearchingContext } from "components/Providers/CourseSearchingProvider";
+import { useDisplayTags } from "components/Providers/DisplayTagsProvider";
+import handleAPIError from "utils/handleAPIError";
+import { fetchSearchIDs, fetchSearchResults } from "queries/course";
function CourseSearchInputTextArea() {
const navigate = useNavigate();
const toast = useToast();
-
- const search_columns = useSelector((state) => state.search_columns);
- const search_filters = useSelector((state) => state.search_filters);
- const batch_size = useSelector((state) => state.batch_size);
- const strict_match = useSelector((state) => state.search_settings.strict_search_mode);
- const search_filters_enable = useSelector((state) => state.search_filters_enable);
+ const {
+ setSearchIds,
+ searchColumns,
+ searchFilters,
+ batchSize,
+ searchFiltersEnable,
+ searchSettings,
+ setSearchColumns,
+ setSearchResult,
+ setSearchLoading,
+ setSearchError,
+ setOffset,
+ setTotalCount,
+ } = useCourseSearchingContext();
const [search, setSearch] = useState("");
useMount(() => {
setSearch("");
});
- const dispatch = useDispatch();
-
const toggle_search_column = (e) => {
- dispatch(setSearchColumn(e.currentTarget.value));
+ const col_name = e.currentTarget.value;
+ if (searchColumns.includes(col_name)) {
+ setSearchColumns(searchColumns.filter((col) => col !== col_name));
+ } else {
+ setSearchColumns([...searchColumns, col_name]);
+ }
};
- const startSearch = () => {
- // console.log(search_columns);
- if (search_columns.length === 0) {
+ const startSearch = async () => {
+ // console.log(searchColumns);
+ if (searchColumns.length === 0) {
toast({
title: "搜尋失敗",
description: "您必須指定至少一個搜尋欄位",
@@ -76,8 +88,23 @@ function CourseSearchInputTextArea() {
return;
}
try {
- dispatch(fetchSearchIDs(search, search_columns, search_filters_enable, search_filters, batch_size, strict_match));
- } catch (error) {
+ setSearchLoading(true);
+ setSearchResult([]);
+ const ids = await fetchSearchIDs(search, searchColumns);
+ setSearchIds(ids);
+ await fetchSearchResults(ids, searchFiltersEnable, searchFilters, batchSize, 0, searchSettings.strict_search_mode, {
+ onSuccess: ({ courses, totalCount }) => {
+ setSearchResult(courses);
+ setSearchLoading(false);
+ setSearchError(null);
+ setOffset(batchSize);
+ setTotalCount(totalCount);
+ },
+ });
+ } catch (e) {
+ setSearchLoading(false);
+ setSearchError(e);
+ const error = handleAPIError(e);
if (error.status_code >= 500) {
navigate(`/error/${error.status_code}`, { state: error });
} else {
@@ -216,50 +243,43 @@ function SettingSwitch({ label, setterFunc, defaultValue, isDisabled }) {
}
function CourseSearchInput({ displayPanel }) {
- const dispatch = useDispatch();
const toast = useToast();
-
+ const { searchFilters, searchSettings, searchFiltersEnable, setSearchFiltersEnable, setSearchSettings, setSearchFilters } =
+ useCourseSearchingContext();
+ const { displayTags, setDisplayTags } = useDisplayTags();
const available_tags = ["required", "total_slot", "enroll_method", "area"];
- const search_filters = useSelector((state) => state.search_filters);
- const search_settings = useSelector((state) => state.search_settings);
- const search_filters_enable = useSelector((state) => state.search_filters_enable);
- const display_tags = useSelector((state) => state.display_tags);
// filters local states
- const [selectedTime, setSelectedTime] = useState(mapStateToTimeTable(search_filters.time));
- const [selectedDept, setSelectedDept] = useState(search_filters.department);
- const [selectedType, setSelectedType] = useState(search_filters.category);
+ const [selectedTime, setSelectedTime] = useState(mapStateToTimeTable(searchFilters.time));
+ const [selectedDept, setSelectedDept] = useState(searchFilters.department);
+ const [selectedType, setSelectedType] = useState(searchFilters.category);
- const [timeFilterOn, setTimeFilterOn] = useState(search_filters_enable.time);
- const [deptFilterOn, setDeptFilterOn] = useState(search_filters_enable.department);
- const [catFilterOn, setCatFilterOn] = useState(search_filters_enable.category);
- const [enrollFilterOn, setEnrollFilterOn] = useState(search_filters_enable.enroll_method);
+ const [timeFilterOn, setTimeFilterOn] = useState(searchFiltersEnable.time);
+ const [deptFilterOn, setDeptFilterOn] = useState(searchFiltersEnable.department);
+ const [catFilterOn, setCatFilterOn] = useState(searchFiltersEnable.category);
+ const [enrollFilterOn, setEnrollFilterOn] = useState(searchFiltersEnable.enroll_method);
- // search_settings local states
- const [show_selected_courses, set_show_selected_courses] = useState(search_settings.show_selected_courses);
- const [only_show_not_conflicted_courses, set_only_show_not_conflicted_courses] = useState(search_settings.only_show_not_conflicted_courses);
- const [sync_add_to_nol, set_sync_add_to_nol] = useState(search_settings.sync_add_to_nol);
- const [strict_search_mode, set_strict_search_mode] = useState(search_settings.strict_search_mode);
+ // searchSettings local states
+ const [show_selected_courses, set_show_selected_courses] = useState(searchSettings.show_selected_courses);
+ const [only_show_not_conflicted_courses, set_only_show_not_conflicted_courses] = useState(searchSettings.only_show_not_conflicted_courses);
+ const [sync_add_to_nol, set_sync_add_to_nol] = useState(searchSettings.sync_add_to_nol);
+ const [strict_search_mode, set_strict_search_mode] = useState(searchSettings.strict_search_mode);
useMount(() => {
- setSelectedTime(mapStateToTimeTable(search_filters.time));
+ setSelectedTime(mapStateToTimeTable(searchFilters.time));
});
const set_enroll_method = (e) => {
// console.log(e.currentTarget.value)
const new_enroll_method = e.currentTarget.value;
- const idx = search_filters.enroll_method.indexOf(new_enroll_method);
+ const idx = searchFilters.enroll_method.indexOf(new_enroll_method);
if (idx === -1) {
//add
- dispatch(setFilter("enroll_method", [...search_filters.enroll_method, new_enroll_method]));
+ setSearchFilters({ ...searchFilters, enroll_method: [...searchFilters.enroll_method, new_enroll_method] });
} else {
// remove
- dispatch(
- setFilter(
- "enroll_method",
- search_filters.enroll_method.filter((item) => item !== new_enroll_method)
- )
- );
+
+ setSearchFilters({ ...searchFilters, enroll_method: searchFilters.enroll_method.filter((item) => item !== new_enroll_method) });
}
};
@@ -293,14 +313,14 @@ function CourseSearchInput({ displayPanel }) {
isChecked={timeFilterOn}
onChange={(e) => {
setTimeFilterOn(e.currentTarget.checked);
- dispatch(setFilterEnable("time", e.currentTarget.checked));
+ setSearchFiltersEnable({ ...searchFiltersEnable, time: e.currentTarget.checked });
}}
/>
{
setDeptFilterOn(e.currentTarget.checked);
- dispatch(setFilterEnable("department", e.currentTarget.checked));
+ setSearchFiltersEnable({ ...searchFiltersEnable, department: e.currentTarget.checked });
}}
/>
{
setCatFilterOn(e.currentTarget.checked);
- dispatch(setFilterEnable("category", e.currentTarget.checked));
+ setSearchFiltersEnable({ ...searchFiltersEnable, category: e.currentTarget.checked });
}}
/>
{
setEnrollFilterOn(e.currentTarget.checked);
- dispatch(setFilterEnable("enroll_method", e.currentTarget.checked));
+ setSearchFiltersEnable({ ...searchFiltersEnable, enroll_method: e.currentTarget.checked });
}}
/>