From 995d423a6fc6a13ef5dfe652b2ca18fb8f603426 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Sat, 13 Jan 2024 21:30:48 +0800 Subject: [PATCH] WIP shopping undo --- .../ShoppingListView/ShoppingListView.vue | 2 + vue/src/components/ShoppingLineItem.vue | 3 +- vue/src/stores/ShoppingListStore.js | 40 ++++++++++++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/vue/src/apps/ShoppingListView/ShoppingListView.vue b/vue/src/apps/ShoppingListView/ShoppingListView.vue index 42f0b088f..b3e617966 100644 --- a/vue/src/apps/ShoppingListView/ShoppingListView.vue +++ b/vue/src/apps/ShoppingListView/ShoppingListView.vue @@ -2,6 +2,8 @@
{{ $t("OfflineAlert") }} + Undo +
diff --git a/vue/src/components/ShoppingLineItem.vue b/vue/src/components/ShoppingLineItem.vue index 0edaaa6a5..f6f080062 100644 --- a/vue/src/components/ShoppingLineItem.vue +++ b/vue/src/components/ShoppingLineItem.vue @@ -95,7 +95,7 @@ import Vue from "vue" import {BootstrapVue} from "bootstrap-vue" import "bootstrap-vue/dist/bootstrap-vue.css" -import {ApiMixin, getThemeDependentDarkButton, resolveDjangoUrl, StandardToasts} from "@/utils/utils" +import {ApiMixin, resolveDjangoUrl, StandardToasts} from "@/utils/utils" import {useMealPlanStore} from "@/stores/MealPlanStore"; import {useShoppingListStore} from "@/stores/ShoppingListStore"; import {ApiApiFactory} from "@/utils/openapi/api"; @@ -224,7 +224,6 @@ export default { }, methods: { - getThemeDependentDarkButton, useUserPreferenceStore, useShoppingListStore, resolveDjangoUrl, diff --git a/vue/src/stores/ShoppingListStore.js b/vue/src/stores/ShoppingListStore.js index 02279b461..5b656226e 100644 --- a/vue/src/stores/ShoppingListStore.js +++ b/vue/src/stores/ShoppingListStore.js @@ -21,6 +21,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, { // internal currently_updating: false, last_autosync: null, + undo_stack: [], // constants GROUP_CATEGORY: 'food.supermarket_category.name', @@ -200,19 +201,22 @@ export const useShoppingListStore = defineStore(_STORE_ID, { return apiClient.createShoppingListEntry(object).then((r) => { Vue.set(this.entries, r.data.id, r.data) + + this.registerChange('CREATED', r.data, undefined, undefined) }).catch((err) => { StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err) }) }, /** - * update existing entry object + * update existing entry object and updated_at timestamp * updates data in store + * IMPORTANT: always use this method to update objects to keep client state consistent * @param object entry object to update * @return {Promise} promise of updating call to subscribe to */ updateObject(object) { let apiClient = new ApiApiFactory() - // set the update_at timestamp on the client to prevent auto sync from overriding with older changes + // sets the update_at timestamp on the client to prevent auto sync from overriding with older changes // moment().format() yields locale aware datetime without ms 2024-01-04T13:39:08.607238+01:00 Vue.set(object, 'update_at', moment().format()) @@ -317,5 +321,37 @@ export const useShoppingListStore = defineStore(_STORE_ID, { this.deleteObject(this.entries[i]) } }, + /** + * + */ + registerChange(type, entries, new_value, old_value) { + if (!(type in ['CREATED', 'CHECKED', 'UNCHECKED', 'DELAY'])) { + //throw Error('Tried to register unknown change type') + } + + this.undo_stack.push({'type': type, 'new_value': new_value, 'old_value': old_value, 'entries': entries}) + }, + /** + * + */ + undoChange() { + let last_item = this.undo_stack.pop() + let type = last_item['type'] + let entries = last_item['entries'] + + for (let i in entries) { + let e = entries[i] + if (type === 'CREATED') { + this.deleteObject(e) + } else if (type === 'CHECKED' || type === 'UNCHECKED') { + e.checked = (type === 'UNCHECKED') + this.updateObject(e) + } else if (type === 'DELAY'){ + e.delay_until = null + this.updateObject(e) + } + + } + } }, })