diff --git a/vue3/src/components/dialogs/ShoppingLineItemDialog.vue b/vue3/src/components/dialogs/ShoppingLineItemDialog.vue index f1d6ddd7c..e3102eed5 100644 --- a/vue3/src/components/dialogs/ShoppingLineItemDialog.vue +++ b/vue3/src/components/dialogs/ShoppingLineItemDialog.vue @@ -66,11 +66,11 @@ {{ $t('PostponedUntil') }} {{ DateTime.fromJSDate(e.delayUntil).toLocaleString(DateTime.DATETIME_SHORT) }} - + + + + + @@ -126,6 +126,10 @@ const isShoppingLineDelayed = computed(() => { return isShoppingListFoodDelayed(shoppingListFood.value) }) +/** + * change category of food and update via API + * @param category + */ function categoryUpdate(category: SupermarketCategory) { const api = new ApiApi() shoppingListFood.value.food.supermarketCategory = category diff --git a/vue3/src/components/display/ShoppingLineItem.vue b/vue3/src/components/display/ShoppingLineItem.vue index d432f1712..0151aef0b 100644 --- a/vue3/src/components/display/ShoppingLineItem.vue +++ b/vue3/src/components/display/ShoppingLineItem.vue @@ -15,23 +15,25 @@ - {{ a.amount }} + + {{ a.amount }} + {{ a.unit.name }}
-
- {{ food.name }}
- {{ info_row }} +
+ {{ shoppingListFood.food.name }}
+ {{ infoRow }}
@@ -63,6 +65,9 @@ const props = defineProps({ shoppingListFood: {type: {} as PropType, required: true}, }) +/** + * ID of outer container, used by swipe system + */ const itemContainerId = computed(() => { let id = 'id_sli_' for (let i in props.entries) { @@ -71,6 +76,10 @@ const itemContainerId = computed(() => { return id }) + +/** + * tests if all entries of the given food are checked + */ const isChecked = computed(() => { for (let i in props.entries) { if (!props.entries[i].checked) { @@ -80,15 +89,24 @@ const isChecked = computed(() => { return true }) +/** + * determine if any entry in a given IShoppingListFood is delayed, if so return true + */ const isShoppingLineDelayed = computed(() => { return isShoppingListFoodDelayed(props.shoppingListFood) }) - -const food = computed(() => { - return props.entries[Object.keys(props.entries)[0]]['food'] +/** + * style action button depending on if all items are checked or not + */ +const actionButtonIcon = computed(() => { + if (isChecked.value){ + return 'fa-solid fa-plus' + } + return 'fa-solid fa-check' }) + /** * calculate the amounts for the given line * can combine 1 to n entries with the same unit @@ -128,7 +146,7 @@ const amounts = computed((): Map => { return unitAmounts }) -const info_row = computed(() => { +const infoRow = computed(() => { let info_row = [] let authors = [] @@ -170,25 +188,6 @@ const info_row = computed(() => { return info_row.join(' - ') }) -// TODO implement -/** - * update the food after the category was changed - * handle changing category to category ID as a workaround - * @param food - */ -function updateFoodCategory(food: Food) { - // if (typeof food.supermarketCategory === "number") { // not the best solution, but as long as generic multiselect does not support caching, I don't want to use a proper model - // food.supermarket_category = this.useShoppingListStore().supermarket_categories.filter(sc => sc.id === food.supermarket_category)[0] - // } - // - // let apiClient = new ApiApiFactory() - // apiClient.updateFood(food.id, food).then(r => { - // - // }).catch((err) => { - // StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err) - // }) -} - /** * set food on_hand status to true and check all associated entries * @param food diff --git a/vue3/src/components/display/ShoppingListView.vue b/vue3/src/components/display/ShoppingListView.vue index 1453a2bf9..1cfd01280 100644 --- a/vue3/src/components/display/ShoppingListView.vue +++ b/vue3/src/components/display/ShoppingListView.vue @@ -92,6 +92,28 @@ + + + Sync Queue Debug + + Length: {{ useShoppingStore().itemCheckSyncQueue.length }}
+ Has Failed Items: {{ useShoppingStore().hasFailedItems()}} + + {{ i }} + +
+
+
+ + + Undo Debug + + + {{ i.type }} {{ i.entries.flatMap(e => e.food.name)}} + + + + diff --git a/vue3/src/stores/ShoppingStore.ts b/vue3/src/stores/ShoppingStore.ts index 33eec1c8f..f6cc59dc9 100644 --- a/vue3/src/stores/ShoppingStore.ts +++ b/vue3/src/stores/ShoppingStore.ts @@ -1,5 +1,5 @@ import {acceptHMRUpdate, defineStore} from "pinia" -import {ApiApi, Food, ShoppingListEntry, Supermarket, SupermarketCategory} from "@/openapi"; +import {ApiApi, Food, ShoppingListEntry, ShoppingListEntryBulk, Supermarket, SupermarketCategory} from "@/openapi"; import {computed, ref} from "vue"; import { IShoppingExportEntry, @@ -346,7 +346,6 @@ export const useShoppingStore = defineStore(_STORE_ID, () => { let entryIdList: number[] = [] entries.forEach(entry => { entry.checked = checked - // TODO used to set updatedAt but does not make sense on client, rethink solution (as above) entryIdList.push(entry.id!) }) @@ -367,34 +366,30 @@ export const useShoppingStore = defineStore(_STORE_ID, () => { function _replaySyncQueue() { if (navigator.onLine || document.location.href.includes('localhost')) { let api = new ApiApi() - let promises = [] + let promises: Promise[] = [] - for (let i in itemCheckSyncQueue.value) { - let entry = itemCheckSyncQueue.value[i] + itemCheckSyncQueue.value.forEach((entry, index) => { entry['status'] = ((entry['status'] === 'waiting') ? 'syncing' : 'syncing_failed_before') - itemCheckSyncQueue.value[i] = entry - // TODO set timeout for request (previously was 15000ms) or check that default timeout is similar - let p = api.apiShoppingListEntryBulkCreate({shoppingListEntryBulk: entry}, {}).then((r) => { + let p = api.apiShoppingListEntryBulkCreate({shoppingListEntryBulk: entry}, {}).then((r) => { entry.ids.forEach(id => { let e = entries.value.get(id) e.updatedAt = r.timestamp entries.value.set(id, e) }) - delete itemCheckSyncQueue.value[i] + itemCheckSyncQueue.value.splice(index,1) }).catch((err) => { if (err.code === "ERR_NETWORK" || err.code === "ECONNABORTED") { entry['status'] = 'waiting_failed_before' - itemCheckSyncQueue.value[i] = entry } else { - delete itemCheckSyncQueue.value[i] + itemCheckSyncQueue.value.splice(index,1) console.error('Failed API call for entry ', entry) useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err) } }) promises.push(p) - } - + }) + // TODO verify this all settled works Promise.allSettled(promises).finally(() => { runSyncQueue(500) }) @@ -542,6 +537,8 @@ export const useShoppingStore = defineStore(_STORE_ID, () => { currentlyUpdating, getFlatEntries, hasFailedItems, + itemCheckSyncQueue, + undoStack, refreshFromAPI, autoSync, createObject,