import articlesAPI from 'dashboard/api/helpCenter/articles'; import { uploadExternalImage, uploadFile } from 'dashboard/helper/uploadHelper'; import { throwErrorMessage } from 'dashboard/store/utils/api'; import camelcaseKeys from 'camelcase-keys'; import types from '../../mutation-types'; export const actions = { index: async ( { commit }, { pageNumber, portalSlug, locale, status, authorId, categorySlug, query } ) => { try { commit(types.SET_UI_FLAG, { isFetching: true }); const { data } = await articlesAPI.getArticles({ pageNumber, portalSlug, locale, status, authorId, categorySlug, query, }); const payload = camelcaseKeys(data.payload); const meta = camelcaseKeys(data.meta); const articleIds = payload.map(article => article.id); commit(types.CLEAR_ARTICLES); commit(types.ADD_MANY_ARTICLES, payload); commit(types.SET_ARTICLES_META, meta); commit(types.ADD_MANY_ARTICLES_ID, articleIds); return articleIds; } catch (error) { return throwErrorMessage(error); } finally { commit(types.SET_UI_FLAG, { isFetching: false }); } }, create: async ({ commit, dispatch }, { portalSlug, ...articleObj }) => { commit(types.SET_UI_FLAG, { isCreating: true }); try { const { data } = await articlesAPI.createArticle({ portalSlug, articleObj, }); const payload = camelcaseKeys(data.payload); const { id: articleId } = payload; commit(types.ADD_ARTICLE, payload); commit(types.ADD_ARTICLE_ID, articleId); commit(types.ADD_ARTICLE_FLAG, articleId); dispatch('portals/updatePortal', portalSlug, { root: true }); return articleId; } catch (error) { return throwErrorMessage(error); } finally { commit(types.SET_UI_FLAG, { isCreating: false }); } }, show: async ({ commit }, { id, portalSlug }) => { commit(types.SET_UI_FLAG, { isFetching: true }); try { const { data } = await articlesAPI.getArticle({ id, portalSlug }); const payload = camelcaseKeys(data.payload); const { id: articleId } = payload; commit(types.ADD_ARTICLE, payload); commit(types.ADD_ARTICLE_ID, articleId); commit(types.SET_UI_FLAG, { isFetching: false }); } catch (error) { commit(types.SET_UI_FLAG, { isFetching: false }); } }, update: async ({ commit }, { portalSlug, articleId, ...articleObj }) => { commit(types.UPDATE_ARTICLE_FLAG, { uiFlags: { isUpdating: true }, articleId, }); try { const { data } = await articlesAPI.updateArticle({ portalSlug, articleId, articleObj, }); const payload = camelcaseKeys(data.payload); commit(types.UPDATE_ARTICLE, payload); return articleId; } catch (error) { return throwErrorMessage(error); } finally { commit(types.UPDATE_ARTICLE_FLAG, { uiFlags: { isUpdating: false }, articleId, }); } }, // Push the draft to live and clear it, optionally changing status in the same // update. Only edited fields are sent so an untouched live value survives. publishDraft: ({ dispatch, state }, { portalSlug, articleId, status }) => { const article = state.articles.byId[articleId]; const payload = { portalSlug, articleId, status, draft_title: null, draft_content: null, }; if (article?.draftTitle != null) payload.title = article.draftTitle; if (article?.draftContent != null) payload.content = article.draftContent; return dispatch('update', payload); }, // Clear the draft (optionally changing status); live content is left untouched. discardDraft: ({ dispatch }, { portalSlug, articleId, status }) => dispatch('update', { portalSlug, articleId, status, draft_title: null, draft_content: null, }), updateArticleMeta: async ({ commit }, { portalSlug, locale }) => { try { const { data } = await articlesAPI.getArticles({ pageNumber: 1, portalSlug, locale, }); const meta = camelcaseKeys(data.meta); const { currentPage, ...metaWithoutCurrentPage } = meta; commit(types.SET_ARTICLES_META, metaWithoutCurrentPage); } catch (error) { throwErrorMessage(error); } }, delete: async ({ commit }, { portalSlug, articleId }) => { commit(types.UPDATE_ARTICLE_FLAG, { uiFlags: { isDeleting: true, }, articleId, }); try { await articlesAPI.deleteArticle({ portalSlug, articleId }); commit(types.REMOVE_ARTICLE, articleId); commit(types.REMOVE_ARTICLE_ID, articleId); return articleId; } catch (error) { return throwErrorMessage(error); } finally { commit(types.UPDATE_ARTICLE_FLAG, { uiFlags: { isDeleting: false, }, articleId, }); } }, attachImage: async (_, { file }) => { const { fileUrl } = await uploadFile(file); return fileUrl; }, uploadExternalImage: async (_, { url }) => { const { fileUrl } = await uploadExternalImage(url); return fileUrl; }, reorder: async ( { commit, state }, { portalSlug, categorySlug, reorderedGroup } ) => { // Save old positions so we can rollback on failure const oldPositions = Object.keys(reorderedGroup).reduce((map, id) => { map[id] = state.articles.byId[id]?.position; return map; }, {}); // Update positions in the store immediately so subsequent mutations preserve correct positions commit(types.SET_ARTICLE_POSITIONS, reorderedGroup); try { const { data } = await articlesAPI.reorderArticles({ portalSlug, reorderedGroup, categorySlug, }); // Adopt the backend's re-spaced positions so the next reorder isn't computed from stale local values. if (data?.positions) commit(types.SET_ARTICLE_POSITIONS, data.positions); } catch (error) { commit(types.SET_ARTICLE_POSITIONS, oldPositions); throw error; } }, bulkTranslate: async ( _, { portalSlug, articleIds, locale, categoryId, force = false } ) => { const { data } = await articlesAPI.bulkTranslate({ portalSlug, articleIds, locale, categoryId, force, }); return data; }, };