import {defineStore} from 'pinia' import {ApiApiFactory, UserPreference} from "@/utils/openapi/api"; import Vue from "vue"; import {StandardToasts} from "@/utils/utils"; const _STALE_TIME_IN_MS = 1000 * 30 const _STORE_ID = 'user_preference_store' 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: () => ({ data: null, 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, shopping_show_delayed_entries: false, shopping_show_selected_supermarket_only: false, shopping_selected_grouping: 'food.supermarket_category.name', shopping_selected_supermarket: null, shopping_item_info_created_by: false, shopping_item_info_mealplan: true, shopping_item_info_recipe: true, }, }), 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(_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(_LS_DEVICE_SETTINGS, JSON.stringify(this.device_settings)) }, // ---------------- new methods for user settings loadUserSettings: function (allow_cached_results) { 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 || !allow_cached_results) { //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)) StandardToasts.makeStandardToast(this, StandardToasts.SUCCESS_UPDATE) }).catch(err => { this.currently_updating = false StandardToasts.makeStandardToast(this, StandardToasts.FAIL_UPDATE, err) }) }, // ---------------- // 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 * @returns {UserPreference|*|Promise>} */ getData: function () { if (this.isStaleOrEmpty) { return this.refreshFromAPI() } else { return this.data } }, /** * get data from store. Does not use API, if store is not initialized returns null. * @returns {null|UserPreference|*} */ getStaleData: function () { return this.data }, /** * checks if update timestamp is older than configured stale time interval * @returns {boolean} true if data is considered stale and should be updated */ isStale() { return this.updated_at === null || ((new Date()) - this.updated_at) > _STALE_TIME_IN_MS; }, /** * checks if data of store is empty/not initialized * @returns {boolean} true if store is empty */ isEmpty() { return this.data === null }, /** * checks if store is empty or data is considered stale, see isStale() and isEmpty() * @returns {boolean} */ isStaleOrEmpty() { return this.isStale() || this.isEmpty() }, /** * refreshes store data if isStaleOrEmpty() is true * @returns {Promise>} returns promise with data */ updateIfStaleOrEmpty() { if (this.isStaleOrEmpty) { return this.refreshFromAPI() } }, /** * refreshes store data from API * @returns {Promise>} returns promise with data */ refreshFromAPI() { let apiClient = new ApiApiFactory() if (!this.currently_updating) { this.currently_updating = true return apiClient.retrieveUserPreference(localStorage.getItem('USER_ID')).then(r => { 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 }) } }, }, })