diff --git a/app/javascript/dashboard/api/helpCenter/categories.js b/app/javascript/dashboard/api/helpCenter/categories.js new file mode 100644 index 000000000..c5cb40cd4 --- /dev/null +++ b/app/javascript/dashboard/api/helpCenter/categories.js @@ -0,0 +1,27 @@ +/* global axios */ + +import PortalsAPI from './portals'; + +class CategoriesAPI extends PortalsAPI { + constructor() { + super('categories', { accountScoped: true }); + } + + get({ portalSlug }) { + return axios.get(`${this.url}/${portalSlug}/categories`); + } + + create({ portalSlug, categoryObj }) { + return axios.post(`${this.url}/${portalSlug}/categories`, categoryObj); + } + + update({ portalSlug, categoryObj }) { + return axios.patch(`${this.url}/${portalSlug}/categories`, categoryObj); + } + + delete({ portalSlug, categoryId }) { + return axios.delete(`${this.url}/${portalSlug}/categories/${categoryId}`); + } +} + +export default new CategoriesAPI(); diff --git a/app/javascript/dashboard/api/helpCenter/portals.js b/app/javascript/dashboard/api/helpCenter/portals.js index 2a15fa7bd..1df4d2554 100644 --- a/app/javascript/dashboard/api/helpCenter/portals.js +++ b/app/javascript/dashboard/api/helpCenter/portals.js @@ -13,4 +13,4 @@ class PortalsAPI extends ApiClient { } } -export default new PortalsAPI(); +export default PortalsAPI; diff --git a/app/javascript/dashboard/api/specs/helpCenter/categories.spec.js b/app/javascript/dashboard/api/specs/helpCenter/categories.spec.js new file mode 100644 index 000000000..2c56f4e00 --- /dev/null +++ b/app/javascript/dashboard/api/specs/helpCenter/categories.spec.js @@ -0,0 +1,12 @@ +import categoriesAPI from '../../helpCenter/categories'; +import ApiClient from '../../ApiClient'; + +describe('#BulkActionsAPI', () => { + it('creates correct instance', () => { + expect(categoriesAPI).toBeInstanceOf(ApiClient); + expect(categoriesAPI).toHaveProperty('get'); + expect(categoriesAPI).toHaveProperty('create'); + expect(categoriesAPI).toHaveProperty('update'); + expect(categoriesAPI).toHaveProperty('delete'); + }); +}); diff --git a/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js b/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js index 87d4a886d..2a1e38da7 100644 --- a/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js +++ b/app/javascript/dashboard/store/modules/helpCenterArticles/actions.js @@ -1,6 +1,7 @@ -import portalAPI from 'dashboard/api/helpCenter/portals'; +import PortalAPI from 'dashboard/api/helpCenter/portals'; import articlesAPI from 'dashboard/api/helpCenter/articles'; import { throwErrorMessage } from 'dashboard/store/utils/api'; +const portalAPIs = new PortalAPI(); import types from '../../mutation-types'; export const actions = { index: async ({ commit }, { pageNumber, portalSlug, locale }) => { @@ -8,7 +9,7 @@ export const actions = { commit(types.SET_UI_FLAG, { isFetching: true }); const { data: { payload, meta }, - } = await portalAPI.getArticles({ + } = await portalAPIs.getArticles({ pageNumber, portalSlug, locale, @@ -44,7 +45,7 @@ export const actions = { show: async ({ commit }, { id, portalSlug }) => { commit(types.SET_UI_FLAG, { isFetching: true }); try { - const response = await portalAPI.getArticle({ id, portalSlug }); + const response = await articlesAPI.getArticle({ id, portalSlug }); const { data: { payload }, } = response; diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/actions.js b/app/javascript/dashboard/store/modules/helpCenterCategories/actions.js new file mode 100644 index 000000000..e1bd50f1e --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/actions.js @@ -0,0 +1,84 @@ +import categoriesAPI from 'dashboard/api/helpCenter/categories.js'; +import { throwErrorMessage } from 'dashboard/store/utils/api'; +import types from '../../mutation-types'; +export const actions = { + index: async ({ commit }, { portalSlug }) => { + try { + commit(types.SET_UI_FLAG, { isFetching: true }); + const { + data: { payload }, + } = await categoriesAPI.get({ portalSlug }); + const categoryIds = payload.map(category => category.id); + commit(types.ADD_MANY_CATEGORIES, payload); + commit(types.ADD_MANY_CATEGORIES_ID, categoryIds); + return categoryIds; + } catch (error) { + return throwErrorMessage(error); + } finally { + commit(types.SET_UI_FLAG, { isFetching: false }); + } + }, + + create: async ({ commit }, portalSlug, categoryObj) => { + commit(types.SET_UI_FLAG, { isCreating: true }); + try { + const { data } = await categoriesAPI.create({ portalSlug, categoryObj }); + const { id: categoryId } = data; + commit(types.ADD_CATEGORY, data); + commit(types.ADD_CATEGORY_ID, categoryId); + return categoryId; + } catch (error) { + return throwErrorMessage(error); + } finally { + commit(types.SET_UI_FLAG, { isCreating: false }); + } + }, + + update: async ({ commit }, portalSlug, categoryObj) => { + const categoryId = categoryObj.id; + commit(types.ADD_CATEGORY_FLAG, { + uiFlags: { + isUpdating: true, + }, + categoryId, + }); + try { + const { data } = await categoriesAPI.update({ portalSlug, categoryObj }); + commit(types.UPDATE_CATEGORY, data); + return categoryId; + } catch (error) { + return throwErrorMessage(error); + } finally { + commit(types.ADD_CATEGORY_FLAG, { + uiFlags: { + isUpdating: false, + }, + categoryId, + }); + } + }, + + delete: async ({ commit }, portalSlug, categoryId) => { + commit(types.ADD_CATEGORY_FLAG, { + uiFlags: { + isDeleting: true, + }, + categoryId, + }); + try { + await categoriesAPI.delete({ portalSlug, categoryId }); + commit(types.REMOVE_CATEGORY, categoryId); + commit(types.REMOVE_CATEGORY_ID, categoryId); + return categoryId; + } catch (error) { + return throwErrorMessage(error); + } finally { + commit(types.ADD_CATEGORY_FLAG, { + uiFlags: { + isDeleting: false, + }, + categoryId, + }); + } + }, +}; diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/getters.js b/app/javascript/dashboard/store/modules/helpCenterCategories/getters.js new file mode 100644 index 000000000..f7745a356 --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/getters.js @@ -0,0 +1,24 @@ +export const getters = { + uiFlags: state => helpCenterId => { + const uiFlags = state.categories.uiFlags.byId[helpCenterId]; + if (uiFlags) return uiFlags; + return { isFetching: false, isUpdating: false, isDeleting: false }; + }, + isFetching: state => state.uiFlags.isFetching, + categoryById: (...getterArguments) => categoryId => { + const [state] = getterArguments; + const category = state.categories.byId[categoryId]; + if (!category) return undefined; + return category; + }, + allCategories: (...getterArguments) => { + const [state, _getters] = getterArguments; + const categories = state.categories.allIds.map(id => { + return _getters.categoryById(id); + }); + return categories; + }, + getMeta: state => { + return state.meta; + }, +}; diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/index.js b/app/javascript/dashboard/store/modules/helpCenterCategories/index.js new file mode 100644 index 000000000..574f16b0d --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/index.js @@ -0,0 +1,31 @@ +import { getters } from './getters'; +import { actions } from './actions'; +import { mutations } from './mutations'; + +export const defaultHelpCenterFlags = { + isFetching: false, + isUpdating: false, + isDeleting: false, +}; +const state = { + categoriess: { + byId: {}, + byLocale: {}, + allIds: [], + uiFlags: { + byId: {}, + }, + }, + uiFlags: { + allFetched: false, + isFetching: false, + }, +}; + +export default { + namespaced: true, + state, + getters, + actions, + mutations, +}; diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/mutations.js b/app/javascript/dashboard/store/modules/helpCenterCategories/mutations.js new file mode 100644 index 000000000..11addb9be --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/mutations.js @@ -0,0 +1,74 @@ +import types from '../../mutation-types'; +import Vue from 'vue'; + +export const mutations = { + [types.SET_UI_FLAG](_state, uiFlags) { + _state.uiFlags = { + ..._state.uiFlags, + ...uiFlags, + }; + }, + + [types.ADD_CATEGORY]: ($state, category) => { + if (!category.id) return; + + Vue.set($state.categories.byId, category.id, { + ...category, + }); + }, + [types.CLEAR_CATEGORIES]: $state => { + Vue.set($state.categories, 'byId', {}); + Vue.set($state.categories, 'allIds', []); + Vue.set($state.categories, 'uiFlags', {}); + }, + [types.ADD_MANY_CATEGORIES]($state, categories) { + const allCategories = { ...$state.categories.byId }; + categories.forEach(category => { + allCategories[category.id] = category; + }); + Vue.set($state.categories, 'byId', allCategories); + }, + [types.ADD_MANY_CATEGORIES_ID]($state, categoryIds) { + $state.categories.allIds.push(...categoryIds); + }, + + [types.SET_CATEGORIES_META]: ($state, data) => { + const { categories_count: count, current_page: currentPage } = data; + Vue.set($state.meta, 'count', count); + Vue.set($state.meta, 'currentPage', currentPage); + }, + + [types.ADD_CATEGORY_ID]: ($state, categoryId) => { + $state.categories.allIds.push(categoryId); + }, + [types.ADD_CATEGORY_FLAG]: ($state, { categoryId, uiFlags }) => { + const flags = $state.categories.uiFlags.byId[categoryId]; + Vue.set($state.categories.uiFlags.byId, categoryId, { + ...{ + isFetching: false, + isUpdating: false, + isDeleting: false, + }, + ...flags, + ...uiFlags, + }); + }, + [types.UPDATE_CATEGORY]($state, category) { + const categoryId = category.id; + + if (!$state.categories.allIds.includes(categoryId)) return; + + Vue.set($state.categories.byId, categoryId, { + ...category, + }); + }, + [types.REMOVE_CATEGORY]($state, categoryId) { + const { [categoryId]: toBeRemoved, ...newById } = $state.categories.byId; + Vue.set($state.categories, 'byId', newById); + }, + [types.REMOVE_CATEGORY_ID]($state, categoryId) { + $state.categories.allIds = $state.categories.allIds.filter( + id => id !== categoryId + ); + }, +}; diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/specs/actions.spec.js b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/actions.spec.js new file mode 100644 index 000000000..62c998712 --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/actions.spec.js @@ -0,0 +1,138 @@ +import axios from 'axios'; +import { actions } from '../actions'; +import * as types from '../../../mutation-types'; +import { categoriesPayload } from './fixtures'; +const commit = jest.fn(); +global.axios = axios; +jest.mock('axios'); + +describe('#actions', () => { + describe('#index', () => { + it('sends correct actions if API is success', async () => { + axios.get.mockResolvedValue({ data: categoriesPayload }); + await actions.index({ commit }, { portalSlug: 'room-rental' }); + expect(commit.mock.calls).toEqual([ + [types.default.SET_UI_FLAG, { isFetching: true }], + [types.default.ADD_MANY_CATEGORIES, categoriesPayload.payload], + [types.default.ADD_MANY_CATEGORIES_ID, [1, 2]], + [types.default.SET_UI_FLAG, { isFetching: false }], + ]); + }); + it('sends correct actions if API is error', async () => { + axios.get.mockRejectedValue({ message: 'Incorrect header' }); + await expect( + actions.index({ commit }, { portalSlug: 'room-rental' }) + ).rejects.toThrow(Error); + expect(commit.mock.calls).toEqual([ + [types.default.SET_UI_FLAG, { isFetching: true }], + [types.default.SET_UI_FLAG, { isFetching: false }], + ]); + }); + }); + + describe('#create', () => { + it('sends correct actions if API is success', async () => { + axios.post.mockResolvedValue({ data: categoriesPayload.payload[0] }); + await actions.create({ commit }, categoriesPayload.payload[0]); + expect(commit.mock.calls).toEqual([ + [types.default.SET_UI_FLAG, { isCreating: true }], + [types.default.ADD_CATEGORY, categoriesPayload.payload[0]], + [types.default.ADD_CATEGORY_ID, 1], + [types.default.SET_UI_FLAG, { isCreating: false }], + ]); + }); + + it('sends correct actions if API is error', async () => { + axios.post.mockRejectedValue({ message: 'Incorrect header' }); + await expect( + actions.create({ commit }, 'web-docs', categoriesPayload.payload[0]) + ).rejects.toThrow(Error); + expect(commit.mock.calls).toEqual([ + [types.default.SET_UI_FLAG, { isCreating: true }], + [types.default.SET_UI_FLAG, { isCreating: false }], + ]); + }); + }); + + describe('#update', () => { + it('sends correct actions if API is success', async () => { + axios.patch.mockResolvedValue({ data: categoriesPayload.payload[0] }); + await actions.update( + { commit }, + 'web-docs', + categoriesPayload.payload[0] + ); + expect(commit.mock.calls).toEqual([ + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isUpdating: true }, categoryId: 1 }, + ], + [types.default.UPDATE_CATEGORY, categoriesPayload.payload[0]], + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isUpdating: false }, categoryId: 1 }, + ], + ]); + }); + + it('sends correct actions if API is error', async () => { + axios.patch.mockRejectedValue({ message: 'Incorrect header' }); + await expect( + actions.update({ commit }, 'web-docs', categoriesPayload.payload[0]) + ).rejects.toThrow(Error); + expect(commit.mock.calls).toEqual([ + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isUpdating: true }, categoryId: 1 }, + ], + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isUpdating: false }, categoryId: 1 }, + ], + ]); + }); + }); + + describe('#delete', () => { + it('sends correct actions if API is success', async () => { + axios.delete.mockResolvedValue({ data: categoriesPayload.payload[0] }); + await actions.delete( + { commit }, + 'portal-slug', + categoriesPayload.payload[0].id + ); + expect(commit.mock.calls).toEqual([ + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isDeleting: true }, categoryId: 1 }, + ], + [types.default.REMOVE_CATEGORY, categoriesPayload.payload[0].id], + [types.default.REMOVE_CATEGORY_ID, categoriesPayload.payload[0].id], + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isDeleting: false }, categoryId: 1 }, + ], + ]); + }); + it('sends correct actions if API is error', async () => { + axios.delete.mockRejectedValue({ message: 'Incorrect header' }); + await expect( + actions.delete( + { commit }, + 'portal-slug', + categoriesPayload.payload[0].id + ) + ).rejects.toThrow(Error); + expect(commit.mock.calls).toEqual([ + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isDeleting: true }, categoryId: 1 }, + ], + [ + types.default.ADD_CATEGORY_FLAG, + { uiFlags: { isDeleting: false }, categoryId: 1 }, + ], + ]); + }); + }); +}); diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/specs/fixtures.js b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/fixtures.js new file mode 100644 index 000000000..c19d7a615 --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/fixtures.js @@ -0,0 +1,77 @@ +export const categoriesPayload = { + payload: [ + { + id: 1, + name: 'FAQs', + slug: 'faq', + locale: 'en', + description: 'This category is for FAQs', + position: 0, + account_id: 1, + meta: { + articles_count: 1, + }, + }, + { + id: 2, + name: 'Product updates', + slug: 'product-updates', + locale: 'en', + description: 'This category is for product updates', + position: 0, + account_id: 1, + meta: { + articles_count: 0, + }, + }, + ], + meta: { + current_page: 1, + categories_count: 2, + }, +}; + +export const categoriesState = { + meta: { + count: 123, + currentPage: 1, + }, + categories: { + byId: { + 1: { + id: 1, + name: 'FAQs', + slug: 'faq', + locale: 'en', + description: 'This category is for FAQs', + position: 0, + account_id: 1, + meta: { + articles_count: 1, + }, + }, + 2: { + id: 2, + name: 'Product updates', + slug: 'product-updates', + locale: 'en', + description: 'This category is for product updates', + position: 0, + account_id: 1, + meta: { + articles_count: 0, + }, + }, + }, + allIds: [1, 2], + uiFlags: { + byId: { + 1: { isFetching: false, isUpdating: true, isDeleting: false }, + }, + }, + }, + uiFlags: { + allFetched: false, + isFetching: true, + }, +}; diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/specs/getters.spec.js b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/getters.spec.js new file mode 100644 index 000000000..9890d6cc6 --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/getters.spec.js @@ -0,0 +1,25 @@ +import { getters } from '../getters'; +import { categoriesState } from './fixtures'; +describe('#getters', () => { + let state = {}; + beforeEach(() => { + state = categoriesState; + }); + it('uiFlags', () => { + expect(getters.uiFlags(state)(1)).toEqual({ + isFetching: false, + isUpdating: true, + isDeleting: false, + }); + }); + + it('categoryById', () => { + expect(getters.categoryById(state)(1)).toEqual( + categoriesState.categories.byId[1] + ); + }); + + it('isFetchingCategories', () => { + expect(getters.isFetching(state)).toEqual(true); + }); +}); diff --git a/app/javascript/dashboard/store/modules/helpCenterCategories/specs/mutations.spec.js b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/mutations.spec.js new file mode 100644 index 000000000..d7ea4623e --- /dev/null +++ b/app/javascript/dashboard/store/modules/helpCenterCategories/specs/mutations.spec.js @@ -0,0 +1,101 @@ +import { mutations } from '../mutations'; +import types from '../../../mutation-types'; +import { categoriesState, categoriesPayload } from './fixtures'; +describe('#mutations', () => { + let state = {}; + beforeEach(() => { + state = categoriesState; + }); + + describe('#SET_UI_FLAG', () => { + it('It returns default flags if empty object passed', () => { + mutations[types.SET_UI_FLAG](state, {}); + expect(state.uiFlags).toEqual({ + allFetched: false, + isFetching: true, + }); + }); + it('Update flags when flag passed as parameters', () => { + mutations[types.SET_UI_FLAG](state, { isFetching: true }); + expect(state.uiFlags).toEqual({ + allFetched: false, + isFetching: true, + }); + }); + }); + + describe('#ADD_CATEGORY', () => { + it('add valid category to state', () => { + mutations[types.ADD_CATEGORY](state, categoriesPayload.payload[0]); + expect(state.categories.byId[1]).toEqual(categoriesPayload.payload[0]); + }); + it('does not add category with empty data passed', () => { + mutations[types.ADD_CATEGORY](state, {}); + expect(state).toEqual(categoriesState); + }); + }); + + describe('#CATEGORIES_META', () => { + it('add meta to state', () => { + mutations[types.SET_CATEGORIES_META](state, { + categories_count: 3, + current_page: 1, + }); + expect(state.meta).toEqual({ + count: 3, + currentPage: 1, + }); + }); + }); + + describe('#ADD_CATEGORY_ID', () => { + it('add valid category id to state', () => { + mutations[types.ADD_CATEGORY_ID](state, 3); + expect(state.categories.allIds).toEqual([1, 2, 3]); + }); + it('Does not invalid category with empty data passed', () => { + mutations[types.ADD_CATEGORY_ID](state, {}); + expect(state).toEqual(categoriesState); + }); + }); + + describe('#UPDATE_CATEGORY', () => { + it('does not updates if empty object is passed', () => { + mutations[types.UPDATE_CATEGORY](state, {}); + expect(state).toEqual(categoriesState); + }); + it('does not updates if object id is not present ', () => { + mutations[types.UPDATE_CATEGORY](state, { id: 5 }); + expect(state).toEqual(categoriesState); + }); + it(' updates if object with id already present in the state', () => { + mutations[types.UPDATE_CATEGORY](state, { + id: 2, + title: 'This category is for product updates', + }); + expect(state.categories.byId[2].title).toEqual( + 'This category is for product updates' + ); + }); + }); + + describe('#REMOVE_CATEGORY', () => { + it('does not remove object entry if no id is passed', () => { + mutations[types.REMOVE_CATEGORY](state, undefined); + expect(state).toEqual({ ...categoriesState }); + }); + it('removes category if valid category id passed', () => { + mutations[types.REMOVE_CATEGORY](state, 2); + expect(state.categories.byId[2]).toEqual(undefined); + }); + }); + + // describe('#CLEAR_CATEGORIES', () => { + // it('clears categories', () => { + // mutations[types.CLEAR_CATEGORIES](state); + // expect(state.categories.allIds).toEqual([]); + // expect(state.categories.byId).toEqual({}); + // expect(state.categories.uiFlags).toEqual({}); + // }); + // }); +}); diff --git a/app/javascript/dashboard/store/modules/helpCenterPortals/actions.js b/app/javascript/dashboard/store/modules/helpCenterPortals/actions.js index 04fffea95..64a431d34 100644 --- a/app/javascript/dashboard/store/modules/helpCenterPortals/actions.js +++ b/app/javascript/dashboard/store/modules/helpCenterPortals/actions.js @@ -1,12 +1,12 @@ -import PortalsAPI from 'dashboard/api/helpCenter/portals.js'; +import PortalAPI from 'dashboard/api/helpCenter/portals.js'; import { throwErrorMessage } from 'dashboard/store/utils/api'; import { types } from './mutations'; - +const portalAPIs = new PortalAPI(); export const actions = { index: async ({ commit }) => { try { commit(types.SET_UI_FLAG, { isFetching: true }); - const { data } = await PortalsAPI.get(); + const { data } = await portalAPIs.get(); const portalIds = data.map(portal => portal.id); commit(types.ADD_MANY_PORTALS_ENTRY, data); commit(types.ADD_MANY_PORTALS_IDS, portalIds); @@ -20,7 +20,7 @@ export const actions = { create: async ({ commit }, params) => { commit(types.SET_UI_FLAG, { isCreating: true }); try { - const { data } = await PortalsAPI.create(params); + const { data } = await portalAPIs.create(params); const { id: portalId } = data; commit(types.ADD_PORTAL_ENTRY, data); commit(types.ADD_PORTAL_ID, portalId); @@ -38,7 +38,7 @@ export const actions = { portalId, }); try { - const { data } = await PortalsAPI.update(params); + const { data } = await portalAPIs.update(params); commit(types.UPDATE_PORTAL_ENTRY, data); } catch (error) { throwErrorMessage(error); @@ -56,7 +56,7 @@ export const actions = { portalId, }); try { - await PortalsAPI.delete(portalId); + await portalAPIs.delete(portalId); commit(types.REMOVE_PORTAL_ENTRY, portalId); commit(types.REMOVE_PORTAL_ID, portalId); } catch (error) { diff --git a/app/javascript/dashboard/store/mutation-types.js b/app/javascript/dashboard/store/mutation-types.js index c9073d58a..77e1969c5 100755 --- a/app/javascript/dashboard/store/mutation-types.js +++ b/app/javascript/dashboard/store/mutation-types.js @@ -233,4 +233,13 @@ export default { REMOVE_ARTICLE: 'REMOVE_ARTICLE', REMOVE_ARTICLE_ID: 'REMOVE_ARTICLE_ID', SET_UI_FLAG: 'SET_UI_FLAG', + // Help Center -- Categories + ADD_CATEGORY: 'ADD_CATEGORY', + ADD_CATEGORY_ID: 'ADD_CATEGORY_ID', + ADD_MANY_CATEGORIES: 'ADD_MANY_CATEGORIES', + ADD_MANY_CATEGORIES_ID: 'ADD_MANY_CATEGORIES_ID', + ADD_CATEGORY_FLAG: 'ADD_CATEGORY_FLAG', + UPDATE_CATEGORY: 'UPDATE_CATEGORY', + REMOVE_CATEGORY: 'REMOVE_CATEGORY', + REMOVE_CATEGORY_ID: 'REMOVE_CATEGORY_ID', };