Skip to content

Commit

Permalink
several shopping fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
vabene1111 committed Nov 27, 2024
1 parent 2fab51e commit 110ffe5
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 47 deletions.
14 changes: 9 additions & 5 deletions vue3/src/components/dialogs/ShoppingLineItemDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@
{{ $t('PostponedUntil') }} {{ DateTime.fromJSDate(e.delayUntil).toLocaleString(DateTime.DATETIME_SHORT) }}
</v-list-item-subtitle>
<template #append>
<v-btn size="small" color="delete" icon="$delete" v-if="!e.recipeMealplan">
<v-icon icon="$delete"></v-icon>
</v-btn>
</template>
<!-- <template #append>-->
<!-- <v-btn size="small" color="delete" icon="$delete" v-if="!e.recipeMealplan">-->
<!-- <v-icon icon="$delete"></v-icon>-->
<!-- </v-btn>-->
<!-- </template>-->
<!-- TODO make properly reactive or delete from the food instance in this component as well | ADD functionality once reactive -->
<model-edit-dialog model="ShoppingListEntry" :item="e" @delete="useShoppingStore().entries.delete(e.id!);" v-if="!e.recipeMealplan"></model-edit-dialog>
Expand Down Expand Up @@ -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
Expand Down
57 changes: 28 additions & 29 deletions vue3/src/components/display/ShoppingLineItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,25 @@
<span>
<i class="fas fa-check text-warning" v-if="a.checked && !isChecked"></i>
<i class="fas fa-hourglass-half text-primary" v-if="a.delayed && !a.checked"></i> <b>
{{ a.amount }}
<span :class="{'text-decoration-line-through': a.checked}">
{{ a.amount }}
</span>
<span v-if="a.unit">{{ a.unit.name }}</span>
</b>
</span>
<br/>
</span>
</div>
<div class="d-flex flex-column flex-grow-1 align-self-center">
{{ food.name }} <br/>
<span v-if="info_row"><small class="text-disabled">{{ info_row }}</small></span>
<div class="d-flex flex-column flex-grow-1 align-self-center" :class="{'text-decoration-line-through': isChecked}">
{{ shoppingListFood.food.name }} <br/>
<span v-if="infoRow"><small class="text-disabled">{{ infoRow }}</small></span>
</div>
</div>
</div>

<template #append>
<v-btn color="success" @click="useShoppingStore().setEntriesCheckedState(entries, !isChecked, true)"
:class="{'btn-success': !isChecked, 'btn-warning': isChecked}" icon="fa-solid fa-check" variant="plain">
<v-btn color="success" @click.native.stop="useShoppingStore().setEntriesCheckedState(entries, !isChecked, true);"
:class="{'btn-success': !isChecked, 'btn-warning': isChecked}" :icon="actionButtonIcon" variant="plain">
</v-btn>
<!-- <i class="d-print-none fa-fw fas" :class="{'fa-check': !isChecked , 'fa-cart-plus': isChecked }"></i>-->
</template>
Expand Down Expand Up @@ -63,6 +65,9 @@ const props = defineProps({
shoppingListFood: {type: {} as PropType<IShoppingListFood>, required: true},
})
/**
* ID of outer container, used by swipe system
*/
const itemContainerId = computed(() => {
let id = 'id_sli_'
for (let i in props.entries) {
Expand All @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -128,7 +146,7 @@ const amounts = computed((): Map<number, ShoppingLineAmount> => {
return unitAmounts
})
const info_row = computed(() => {
const infoRow = computed(() => {
let info_row = []
let authors = []
Expand Down Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions vue3/src/components/display/ShoppingListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,28 @@
</v-card-text>
</v-card>
</v-col>
<v-col cols="4">
<v-card>
<v-card-title>Sync Queue Debug</v-card-title>
<v-card-text>
Length: {{ useShoppingStore().itemCheckSyncQueue.length }} <br/>
Has Failed Items: {{ useShoppingStore().hasFailedItems()}}
<v-list>
<v-list-item v-for="i in useShoppingStore().itemCheckSyncQueue" :key="i">{{ i }}</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-col>
<v-col cols="4">
<v-card>
<v-card-title>Undo Debug</v-card-title>
<v-card-text>
<v-list>
<v-list-item v-for="i in useShoppingStore().undoStack" :key="i">{{ i.type }} {{ i.entries.flatMap(e => e.food.name)}}</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-container>
</v-window-item>
Expand Down
23 changes: 10 additions & 13 deletions vue3/src/stores/ShoppingStore.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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!)
})

Expand All @@ -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<void>[] = []

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)
})
Expand Down Expand Up @@ -542,6 +537,8 @@ export const useShoppingStore = defineStore(_STORE_ID, () => {
currentlyUpdating,
getFlatEntries,
hasFailedItems,
itemCheckSyncQueue,
undoStack,
refreshFromAPI,
autoSync,
createObject,
Expand Down

0 comments on commit 110ffe5

Please sign in to comment.