diff --git a/src/data/redux/app/reducer.js b/src/data/redux/app/reducer.js
index a8df1ee4..a3f94e64 100644
--- a/src/data/redux/app/reducer.js
+++ b/src/data/redux/app/reducer.js
@@ -10,15 +10,17 @@ const initialState = {
enterpriseDashboard: {},
platformSettings: {},
suggestedCourses: [],
- filterState: {},
selectSessionModal: {},
+ filters: [],
};
export const cardId = (val) => `card-${val}`;
export const today = Date.now();
-// eslint-disable-next-line no-unused-vars
+/**
+ * Creates a redux slice with actions to load dashboard data and manage visual layout
+ */
const app = createSlice({
name: 'app',
initialState,
@@ -49,6 +51,22 @@ const app = createSlice({
selectSessionModal: { cardId: payload },
}),
setPageNumber: (state, { payload }) => ({ ...state, pageNumber: payload }),
+ setFilters: (state, { payload }) => ({
+ ...state,
+ filters: payload,
+ }),
+ addFilter: (state, { payload }) => ({
+ ...state,
+ filters: [...state.filters, payload],
+ }),
+ removeFilter: (state, { payload }) => ({
+ ...state,
+ filters: state.filters.filter(item => item !== payload),
+ }),
+ clearFilters: (state) => ({
+ ...state,
+ filters: [],
+ }),
},
});
diff --git a/src/data/redux/app/reducer.test.js b/src/data/redux/app/reducer.test.js
index 00a98c10..5d542223 100644
--- a/src/data/redux/app/reducer.test.js
+++ b/src/data/redux/app/reducer.test.js
@@ -14,12 +14,14 @@ describe('app reducer', () => {
it('returns initial state', () => {
expect(reducer(undefined, {})).toEqual(initialState);
});
+ const initialFilter = 'initial filter';
const testState = {
...initialState,
enrollments: [],
courseData: {
},
entitlement: [],
+ filters: [initialFilter],
};
describe('action handlers', () => {
describe('loadCourses', () => {
@@ -93,6 +95,30 @@ describe('app reducer', () => {
});
});
});
+ describe('filters', () => {
+ const newFilter = 'new filter';
+ let out;
+ beforeEach(() => {
+ out = reducer(testState, {});
+ });
+ it('overwrites the filters object when using setFilters', () => {
+ expect(out.filters).toEqual([initialFilter]);
+ out = reducer(testState, actions.setFilters([newFilter]));
+ expect(out.filters).toEqual([newFilter]);
+ });
+ it('adds a filter when using addFilter', () => {
+ out = reducer(testState, actions.addFilter(newFilter));
+ expect(out.filters).toEqual([initialFilter, newFilter]);
+ });
+ it('removes a filter when using removeFilter', () => {
+ out = reducer(testState, actions.removeFilter(initialFilter));
+ expect(out.filters).toEqual([]);
+ });
+ it('clears the filters when using clearFilters', () => {
+ out = reducer(testState, actions.clearFilters());
+ expect(out.filters).toEqual([]);
+ });
+ });
});
});
});
diff --git a/src/data/redux/app/selectors/currentList.js b/src/data/redux/app/selectors/currentList.js
index 4e22a77e..9c713eb6 100644
--- a/src/data/redux/app/selectors/currentList.js
+++ b/src/data/redux/app/selectors/currentList.js
@@ -50,7 +50,7 @@ export const visibleList = (state, {
};
}
return {
- visible: list.slice((pageNumber - 1) * pageSize, pageNumber * pageSize),
+ visibleList: list.slice((pageNumber - 1) * pageSize, pageNumber * pageSize),
numPages: Math.ceil(list.length / pageSize),
};
};
diff --git a/src/data/redux/app/selectors/currentList.test.js b/src/data/redux/app/selectors/currentList.test.js
index d8bff131..058d5619 100644
--- a/src/data/redux/app/selectors/currentList.test.js
+++ b/src/data/redux/app/selectors/currentList.test.js
@@ -171,7 +171,7 @@ describe('courseList selector module', () => {
});
it('returns visible page based on passed page size and stored pageNumber', () => {
// page 3, 2 per page. [0 1] [2 3] [4 5] ...
- expect(out.visible).toEqual([testList[4], testList[5]]);
+ expect(out.visibleList).toEqual([testList[4], testList[5]]);
});
it('returns number of pages based on page size and list length', () => {
expect(out.numPages).toEqual(6);
diff --git a/src/data/redux/app/selectors/simpleSelectors.js b/src/data/redux/app/selectors/simpleSelectors.js
index c8ce2a0f..0c576fc2 100644
--- a/src/data/redux/app/selectors/simpleSelectors.js
+++ b/src/data/redux/app/selectors/simpleSelectors.js
@@ -15,6 +15,7 @@ export const simpleSelectors = StrictDict({
enterpriseDashboard: mkSimpleSelector(app => app.enterpriseDashboard || {}),
selectSessionModal: mkSimpleSelector(app => app.selectSessionModal),
pageNumber: mkSimpleSelector(app => app.pageNumber),
+ filters: mkSimpleSelector(app => app.filters),
socialShareSettings: mkSimpleSelector(app => app.socialShareSettings),
});
diff --git a/src/data/redux/hooks/app.js b/src/data/redux/hooks/app.js
index dd74aa8b..06a5c352 100644
--- a/src/data/redux/hooks/app.js
+++ b/src/data/redux/hooks/app.js
@@ -9,6 +9,7 @@ const actions = redux.actions.app;
/** Simple Selectors **/
export const usePageNumber = () => useSelector(selectors.pageNumber);
+export const useFilters = () => useSelector(selectors.filters);
export const useEmailConfirmationData = () => useSelector(selectors.emailConfirmation);
export const useEnterpriseDashboardData = () => useSelector(selectors.enterpriseDashboard);
export const usePlatformSettingsData = () => useSelector(selectors.platformSettings);
@@ -77,6 +78,26 @@ export const useSetPageNumber = () => {
return (value) => dispatch(actions.setPageNumber(value));
};
+export const useSetFilters = () => {
+ const dispatch = useDispatch();
+ return (value) => dispatch(actions.setFilters(value));
+};
+
+export const useAddFilter = () => {
+ const dispatch = useDispatch();
+ return (value) => dispatch(actions.addFilter(value));
+};
+
+export const useRemoveFilter = () => {
+ const dispatch = useDispatch();
+ return (value) => dispatch(actions.removeFilter(value));
+};
+
+export const useClearFilters = () => {
+ const dispatch = useDispatch();
+ return (value) => dispatch(actions.clearFilters(value));
+};
+
export const useLoadData = () => {
const dispatch = useDispatch();
return ({ courses, ...globalData }) => {
diff --git a/src/data/redux/index.js b/src/data/redux/index.js
index 827570b1..24e6e10b 100644
--- a/src/data/redux/index.js
+++ b/src/data/redux/index.js
@@ -10,6 +10,14 @@ const modules = {
requests,
};
+/**
+ * Extracts keys from the modules object and the provided propName parameter to locate the
+ * corresponding object for that propName.
+ * Example: moduleProps('reducer') will return an aggregated object containing the reducer for each module
+ *
+ * @param {string} propName Used to locate the prop in each module
+ * @returns {object} Aggregated values for the provided propName
+ */
const moduleProps = (propName) => Object.keys(modules).reduce(
(obj, moduleKey) => {
const value = modules[moduleKey][propName];