From 5ae8bace820b05d3ad05f40ab51164ec2c35c068 Mon Sep 17 00:00:00 2001 From: Dominik Pschenitschni Date: Mon, 31 Oct 2022 20:41:23 +0000 Subject: [PATCH] feat: lists store with composition api (#2606) Co-authored-by: Dominik Pschenitschni Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/2606 Reviewed-by: konrad Co-authored-by: Dominik Pschenitschni Co-committed-by: Dominik Pschenitschni --- src/stores/lists.ts | 261 +++++++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 125 deletions(-) diff --git a/src/stores/lists.ts b/src/stores/lists.ts index 72b011ba8..91b4158cd 100644 --- a/src/stores/lists.ts +++ b/src/stores/lists.ts @@ -1,4 +1,4 @@ -import {watch, reactive, shallowReactive, unref, toRefs, readonly} from 'vue' +import {watch, reactive, shallowReactive, unref, toRefs, readonly, ref, computed} from 'vue' import {acceptHMRUpdate, defineStore} from 'pinia' import {useI18n} from 'vue-i18n' @@ -21,149 +21,160 @@ const {add, remove, search, update} = createNewIndexer('lists', ['title', 'descr const FavoriteListsNamespace = -2 export interface ListState { - lists: { [id: IList['id']]: IList }, - isLoading: boolean, + [id: IList['id']]: IList } -export const useListStore = defineStore('list', { - state: () : ListState => ({ - isLoading: false, - // The lists are stored as an object which has the list ids as keys. - lists: {}, - }), +export const useListStore = defineStore('list', () => { + const baseStore = useBaseStore() + const namespaceStore = useNamespaceStore() - getters: { - getListById(state) { - return (id: IList['id']) => typeof state.lists[id] !== 'undefined' ? state.lists[id] : null - }, + const isLoading = ref(false) - findListByExactname(state) { - return (name: string) => { - const list = Object.values(state.lists).find(l => { - return l.title.toLowerCase() === name.toLowerCase() - }) - return typeof list === 'undefined' ? null : list - } - }, + // The lists are stored as an object which has the list ids as keys. + const lists = ref({}) - searchList(state) { - return (query: string, includeArchived = false) => { - return search(query) - ?.filter(value => value > 0) - .map(id => state.lists[id]) - .filter(list => list.isArchived === includeArchived) - || [] - } - }, - }, - actions: { - setIsLoading(isLoading: boolean) { - this.isLoading = isLoading - }, + const getListById = computed(() => { + return (id: IList['id']) => typeof lists.value[id] !== 'undefined' ? lists.value[id] : null + }) - setList(list: IList) { - this.lists[list.id] = list - update(list) - - const baseStore = useBaseStore() - if (baseStore.currentList?.id === list.id) { - baseStore.setCurrentList(list) - } - }, - - setLists(lists: IList[]) { - lists.forEach(l => { - this.lists[l.id] = l - add(l) + const findListByExactname = computed(() => { + return (name: string) => { + const list = Object.values(lists.value).find(l => { + return l.title.toLowerCase() === name.toLowerCase() }) - }, + return typeof list === 'undefined' ? null : list + } + }) - removeListById(list: IList) { - remove(list) - delete this.lists[list.id] - }, + const searchList = computed(() => { + return (query: string, includeArchived = false) => { + return search(query) + ?.filter(value => value > 0) + .map(id => lists.value[id]) + .filter(list => list.isArchived === includeArchived) + || [] + } + }) - toggleListFavorite(list: IList) { - // The favorites pseudo list is always favorite - // Archived lists cannot be marked favorite - if (list.id === -1 || list.isArchived) { - return + function setIsLoading(newIsLoading: boolean) { + isLoading.value = newIsLoading + } + + function setList(list: IList) { + lists.value[list.id] = list + update(list) + + if (baseStore.currentList?.id === list.id) { + baseStore.setCurrentList(list) + } + } + + function setLists(newLists: IList[]) { + newLists.forEach(l => { + lists.value[l.id] = l + add(l) + }) + } + + function removeListById(list: IList) { + remove(list) + delete lists.value[list.id] + } + + function toggleListFavorite(list: IList) { + // The favorites pseudo list is always favorite + // Archived lists cannot be marked favorite + if (list.id === -1 || list.isArchived) { + return + } + return updateList({ + ...list, + isFavorite: !list.isFavorite, + }) + } + + async function createList(list: IList) { + const cancel = setModuleLoading(this, setIsLoading) + const listService = new ListService() + + try { + const createdList = await listService.create(list) + createdList.namespaceId = list.namespaceId + namespaceStore.addListToNamespace(createdList) + setList(createdList) + return createdList + } finally { + cancel() + } + } + + async function updateList(list: IList) { + const cancel = setModuleLoading(this, setIsLoading) + const listService = new ListService() + + try { + await listService.update(list) + setList(list) + namespaceStore.setListInNamespaceById(list) + + // the returned list from listService.update is the same! + // in order to not create a manipulation in pinia store we have to create a new copy + const newList = { + ...list, + namespaceId: FavoriteListsNamespace, } - return this.updateList({ + if (list.isFavorite) { + namespaceStore.addListToNamespace(newList) + } else { + namespaceStore.removeListFromNamespaceById(newList) + } + namespaceStore.loadNamespacesIfFavoritesDontExist() + namespaceStore.removeFavoritesNamespaceIfEmpty() + return newList + } catch (e) { + // Reset the list state to the initial one to avoid confusion for the user + setList({ ...list, isFavorite: !list.isFavorite, }) - }, + throw e + } finally { + cancel() + } + } - async createList(list: IList) { - const cancel = setModuleLoading(this) - const listService = new ListService() + async function deleteList(list: IList) { + const cancel = setModuleLoading(this, setIsLoading) + const listService = new ListService() - try { - const createdList = await listService.create(list) - createdList.namespaceId = list.namespaceId - const namespaceStore = useNamespaceStore() - namespaceStore.addListToNamespace(createdList) - this.setList(createdList) - return createdList - } finally { - cancel() - } - }, + try { + const response = await listService.delete(list) + removeListById(list) + namespaceStore.removeListFromNamespaceById(list) + removeListFromHistory({id: list.id}) + return response + } finally { + cancel() + } + } - async updateList(list: IList) { - const cancel = setModuleLoading(this) - const listService = new ListService() + return { + isLoading: readonly(isLoading), + lists: readonly(lists), - try { - await listService.update(list) - this.setList(list) - const namespaceStore = useNamespaceStore() - namespaceStore.setListInNamespaceById(list) + getListById, + findListByExactname, + searchList, - // the returned list from listService.update is the same! - // in order to not create a manipulation in pinia store we have to create a new copy - const newList = { - ...list, - namespaceId: FavoriteListsNamespace, - } - if (list.isFavorite) { - namespaceStore.addListToNamespace(newList) - } else { - namespaceStore.removeListFromNamespaceById(newList) - } - namespaceStore.loadNamespacesIfFavoritesDontExist(null) - namespaceStore.removeFavoritesNamespaceIfEmpty(null) - return newList - } catch (e) { - // Reset the list state to the initial one to avoid confusion for the user - this.setList({ - ...list, - isFavorite: !list.isFavorite, - }) - throw e - } finally { - cancel() - } - }, - - async deleteList(list: IList) { - const cancel = setModuleLoading(this) - const listService = new ListService() - - try { - const response = await listService.delete(list) - this.removeListById(list) - const namespaceStore = useNamespaceStore() - namespaceStore.removeListFromNamespaceById(list) - removeListFromHistory({id: list.id}) - return response - } finally { - cancel() - } - }, - }, + setList, + setLists, + removeListById, + toggleListFavorite, + createList, + updateList, + deleteList, + } }) export function useList(listId: MaybeRef) {