basic auto sync working
This commit is contained in:
parent
964afd5f73
commit
3cab0ab52e
@ -30,6 +30,7 @@ from django.http import FileResponse, HttpResponse, JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.timezone import make_aware
|
||||
from django.utils.translation import gettext as _
|
||||
from django_scopes import scopes_disabled
|
||||
from icalendar import Calendar, Event
|
||||
@ -1163,10 +1164,13 @@ class ShoppingListEntryViewSet(viewsets.ModelViewSet):
|
||||
if 'checked' in self.request.query_params or 'recent' in self.request.query_params:
|
||||
return shopping_helper(self.queryset, self.request)
|
||||
|
||||
last_autosync = self.request.query_params.get('last_autosync', None)
|
||||
if last_autosync:
|
||||
last_autosync = datetime.datetime.now() # TODO implement
|
||||
self.queryset = self.queryset.filter(updated_at__gte=last_autosync)
|
||||
try:
|
||||
last_autosync = self.request.query_params.get('last_autosync', None)
|
||||
if last_autosync:
|
||||
last_autosync = make_aware(datetime.datetime.fromtimestamp(int(last_autosync) / 1000))
|
||||
self.queryset = self.queryset.filter(updated_at__gte=last_autosync)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
# TODO once old shopping list is removed this needs updated to sharing users in preferences
|
||||
return self.queryset
|
||||
|
@ -29,9 +29,13 @@
|
||||
<!-- shopping list tab -->
|
||||
<b-tab active>
|
||||
<template #title>
|
||||
<b-spinner v-if="shopping_list_store.currently_updating" type="border" small class="d-inline-block"></b-spinner>
|
||||
<i v-if="!shopping_list_store.currently_updating" class="fas fa-shopping-cart fa-fw d-inline-block d-md-none"></i>
|
||||
<span class="d-none d-md-inline-block">{{ $t('Shopping_list') + ` (${Object.keys(shopping_list_store.entries).length})` }}</span> <!-- TODO properly count only checked -->
|
||||
<b-spinner v-if="shopping_list_store.currently_updating" type="border" small
|
||||
class="d-inline-block"></b-spinner>
|
||||
<i v-if="!shopping_list_store.currently_updating"
|
||||
class="fas fa-shopping-cart fa-fw d-inline-block d-md-none"></i>
|
||||
<span class="d-none d-md-inline-block">{{
|
||||
$t('Shopping_list') + ` (${Object.keys(shopping_list_store.entries).length})`
|
||||
}}</span> <!-- TODO properly count only checked -->
|
||||
</template>
|
||||
|
||||
<b-row class="d-lg-block d-print-none d-none pr-1 pl-1 mb-3 mt-3">
|
||||
@ -52,13 +56,17 @@
|
||||
|
||||
<!-- shopping list table -->
|
||||
<b-row v-for="c in shopping_list_store.get_entries_by_group" v-bind:key="c.id" class="pr-1 pl-1">
|
||||
<b-col cols="12" v-if="c.count_unchecked > 0 || user_preference_store.device_settings.shopping_show_checked_entries && (c.count_unchecked + c.count_ecked) > 0">
|
||||
<b-col cols="12"
|
||||
v-if="c.count_unchecked > 0 || user_preference_store.device_settings.shopping_show_checked_entries && (c.count_unchecked + c.count_ecked) > 0">
|
||||
<b-button-group class="w-100 mt-1">
|
||||
<b-button variant="light" block class="btn btn-block text-left">
|
||||
<span v-if="c.name === shopping_list_store.UNDEFINED_CATEGORY">{{ $t('Undefined') }}</span>
|
||||
<span v-if="c.name === shopping_list_store.UNDEFINED_CATEGORY">{{
|
||||
$t('Undefined')
|
||||
}}</span>
|
||||
<span v-else>{{ c.name }}</span>
|
||||
</b-button>
|
||||
<b-button variant="success"><i class="fas fa-check fa-fw"></i></b-button> <!-- todo implement -->
|
||||
<b-button variant="success"><i class="fas fa-check fa-fw"></i></b-button>
|
||||
<!-- todo implement -->
|
||||
</b-button-group>
|
||||
|
||||
<span v-for="f in c.foods" v-bind:key="f.id">
|
||||
@ -72,7 +80,9 @@
|
||||
<b-tab :title="$t('Recipes')">
|
||||
<template #title>
|
||||
<i class="fas fa-book fa-fw d-block d-md-none"></i>
|
||||
<span class="d-none d-md-block">{{ $t('Recipes') + ` (${Object.keys(shopping_list_store.getAssociatedRecipes()).length})` }}</span>
|
||||
<span class="d-none d-md-block">{{
|
||||
$t('Recipes') + ` (${Object.keys(shopping_list_store.getAssociatedRecipes()).length})`
|
||||
}}</span>
|
||||
</template>
|
||||
|
||||
<b-row class="d-lg-block d-print-none d-none pr-1 pl-1 mb-3 mt-3">
|
||||
@ -85,23 +95,37 @@
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row v-for="r in shopping_list_store.getAssociatedRecipes()" :key="r.shopping_list_recipe_id" class="pr-1 pl-1">
|
||||
<b-row v-for="r in shopping_list_store.getAssociatedRecipes()" :key="r.shopping_list_recipe_id"
|
||||
class="pr-1 pl-1">
|
||||
<b-col cols="12">
|
||||
<b-button-group class="w-100 mt-2">
|
||||
<b-button variant="dark" block class="btn btn-block text-left">
|
||||
<span>{{ r.recipe_name }}</span> <br/>
|
||||
<span><small class="text-muted">{{ r.recipe_name }}</small></span> <!-- TODO show meal plan date/type -->
|
||||
<span><small class="text-muted">{{ r.recipe_name }}</small></span>
|
||||
<!-- TODO show meal plan date/type -->
|
||||
</b-button>
|
||||
<!-- <b-form-input min="1" type="number" :debounce="300" v-model="r.servings" @update="updateServings(r.shopping_list_recipe_id, r.servings)"></b-form-input>-->
|
||||
<b-button variant="danger" @click="deleteRecipe(r.shopping_list_recipe_id)"><i class="fas fa-trash fa-fw"></i></b-button>
|
||||
<b-button variant="danger" @click="deleteRecipe(r.shopping_list_recipe_id)"><i
|
||||
class="fas fa-trash fa-fw"></i></b-button>
|
||||
</b-button-group>
|
||||
|
||||
<b-button-group class="w-100 mt-1">
|
||||
<b-button @click="r.servings = updateServings(r, 'half')" :disabled="shopping_list_store.currently_updating"><i class="fas fa-divide"></i> 2</b-button>
|
||||
<b-button variant="info" @click="r.servings = updateServings(r, 'sub')" :disabled="shopping_list_store.currently_updating"><i class="fas fa-minus"></i></b-button>
|
||||
<b-button variant="info" @click="r.servings = updateServings(r, 'prompt')">{{ r.servings }}</b-button>
|
||||
<b-button variant="info" @click="r.servings = updateServings(r, 'add')" :disabled="shopping_list_store.currently_updating"><i class="fas fa-plus"></i></b-button>
|
||||
<b-button @click="r.servings = updateServings(r, 'multiply')" :disabled="shopping_list_store.currently_updating"><i class="fas fa-times"></i> 2</b-button>
|
||||
<b-button @click="r.servings = updateServings(r, 'half')"
|
||||
:disabled="shopping_list_store.currently_updating"><i class="fas fa-divide"></i> 2
|
||||
</b-button>
|
||||
<b-button variant="info" @click="r.servings = updateServings(r, 'sub')"
|
||||
:disabled="shopping_list_store.currently_updating"><i class="fas fa-minus"></i>
|
||||
</b-button>
|
||||
<b-button variant="info" @click="r.servings = updateServings(r, 'prompt')">{{
|
||||
r.servings
|
||||
}}
|
||||
</b-button>
|
||||
<b-button variant="info" @click="r.servings = updateServings(r, 'add')"
|
||||
:disabled="shopping_list_store.currently_updating"><i class="fas fa-plus"></i>
|
||||
</b-button>
|
||||
<b-button @click="r.servings = updateServings(r, 'multiply')"
|
||||
:disabled="shopping_list_store.currently_updating"><i class="fas fa-times"></i> 2
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
|
||||
</b-col>
|
||||
@ -111,7 +135,9 @@
|
||||
<b-tab>
|
||||
<template #title>
|
||||
<i class="fas fa-store-alt fa-fw d-block d-md-none"></i>
|
||||
<span class="d-none d-md-block">{{ $t('Supermarkets') + ` (${shopping_list_store.supermarkets.length})` }}</span>
|
||||
<span class="d-none d-md-block">{{
|
||||
$t('Supermarkets') + ` (${shopping_list_store.supermarkets.length})`
|
||||
}}</span>
|
||||
</template>
|
||||
<div class="container p-0">
|
||||
<div class="row">
|
||||
@ -129,7 +155,8 @@
|
||||
></span></h5>
|
||||
<b-list-group>
|
||||
<b-card no-body class="mt-1 list-group-item p-2"
|
||||
v-for="(supermarket, index) in shopping_list_store.supermarkets" v-hover
|
||||
v-for="(supermarket, index) in shopping_list_store.supermarkets"
|
||||
v-hover
|
||||
:key="supermarket.id">
|
||||
<b-card-header class="p-2 border-0">
|
||||
<b-row>
|
||||
@ -188,7 +215,8 @@
|
||||
<div v-if="editingSupermarket.length === 0">
|
||||
<b-list-group>
|
||||
<b-card no-body class="mt-1 list-group-item p-2"
|
||||
v-for="(category, index) in shopping_list_store.supermarket_categories" v-hover
|
||||
v-for="(category, index) in shopping_list_store.supermarket_categories"
|
||||
v-hover
|
||||
:key="category.id">
|
||||
<b-card-header class="p-2 border-0">
|
||||
<b-row>
|
||||
@ -313,7 +341,8 @@
|
||||
</template>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-md-8">
|
||||
<shopping-settings-component @updated="settings = $event" :user_id="user_id"></shopping-settings-component>
|
||||
<shopping-settings-component @updated="settings = $event"
|
||||
:user_id="user_id"></shopping-settings-component>
|
||||
</div>
|
||||
</div>
|
||||
</b-tab>
|
||||
@ -324,37 +353,48 @@
|
||||
<div>
|
||||
<b-form-group v-bind:label="$t('GroupBy')" label-for="popover-input-1" label-cols="6" class="mb-1">
|
||||
<b-form-select v-model="user_preference_store.device_settings.shopping_selected_grouping" size="sm">
|
||||
<b-form-select-option v-for="go in shopping_list_store.grouping_options" :value="go.id" v-bind:key="go.id">{{ $t(go.translatable_label) }}</b-form-select-option>
|
||||
<b-form-select-option v-for="go in shopping_list_store.grouping_options" :value="go.id"
|
||||
v-bind:key="go.id">{{ $t(go.translatable_label) }}
|
||||
</b-form-select-option>
|
||||
</b-form-select>
|
||||
</b-form-group>
|
||||
<b-form-group v-bind:label="$t('Supermarket')" label-for="popover-input-2" label-cols="6" class="mb-1">
|
||||
<generic-multiselect :model="Models.SUPERMARKET" :initial_single_selection="user_preference_store.device_settings.shopping_selected_supermarket"
|
||||
@change="user_preference_store.device_settings.shopping_selected_supermarket = $event.val; user_preference_store.updateDeviceSettings()" :multiple="false"></generic-multiselect>
|
||||
<generic-multiselect :model="Models.SUPERMARKET"
|
||||
:initial_single_selection="user_preference_store.device_settings.shopping_selected_supermarket"
|
||||
@change="user_preference_store.device_settings.shopping_selected_supermarket = $event.val; user_preference_store.updateDeviceSettings()"
|
||||
:multiple="false"></generic-multiselect>
|
||||
</b-form-group>
|
||||
<b-form-group v-bind:label="$t('ShowDelayed')" label-for="popover-input-3" content-cols="1"
|
||||
class="mb-1">
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_show_delayed_entries" @change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_show_delayed_entries"
|
||||
@change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
</b-form-group>
|
||||
<b-form-group v-bind:label="$t('ShowRecentlyCompleted')" label-for="popover-input-3" content-cols="1"
|
||||
class="mb-1">
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_show_checked_entries" @change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_show_checked_entries"
|
||||
@change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
</b-form-group>
|
||||
<b-form-group v-bind:label="$t('SupermarketCategoriesOnly')" label-for="popover-input-5"
|
||||
content-cols="1" class="mb-1">
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_show_selected_supermarket_only" @change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
<b-form-checkbox
|
||||
v-model="user_preference_store.device_settings.shopping_show_selected_supermarket_only"
|
||||
@change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
</b-form-group>
|
||||
<span>{{ $t('Information') }}</span>
|
||||
<b-form-group v-bind:label="$t('Recipe')" label-for="popover-input-5"
|
||||
content-cols="1" class="mb-1">
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_item_info_recipe" @change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_item_info_recipe"
|
||||
@change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
</b-form-group>
|
||||
<b-form-group v-bind:label="$t('Meal_Plan')" label-for="popover-input-5"
|
||||
content-cols="1" class="mb-1">
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_item_info_mealplan" @change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_item_info_mealplan"
|
||||
@change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
</b-form-group>
|
||||
<b-form-group v-bind:label="$t('created_by')" label-for="popover-input-5"
|
||||
content-cols="1" class="mb-1">
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_item_info_created_by" @change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
<b-form-checkbox v-model="user_preference_store.device_settings.shopping_item_info_created_by"
|
||||
@change="user_preference_store.updateDeviceSettings()"></b-form-checkbox>
|
||||
</b-form-group>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 1vh; min-width: 300px">
|
||||
@ -366,7 +406,8 @@
|
||||
</div>
|
||||
</b-popover>
|
||||
|
||||
<shopping-modal v-if="new_recipe.id" :recipe="new_recipe" :modal_id="new_recipe.id" :servings="new_recipe.servings" :mealplan="undefined" @finish="finishShopping"/>
|
||||
<shopping-modal v-if="new_recipe.id" :recipe="new_recipe" :modal_id="new_recipe.id"
|
||||
:servings="new_recipe.servings" :mealplan="undefined" @finish="finishShopping"/>
|
||||
|
||||
<bottom-navigation-bar active-view="view_shopping">
|
||||
<template #custom_nav_content v-if="current_tab <= 1">
|
||||
@ -375,7 +416,8 @@
|
||||
|
||||
<template v-if="current_tab===0">
|
||||
<b-input-group>
|
||||
<b-form-input v-model="new_item.ingredient" :placeholder="$t('Food')" @keyup.enter="addItem"></b-form-input>
|
||||
<b-form-input v-model="new_item.ingredient" :placeholder="$t('Food')"
|
||||
@keyup.enter="addItem"></b-form-input>
|
||||
<b-input-group-append>
|
||||
<b-button @click="addItem" variant="success">
|
||||
<i class="fas fa-cart-plus "/>
|
||||
@ -535,45 +577,33 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
"settings.shopping_auto_sync": function (newVal, oldVal) {
|
||||
clearInterval(this.autosync_id)
|
||||
this.autosync_id = undefined
|
||||
if (this.settings.shopping_auto_sync > 0) {
|
||||
if (!newVal) {
|
||||
window.removeEventListener("online", this.updateOnlineStatus)
|
||||
window.removeEventListener("offline", this.updateOnlineStatus)
|
||||
return
|
||||
} else if (oldVal === 0 && newVal > 0) {
|
||||
window.addEventListener("online", this.updateOnlineStatus)
|
||||
window.addEventListener("offline", this.updateOnlineStatus)
|
||||
}
|
||||
this.autosync_id = setInterval(() => {
|
||||
if (this.online && !this.auto_sync_running) {
|
||||
this.auto_sync_running = true
|
||||
this.getShoppingList(true)
|
||||
}
|
||||
}, this.settings.shopping_auto_sync * 1000)
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
},
|
||||
watch: {},
|
||||
mounted() {
|
||||
//this.getShoppingList()
|
||||
|
||||
if (this.settings.shopping_auto_sync) {
|
||||
window.addEventListener("online", this.updateOnlineStatus)
|
||||
window.addEventListener("offline", this.updateOnlineStatus)
|
||||
}
|
||||
window.addEventListener("online", this.updateOnlineStatus)
|
||||
window.addEventListener("offline", this.updateOnlineStatus)
|
||||
|
||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||
|
||||
this.shopping_list_store.refreshFromAPI()
|
||||
this.setupAutoSync()
|
||||
},
|
||||
methods: {
|
||||
useShoppingListStore,
|
||||
setupAutoSync: function () {
|
||||
// prevent setting up multiple loops on accident
|
||||
// TODO should this just raise an error?
|
||||
clearInterval(this.autosync_id)
|
||||
this.autosync_id = undefined
|
||||
|
||||
let timeout = Math.max(this.settings.shopping_auto_sync, 1) * 1000 // if disabled (shopping_auto_sync=0) check again after 1 second if enabled
|
||||
|
||||
this.autosync_id = setInterval(() => { //TODO does setInterval automatically loop (because it kind of did)
|
||||
if (this.online && this.settings.shopping_auto_sync > 0) {
|
||||
this.shopping_list_store.autosync()
|
||||
this.setupAutoSync()
|
||||
}
|
||||
}, timeout)
|
||||
},
|
||||
/**
|
||||
* failed requests to sync entry check events are automatically re-queued by the service worker for sync
|
||||
* this command allows to manually force replaying those events before re-enabling automatic sync
|
||||
@ -589,6 +619,7 @@ export default {
|
||||
* get the number of entries left in the sync queue for entry check events
|
||||
* @returns {Promise<Number>} promise resolving to the number of entries left
|
||||
*/
|
||||
//TODO maybe show this somewhere if efficient enough to run often
|
||||
getSyncQueueLength: function () {
|
||||
const wb = new Workbox('/service-worker.js');
|
||||
wb.register();
|
||||
@ -740,14 +771,17 @@ export default {
|
||||
|
||||
if (recipe.servings > 0 && recipe.servings !== "") {
|
||||
let api = new ApiApiFactory()
|
||||
api.partialUpdateShoppingListRecipe(recipe.shopping_list_recipe_id, {id: recipe.shopping_list_recipe_id, servings: recipe.servings}).then(() => {
|
||||
api.partialUpdateShoppingListRecipe(recipe.shopping_list_recipe_id, {
|
||||
id: recipe.shopping_list_recipe_id,
|
||||
servings: recipe.servings
|
||||
}).then(() => {
|
||||
useShoppingListStore().refreshFromAPI()
|
||||
})
|
||||
return recipe.servings
|
||||
}
|
||||
},
|
||||
|
||||
// TODO cleanup, review data structure, probably move to its own component --> FOR ALL SUPERMARKET FUNCTIONS
|
||||
// TODO cleanup, review data structure, probably move to its own component --> FOR ALL SUPERMARKET FUNCTIONS
|
||||
deleteSupermarket(index) {
|
||||
this.$bvModal.msgBoxConfirm(this.$t('Are_You_Sure'), {
|
||||
title: this.$t('Confirm'),
|
||||
|
@ -4,6 +4,7 @@ import {defineStore} from "pinia"
|
||||
import Vue from "vue"
|
||||
import _ from 'lodash';
|
||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||
import moment from "moment/moment";
|
||||
|
||||
const _STORE_ID = "shopping_list_store"
|
||||
/*
|
||||
@ -19,6 +20,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
|
||||
// internal
|
||||
currently_updating: false,
|
||||
last_autosync: null,
|
||||
|
||||
// constants
|
||||
GROUP_CATEGORY: 'food.supermarket_category.name',
|
||||
@ -117,7 +119,10 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
* @return {[{id: *, translatable_label: string},{id: *, translatable_label: string},{id: *, translatable_label: string}]}
|
||||
*/
|
||||
grouping_options: function () {
|
||||
return [{'id': this.GROUP_CATEGORY, 'translatable_label': 'Category'}, {'id': this.GROUP_CREATED_BY, 'translatable_label': 'created_by'}, {
|
||||
return [{'id': this.GROUP_CATEGORY, 'translatable_label': 'Category'}, {
|
||||
'id': this.GROUP_CREATED_BY,
|
||||
'translatable_label': 'created_by'
|
||||
}, {
|
||||
'id': this.GROUP_RECIPE,
|
||||
'translatable_label': 'Recipe'
|
||||
}]
|
||||
@ -139,6 +144,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
})
|
||||
this.currently_updating = false
|
||||
}).catch((err) => {
|
||||
this.currently_updating = false
|
||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
||||
})
|
||||
|
||||
@ -155,6 +161,32 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
})
|
||||
}
|
||||
},
|
||||
autosync() {
|
||||
if (!this.currently_updating) {
|
||||
console.log('running autosync')
|
||||
this.currently_updating = true
|
||||
|
||||
let previous_autosync = this.last_autosync
|
||||
this.last_autosync = new Date().getTime();
|
||||
|
||||
let apiClient = new ApiApiFactory()
|
||||
apiClient.listShoppingListEntrys(undefined, undefined, undefined, {
|
||||
'query': {'last_autosync': previous_autosync}
|
||||
}).then((r) => {
|
||||
r.data.forEach((e) => {
|
||||
// dont update stale client data
|
||||
if (Date.parse(this.entries[e.id].updated_at) <= Date.parse(e.updated_at)) { //TODO validate the django datetime can be parsed in all browsers
|
||||
console.log('updating entry ', e)
|
||||
Vue.set(this.entries, e.id, e)
|
||||
}
|
||||
})
|
||||
this.currently_updating = false
|
||||
}).catch((err) => {
|
||||
console.log('auto sync failed')
|
||||
this.currently_updating = false
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Create a new shopping list entry
|
||||
* adds new entry to store
|
||||
@ -180,6 +212,10 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
*/
|
||||
updateObject(object) {
|
||||
let apiClient = new ApiApiFactory()
|
||||
// set 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())
|
||||
console.log('set local update timestamp to ', moment().format())
|
||||
return apiClient.updateShoppingListEntry(object.id, object).then((r) => {
|
||||
Vue.set(this.entries, r.data.id, r.data)
|
||||
}).catch((err) => {
|
||||
@ -238,7 +274,11 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
||||
Vue.set(structure, grouping_key, {'name': grouping_key, 'foods': {}})
|
||||
}
|
||||
if (!(entry.food.id in structure[grouping_key]['foods'])) {
|
||||
Vue.set(structure[grouping_key]['foods'], entry.food.id, {'id': entry.food.id, 'name': entry.food.name, 'entries': {}})
|
||||
Vue.set(structure[grouping_key]['foods'], entry.food.id, {
|
||||
'id': entry.food.id,
|
||||
'name': entry.food.name,
|
||||
'entries': {}
|
||||
})
|
||||
}
|
||||
Vue.set(structure[grouping_key]['foods'][entry.food.id]['entries'], entry.id, entry)
|
||||
return structure
|
||||
|
Loading…
Reference in New Issue
Block a user