diff --git a/vue/src/apps/ShoppingListView/ShoppingListView.vue b/vue/src/apps/ShoppingListView/ShoppingListView.vue index 893c06aa..0c58d393 100644 --- a/vue/src/apps/ShoppingListView/ShoppingListView.vue +++ b/vue/src/apps/ShoppingListView/ShoppingListView.vue @@ -12,11 +12,11 @@ @@ -341,7 +341,7 @@
-
@@ -444,11 +444,11 @@ - - - @@ -518,19 +518,7 @@ export default { entry_mode_simple: true, selected_supermarket: undefined, }, - settings: { - shopping_auto_sync: 0, - default_delay: 4, - mealplan_autoadd_shopping: false, - mealplan_autoinclude_related: false, - mealplan_autoexclude_onhand: true, - filter_to_supermarket: false, - shopping_recent_days: 7, - csv_delim: ",", - csv_prefix: undefined, - shopping_add_onhand: true, - left_handed: false, - }, + user_id: parseInt(localStorage.getItem('USER_ID')), editing_supermarket_categories: [], editing_supermarket: null, @@ -585,6 +573,8 @@ export default { this.$i18n.locale = window.CUSTOM_LOCALE this.shopping_list_store.refreshFromAPI() + useUserPreferenceStore().loadUserSettings() + useUserPreferenceStore().loadDeviceSettings() this.setupAutoSync() }, methods: { @@ -595,10 +585,10 @@ export default { 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 + let timeout = Math.max(this.user_preference_store.user_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) { + if (this.online && this.user_preference_store.user_settings.shopping_auto_sync > 0) { this.shopping_list_store.autosync() this.setupAutoSync() } diff --git a/vue/src/stores/ShoppingListStore.js b/vue/src/stores/ShoppingListStore.js index 80d8cb73..02279b46 100644 --- a/vue/src/stores/ShoppingListStore.js +++ b/vue/src/stores/ShoppingListStore.js @@ -215,7 +215,7 @@ export const useShoppingListStore = defineStore(_STORE_ID, { // 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) => { diff --git a/vue/src/stores/UserPreferenceStore.js b/vue/src/stores/UserPreferenceStore.js index b378eeb3..8328c3d0 100644 --- a/vue/src/stores/UserPreferenceStore.js +++ b/vue/src/stores/UserPreferenceStore.js @@ -1,14 +1,15 @@ import {defineStore} from 'pinia' -import {ApiApiFactory} from "@/utils/openapi/api"; +import {ApiApiFactory, UserPreference} from "@/utils/openapi/api"; import Vue from "vue"; const _STALE_TIME_IN_MS = 1000 * 30 const _STORE_ID = 'user_preference_store' -const _LOCAL_STORAGE_KEY = 'TANDOOR_LOCAL_SETTINGS' - +const _LS_DEVICE_SETTINGS = 'TANDOOR_LOCAL_SETTINGS' +const _LS_USER_SETTINGS = 'TANDOOR_USER_SETTINGS' +const _USER_ID = localStorage.getItem('USER_ID') export const useUserPreferenceStore = defineStore(_STORE_ID, { state: () => ({ @@ -16,7 +17,41 @@ export const useUserPreferenceStore = defineStore(_STORE_ID, { updated_at: null, currently_updating: false, + user_settings_loaded_at: new Date(0), + user_settings: { + image: null, + theme: "TANDOOR", + nav_bg_color: "#ddbf86", + nav_text_color: "DARK", + nav_show_logo: true, + default_unit: "g", + default_page: "SEARCH", + use_fractions: false, + use_kj: false, + plan_share: [], + nav_sticky: true, + ingredient_decimals: 2, + comments: true, + shopping_auto_sync: 5, + mealplan_autoadd_shopping: false, + food_inherit_default: [], + default_delay: "4.0000", + mealplan_autoinclude_related: true, + mealplan_autoexclude_onhand: true, + shopping_share: [], + shopping_recent_days: 7, + csv_delim: ",", + csv_prefix: "", + filter_to_supermarket: false, + shopping_add_onhand: false, + left_handed: false, + show_step_ingredients: true, + food_children_exist: false, + locally_updated_at: new Date(0), + }, + device_settings_initialized: false, + device_settings_loaded_at: new Date(0), device_settings: { // shopping shopping_show_checked_entries: false, @@ -29,36 +64,69 @@ export const useUserPreferenceStore = defineStore(_STORE_ID, { shopping_item_info_recipe: true, }, }), - getters: { - get_device_settings: function () { - if (!this.device_settings_initialized) { - // stupid hack to initialize device settings variable when store loads - this.loadDeviceSettings() - this.device_settings_initialized = true - } - return this.device_settings - } - }, + getters: {}, actions: { // Device settings (on device settings stored in local storage) /** * Load device settings from local storage and update state device_settings */ loadDeviceSettings() { - let s = localStorage.getItem(_LOCAL_STORAGE_KEY) + let s = localStorage.getItem(_LS_DEVICE_SETTINGS) if (!(s === null || s === {})) { let settings = JSON.parse(s) for (s in settings) { Vue.set(this.device_settings, s, settings[s]) } } + this.device_settings_initialized = true }, /** * persist changes to device settings into local storage */ updateDeviceSettings: function () { - localStorage.setItem(_LOCAL_STORAGE_KEY, JSON.stringify(this.device_settings)) + localStorage.setItem(_LS_DEVICE_SETTINGS, JSON.stringify(this.device_settings)) }, + // ---------------- new methods for user settings + loadUserSettings: function () { + let s = localStorage.getItem(_LS_USER_SETTINGS) + if (!(s === null || s === {})) { + let settings = JSON.parse(s) + for (s in settings) { + Vue.set(this.user_settings, s, settings[s]) + } + console.log(`loaded local user settings age ${((new Date().getTime()) - this.user_settings.locally_updated_at) / 1000} `) + } + if (((new Date().getTime()) - this.user_settings.locally_updated_at) > _STALE_TIME_IN_MS) { + console.log('refreshing user settings from API') + let apiClient = new ApiApiFactory() + apiClient.retrieveUserPreference(localStorage.getItem('USER_ID')).then(r => { + for (s in r.data) { + if (!(s in this.user_settings) && s !== 'user') { + // dont load new keys if no default exists (to prevent forgetting to add defaults) + console.error(`API returned UserPreference key "${s}" which has no default in UserPreferenceStore.user_settings.`) + } else { + Vue.set(this.user_settings, s, r.data[s]) + } + } + Vue.set(this.user_settings, 'locally_updated_at', new Date().getTime()) + localStorage.setItem(_LS_USER_SETTINGS, JSON.stringify(this.user_settings)) + }).catch(err => { + this.currently_updating = false + }) + } + + }, + updateUserSettings: function () { + let apiClient = new ApiApiFactory() + apiClient.partialUpdateUserPreference(_USER_ID, this.user_settings).then(r => { + this.user_settings = r.data + Vue.set(this.user_settings, 'locally_updated_at', new Date().getTime()) + localStorage.setItem(_LS_USER_SETTINGS, JSON.stringify(this.user_settings)) + }).catch(err => { + this.currently_updating = false + }) + }, + // ---------------- // User Preferences (database settings stored in user preference model) /** * gets data from the store either directly or refreshes from API if data is considered stale @@ -120,6 +188,10 @@ export const useUserPreferenceStore = defineStore(_STORE_ID, { this.data = r.data this.updated_at = new Date() this.currently_updating = false + + this.user_settings = r.data + this.user_settings_loaded_at = new Date() + return this.data }).catch(err => { this.currently_updating = false