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.shortcuts import get_object_or_404, redirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.utils.timezone import make_aware
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from icalendar import Calendar, Event
|
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:
|
if 'checked' in self.request.query_params or 'recent' in self.request.query_params:
|
||||||
return shopping_helper(self.queryset, self.request)
|
return shopping_helper(self.queryset, self.request)
|
||||||
|
|
||||||
last_autosync = self.request.query_params.get('last_autosync', None)
|
try:
|
||||||
if last_autosync:
|
last_autosync = self.request.query_params.get('last_autosync', None)
|
||||||
last_autosync = datetime.datetime.now() # TODO implement
|
if last_autosync:
|
||||||
self.queryset = self.queryset.filter(updated_at__gte=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
|
# TODO once old shopping list is removed this needs updated to sharing users in preferences
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
@ -29,9 +29,13 @@
|
|||||||
<!-- shopping list tab -->
|
<!-- shopping list tab -->
|
||||||
<b-tab active>
|
<b-tab active>
|
||||||
<template #title>
|
<template #title>
|
||||||
<b-spinner v-if="shopping_list_store.currently_updating" type="border" small class="d-inline-block"></b-spinner>
|
<b-spinner v-if="shopping_list_store.currently_updating" type="border" small
|
||||||
<i v-if="!shopping_list_store.currently_updating" class="fas fa-shopping-cart fa-fw d-inline-block d-md-none"></i>
|
class="d-inline-block"></b-spinner>
|
||||||
<span class="d-none d-md-inline-block">{{ $t('Shopping_list') + ` (${Object.keys(shopping_list_store.entries).length})` }}</span> <!-- TODO properly count only checked -->
|
<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>
|
</template>
|
||||||
|
|
||||||
<b-row class="d-lg-block d-print-none d-none pr-1 pl-1 mb-3 mt-3">
|
<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 -->
|
<!-- 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-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-group class="w-100 mt-1">
|
||||||
<b-button variant="light" block class="btn btn-block text-left">
|
<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>
|
<span v-else>{{ c.name }}</span>
|
||||||
</b-button>
|
</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>
|
</b-button-group>
|
||||||
|
|
||||||
<span v-for="f in c.foods" v-bind:key="f.id">
|
<span v-for="f in c.foods" v-bind:key="f.id">
|
||||||
@ -72,7 +80,9 @@
|
|||||||
<b-tab :title="$t('Recipes')">
|
<b-tab :title="$t('Recipes')">
|
||||||
<template #title>
|
<template #title>
|
||||||
<i class="fas fa-book fa-fw d-block d-md-none"></i>
|
<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>
|
</template>
|
||||||
|
|
||||||
<b-row class="d-lg-block d-print-none d-none pr-1 pl-1 mb-3 mt-3">
|
<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-col>
|
||||||
</b-row>
|
</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-col cols="12">
|
||||||
<b-button-group class="w-100 mt-2">
|
<b-button-group class="w-100 mt-2">
|
||||||
<b-button variant="dark" block class="btn btn-block text-left">
|
<b-button variant="dark" block class="btn btn-block text-left">
|
||||||
<span>{{ r.recipe_name }}</span> <br/>
|
<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-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-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>
|
||||||
|
|
||||||
<b-button-group class="w-100 mt-1">
|
<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 @click="r.servings = updateServings(r, 'half')"
|
||||||
<b-button variant="info" @click="r.servings = updateServings(r, 'sub')" :disabled="shopping_list_store.currently_updating"><i class="fas fa-minus"></i></b-button>
|
:disabled="shopping_list_store.currently_updating"><i class="fas fa-divide"></i> 2
|
||||||
<b-button variant="info" @click="r.servings = updateServings(r, 'prompt')">{{ r.servings }}</b-button>
|
</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 variant="info" @click="r.servings = updateServings(r, 'sub')"
|
||||||
<b-button @click="r.servings = updateServings(r, 'multiply')" :disabled="shopping_list_store.currently_updating"><i class="fas fa-times"></i> 2</b-button>
|
: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-button-group>
|
||||||
|
|
||||||
</b-col>
|
</b-col>
|
||||||
@ -111,7 +135,9 @@
|
|||||||
<b-tab>
|
<b-tab>
|
||||||
<template #title>
|
<template #title>
|
||||||
<i class="fas fa-store-alt fa-fw d-block d-md-none"></i>
|
<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>
|
</template>
|
||||||
<div class="container p-0">
|
<div class="container p-0">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -129,7 +155,8 @@
|
|||||||
></span></h5>
|
></span></h5>
|
||||||
<b-list-group>
|
<b-list-group>
|
||||||
<b-card no-body class="mt-1 list-group-item p-2"
|
<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">
|
:key="supermarket.id">
|
||||||
<b-card-header class="p-2 border-0">
|
<b-card-header class="p-2 border-0">
|
||||||
<b-row>
|
<b-row>
|
||||||
@ -188,7 +215,8 @@
|
|||||||
<div v-if="editingSupermarket.length === 0">
|
<div v-if="editingSupermarket.length === 0">
|
||||||
<b-list-group>
|
<b-list-group>
|
||||||
<b-card no-body class="mt-1 list-group-item p-2"
|
<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">
|
:key="category.id">
|
||||||
<b-card-header class="p-2 border-0">
|
<b-card-header class="p-2 border-0">
|
||||||
<b-row>
|
<b-row>
|
||||||
@ -313,7 +341,8 @@
|
|||||||
</template>
|
</template>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-12 col-md-8">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</b-tab>
|
</b-tab>
|
||||||
@ -324,37 +353,48 @@
|
|||||||
<div>
|
<div>
|
||||||
<b-form-group v-bind:label="$t('GroupBy')" label-for="popover-input-1" label-cols="6" class="mb-1">
|
<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 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-select>
|
||||||
</b-form-group>
|
</b-form-group>
|
||||||
<b-form-group v-bind:label="$t('Supermarket')" label-for="popover-input-2" label-cols="6" class="mb-1">
|
<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"
|
<generic-multiselect :model="Models.SUPERMARKET"
|
||||||
@change="user_preference_store.device_settings.shopping_selected_supermarket = $event.val; user_preference_store.updateDeviceSettings()" :multiple="false"></generic-multiselect>
|
: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>
|
||||||
<b-form-group v-bind:label="$t('ShowDelayed')" label-for="popover-input-3" content-cols="1"
|
<b-form-group v-bind:label="$t('ShowDelayed')" label-for="popover-input-3" content-cols="1"
|
||||||
class="mb-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>
|
||||||
<b-form-group v-bind:label="$t('ShowRecentlyCompleted')" label-for="popover-input-3" content-cols="1"
|
<b-form-group v-bind:label="$t('ShowRecentlyCompleted')" label-for="popover-input-3" content-cols="1"
|
||||||
class="mb-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>
|
||||||
<b-form-group v-bind:label="$t('SupermarketCategoriesOnly')" label-for="popover-input-5"
|
<b-form-group v-bind:label="$t('SupermarketCategoriesOnly')" label-for="popover-input-5"
|
||||||
content-cols="1" class="mb-1">
|
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>
|
</b-form-group>
|
||||||
<span>{{ $t('Information') }}</span>
|
<span>{{ $t('Information') }}</span>
|
||||||
<b-form-group v-bind:label="$t('Recipe')" label-for="popover-input-5"
|
<b-form-group v-bind:label="$t('Recipe')" label-for="popover-input-5"
|
||||||
content-cols="1" class="mb-1">
|
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>
|
||||||
<b-form-group v-bind:label="$t('Meal_Plan')" label-for="popover-input-5"
|
<b-form-group v-bind:label="$t('Meal_Plan')" label-for="popover-input-5"
|
||||||
content-cols="1" class="mb-1">
|
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>
|
||||||
<b-form-group v-bind:label="$t('created_by')" label-for="popover-input-5"
|
<b-form-group v-bind:label="$t('created_by')" label-for="popover-input-5"
|
||||||
content-cols="1" class="mb-1">
|
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>
|
</b-form-group>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="margin-top: 1vh; min-width: 300px">
|
<div class="row" style="margin-top: 1vh; min-width: 300px">
|
||||||
@ -366,7 +406,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</b-popover>
|
</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">
|
<bottom-navigation-bar active-view="view_shopping">
|
||||||
<template #custom_nav_content v-if="current_tab <= 1">
|
<template #custom_nav_content v-if="current_tab <= 1">
|
||||||
@ -375,7 +416,8 @@
|
|||||||
|
|
||||||
<template v-if="current_tab===0">
|
<template v-if="current_tab===0">
|
||||||
<b-input-group>
|
<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-input-group-append>
|
||||||
<b-button @click="addItem" variant="success">
|
<b-button @click="addItem" variant="success">
|
||||||
<i class="fas fa-cart-plus "/>
|
<i class="fas fa-cart-plus "/>
|
||||||
@ -535,45 +577,33 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
//this.getShoppingList()
|
window.addEventListener("online", this.updateOnlineStatus)
|
||||||
|
window.addEventListener("offline", this.updateOnlineStatus)
|
||||||
if (this.settings.shopping_auto_sync) {
|
|
||||||
window.addEventListener("online", this.updateOnlineStatus)
|
|
||||||
window.addEventListener("offline", this.updateOnlineStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$i18n.locale = window.CUSTOM_LOCALE
|
this.$i18n.locale = window.CUSTOM_LOCALE
|
||||||
|
|
||||||
this.shopping_list_store.refreshFromAPI()
|
this.shopping_list_store.refreshFromAPI()
|
||||||
|
this.setupAutoSync()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
useShoppingListStore,
|
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
|
* 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
|
* 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
|
* 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
|
* @returns {Promise<Number>} promise resolving to the number of entries left
|
||||||
*/
|
*/
|
||||||
|
//TODO maybe show this somewhere if efficient enough to run often
|
||||||
getSyncQueueLength: function () {
|
getSyncQueueLength: function () {
|
||||||
const wb = new Workbox('/service-worker.js');
|
const wb = new Workbox('/service-worker.js');
|
||||||
wb.register();
|
wb.register();
|
||||||
@ -740,14 +771,17 @@ export default {
|
|||||||
|
|
||||||
if (recipe.servings > 0 && recipe.servings !== "") {
|
if (recipe.servings > 0 && recipe.servings !== "") {
|
||||||
let api = new ApiApiFactory()
|
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()
|
useShoppingListStore().refreshFromAPI()
|
||||||
})
|
})
|
||||||
return recipe.servings
|
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) {
|
deleteSupermarket(index) {
|
||||||
this.$bvModal.msgBoxConfirm(this.$t('Are_You_Sure'), {
|
this.$bvModal.msgBoxConfirm(this.$t('Are_You_Sure'), {
|
||||||
title: this.$t('Confirm'),
|
title: this.$t('Confirm'),
|
||||||
|
@ -4,6 +4,7 @@ import {defineStore} from "pinia"
|
|||||||
import Vue from "vue"
|
import Vue from "vue"
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||||
|
import moment from "moment/moment";
|
||||||
|
|
||||||
const _STORE_ID = "shopping_list_store"
|
const _STORE_ID = "shopping_list_store"
|
||||||
/*
|
/*
|
||||||
@ -19,6 +20,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
|||||||
|
|
||||||
// internal
|
// internal
|
||||||
currently_updating: false,
|
currently_updating: false,
|
||||||
|
last_autosync: null,
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
GROUP_CATEGORY: 'food.supermarket_category.name',
|
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}]}
|
* @return {[{id: *, translatable_label: string},{id: *, translatable_label: string},{id: *, translatable_label: string}]}
|
||||||
*/
|
*/
|
||||||
grouping_options: function () {
|
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,
|
'id': this.GROUP_RECIPE,
|
||||||
'translatable_label': 'Recipe'
|
'translatable_label': 'Recipe'
|
||||||
}]
|
}]
|
||||||
@ -139,6 +144,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
|||||||
})
|
})
|
||||||
this.currently_updating = false
|
this.currently_updating = false
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
this.currently_updating = false
|
||||||
StandardToasts.makeStandardToast(this, StandardToasts.FAIL_FETCH, err)
|
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
|
* Create a new shopping list entry
|
||||||
* adds new entry to store
|
* adds new entry to store
|
||||||
@ -180,6 +212,10 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
|||||||
*/
|
*/
|
||||||
updateObject(object) {
|
updateObject(object) {
|
||||||
let apiClient = new ApiApiFactory()
|
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) => {
|
return apiClient.updateShoppingListEntry(object.id, object).then((r) => {
|
||||||
Vue.set(this.entries, r.data.id, r.data)
|
Vue.set(this.entries, r.data.id, r.data)
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
@ -238,7 +274,11 @@ export const useShoppingListStore = defineStore(_STORE_ID, {
|
|||||||
Vue.set(structure, grouping_key, {'name': grouping_key, 'foods': {}})
|
Vue.set(structure, grouping_key, {'name': grouping_key, 'foods': {}})
|
||||||
}
|
}
|
||||||
if (!(entry.food.id in structure[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)
|
Vue.set(structure[grouping_key]['foods'][entry.food.id]['entries'], entry.id, entry)
|
||||||
return structure
|
return structure
|
||||||
|
Loading…
Reference in New Issue
Block a user