import { ActionTree, GetterTree, MutationTree } from 'vuex'; import { handleDelete, handleFetch } from '../../api/helpers'; import RootState from '../types/RootStateModel'; import CrudStoreModel, { CrudStoreItemsModel, CrudStoreSchemaModel, GetItemByIdPayload, GetSingletonItemPayload } from '../types/CrudStoreModel'; import { CreateCrudItemPayload, DeleteCrudItemPayload, PublishCrudItemPayload, SaveCrudItemPayload, SearchCrudItemPayload, UpdateCrudItemPayload } from '../../types/api'; import CrudApi, { CrudSearchReponse } from '../../api/crud-api'; import CrudHelpers from '../../crud/crud-helpers'; export const state: CrudStoreModel = { path: '', latestSearchResult: undefined, loading: false, hasItemsError: false, schema: undefined, itemsCache: [], overview: { fields: [] }, searchState: { page: 1, sort: '', languageFilter: '', query: '' } }; export const actions: ActionTree = { $init({ dispatch }) { dispatch('fetchCrudSchema'); }, async fetchCrudSchema({ commit, state }) { try { const response = await handleFetch(`/items/${state.path}/schema`); commit('crudSchema', await response.json()); } catch (error) { console.warn(error.message); } }, async getItemById({ state, getters, commit }, payload: GetItemByIdPayload): Promise { const foundItem = payload.ignoreCache ? null : getters.getItemByGuid(payload.id); if (!foundItem) { const response = await handleFetch(`/items/${state.path}/${payload.id}`); const item = await response.json(); commit('addOrUpdateItemToCache', item); return item; } return foundItem; }, async getItemByIds({ state, getters, commit }, ids: string[]): Promise { const idsToFetch: string[] = []; ids.forEach((id) => { const foundItem = getters.getItemByGuid(id); if (!foundItem) { idsToFetch.push(id); } }); if (idsToFetch.length) { const response = await handleFetch(`/items/${state.path}/ids`, { method: 'POST', body: JSON.stringify(idsToFetch) }); const items = await response.json(); commit('addOrUpdateItemsToCache', items); return items; } return []; }, async getSingletonItem({ getters, dispatch }, payload: GetSingletonItemPayload): Promise { if (payload.id) { const getItemByIdPayload: GetItemByIdPayload = { id: payload.id }; return await dispatch('getItemById', getItemByIdPayload); } else { // search for first item which has the defaultlanguage await dispatch('fetchItems'); let item = getters.getItemByLanguage(payload.defaultLanguage); // search for possible item, which wasn't created in the defaultlanguage if (!item) { item = getters.getFirstItem(); } return item; } }, async saveItem({ dispatch }, payload: SaveCrudItemPayload): Promise { if (!payload.id) { return await dispatch('createItem', payload); } return await dispatch('updateItem', payload); }, async createItem({ state, commit, dispatch }, payload: CreateCrudItemPayload): Promise { try { const response = await handleFetch(`/items/${state.path}`, { method: 'POST', body: JSON.stringify(payload.item) }); const item = await response.json(); commit('addOrUpdateItemToCache', item); dispatch('fetchItems'); return item; } catch (error) { throw error; } }, async updateItem({ state, commit }, payload: UpdateCrudItemPayload): Promise { try { const response = await handleFetch(`/items/${state.path}/${payload.id}`, { method: 'PUT', body: JSON.stringify(payload.item) }); const item = await response.json(); commit('addOrUpdateItemToCache', item); return item; } catch (error) { throw error; } }, async publishItem({ state, commit }, payload: PublishCrudItemPayload): Promise { try { const response = await handleFetch(`/items/${state.path}/${payload.id}/${payload.action}`, { method: 'PUT', body: JSON.stringify(payload.item) }); const item = await response.json(); commit('addOrUpdateItemToCache', item); return item; } catch (error) { throw error; } }, async deleteItem({ state, commit, dispatch }, payload: DeleteCrudItemPayload): Promise { try { await handleDelete(`/items/${state.path}/${payload.id}`); dispatch('fetchItems'); commit('deleteItem', payload.id); } catch (error) { throw error; } }, async fetchItems({ state, commit }, payload: SearchCrudItemPayload = state.searchState) { // To prevent the relation picker from triggering a reload of the current crud item page due to a change in isLoading, loading must be disabled. This situation occurs when the relation picker loads a crud item of the same type as the one currently displayed on the page. if (!payload.disableLoading) { commit('isLoading', true); } try { const result = await CrudApi.search(state.path, payload.query, payload.languageFilter, payload.page, payload.sort); commit('result', result); commit('addOrUpdateItemsToCache', result.items); commit('hasItemsError', false); commit('isLoading', false); return result.items; } catch (error) { console.warn(error.message); commit('hasItemsError', true); } finally { if (!payload.disableLoading) { commit('isLoading', false); } } }, async updateSearchState({ commit, dispatch }, payload: SearchCrudItemPayload) { commit('searchState', payload); dispatch('fetchItems'); } }; export const getters: GetterTree = { getItemByGuid: (state) => (guid: string): CrudStoreItemsModel | undefined => { return state.itemsCache.find((item) => item.id === guid); }, getItemByLanguage: (state) => (language: string): CrudStoreItemsModel | undefined => { return state.itemsCache.find((item) => item.language == language); }, getFirstItem: (state) => (): CrudStoreItemsModel | undefined => { return state.itemsCache[0]; }, result: (state) => (): CrudSearchReponse | undefined => { return state.latestSearchResult; }, nextDisabled: (state) => (): boolean => { const dataPage = state.latestSearchResult; if (dataPage && dataPage.totalPages === 0) { return true; } return dataPage && dataPage.currentPage ? dataPage.currentPage === dataPage.totalPages : true; }, previousDisabled: (state) => (): boolean => { const dataPage = state.latestSearchResult; if (dataPage && dataPage.totalPages === 0) { return true; } return dataPage && dataPage.currentPage ? dataPage.currentPage === 1 : true; }, searchState: (state) => (): SearchCrudItemPayload => { return state.searchState; } }; export const mutations: MutationTree = { crudSchema(state, schema: CrudStoreSchemaModel) { state.schema = schema; }, addOrUpdateItemToCache(state, item: CrudStoreItemsModel) { CrudHelpers.addOrUpdateCrudItem(state.itemsCache, item); }, addOrUpdateItemsToCache(state, items: CrudStoreItemsModel[]) { items.forEach((item) => { CrudHelpers.addOrUpdateCrudItem(state.itemsCache, item); }); }, deleteItem(state, id: string) { CrudHelpers.removeCrudItem(state.itemsCache, id); }, result(state, result: CrudSearchReponse) { state.latestSearchResult = result; }, isLoading(state, loading: boolean) { state.loading = loading; }, hasItemsError(state, hasItemsError: boolean) { state.hasItemsError = hasItemsError; }, searchState(state, payload: SearchCrudItemPayload) { state.searchState = payload; } };