UNPKG

@geogirafe/lib-geoportal

Version:

GeoGirafe is a flexible application to build online geoportals.

156 lines (155 loc) • 6.64 kB
// SPDX-License-Identifier: Apache-2.0 import GirafeSingleton from '../../base/GirafeSingleton.js'; import { createObjectFromPath, deletePropertyByPath, getPropertyByPath, setPropertyByPath, mergeObjects } from '../utils/pathUtils.js'; /** * Manages user data storage and retrieval across different storage sources. * The class supports localStorage and server as storage options (server-side implementation currently not available). * It provides functionality to set, get, save, and delete user data while maintaining the flexibility to target specific paths * within the user data object. */ class UserDataManager extends GirafeSingleton { // Using the full URL as storage key allows having separate user data for apps under the same base URL (e.g. demo apps) storageKey = window.location.origin + window.location.pathname; config; allowSaveUserPreferences = true; initializeFromConfig(config) { this.config = config; } userData; userDataPromise; /** * Retrieves a specific part of the user data defined by the storage path. * @param storagePath path in the user data object to the requested value. * @returns the partial user data object. */ async getUserData(storagePath) { if (this.userData) { // User Data were already loaded return this.extractValue(this.userData, storagePath); } this.userDataPromise = this.load().catch((error) => { this.userDataPromise = undefined; throw error; }); this.userData = await this.userDataPromise; return this.extractValue(this.userData, storagePath); } getFromLocalStorage(storagePath) { const storedUserData = localStorage.getItem(this.storageKey); const userData = storedUserData ? JSON.parse(storedUserData) : {}; return this.extractValue(userData, storagePath); } extractValue(data, storagePath) { const { found, parentObject, lastKey } = getPropertyByPath(data, storagePath); return found && parentObject && lastKey ? parentObject[lastKey] : undefined; } async load() { if (this.config.source === 'localStorage') { return this.loadFromLocalStorage(); } else if (this.config.source === 'server') { const userdata = await this.loadFromServer(); return userdata; } throw new Error(`Unknown source for user preferences: ${this.config.source}`); } loadFromLocalStorage() { const storedUserData = localStorage.getItem(this.storageKey); return storedUserData ? JSON.parse(storedUserData) : {}; } async loadFromServer() { try { const response = await fetch(this.config.getUrl); const storedUserData = await response.json(); return storedUserData; } catch { // Cannot load user preference from server. // In this case, we deactivate the save process for user preferences // (because we do not want to override the existing user-preferences if they could not be loaded for some reason) // And we return empty preferences, because we want to be able to start the application // even if the user preferences could not be retrieved. this.allowSaveUserPreferences = false; this.context.errorManager.pushMessage('loadUserPreferencesError', 'User Preferences could not be loaded. Try refreshing the page or contact your administrator.', 'error'); return {}; } } async saveUserData(storagePath, newValue) { if (!getPropertyByPath(this.userData, storagePath).found) { // Object does not exist in user data yet, create it const newUserData = createObjectFromPath(storagePath); this.userData = mergeObjects(this.userData ?? {}, newUserData); } if (setPropertyByPath(this.userData, storagePath, newValue)) { await this.save(this.userData ?? {}); } } saveToLocalStorage(storagePath, newValue) { let fullUserDataObject = this.loadFromLocalStorage(); if (!getPropertyByPath(fullUserDataObject, storagePath).found) { // Object does not exist in user data yet, create it const newUserData = createObjectFromPath(storagePath); fullUserDataObject = mergeObjects(fullUserDataObject, newUserData); } if (setPropertyByPath(fullUserDataObject, storagePath, newValue)) { this.writeToLocalStorage(fullUserDataObject); } } async save(fullUserDataObject) { if (this.config.source === 'localStorage') { this.writeToLocalStorage(fullUserDataObject); } else if (this.config.source === 'server') { await this.writeToServer(fullUserDataObject); } else { throw new Error(`Unknown source for user preferences: ${this.config.source}`); } } writeToLocalStorage(fullUserDataObject) { localStorage.setItem(this.storageKey, JSON.stringify(fullUserDataObject)); } async writeToServer(fullUserDataObject) { if (!this.allowSaveUserPreferences) { return; } const response = await fetch(this.config.postUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(fullUserDataObject) }); if (!response.ok) { console.error(response.text); throw new Error(`Error while saving user preferences: ${response.status}`); } } async deleteUserData(storagePath) { deletePropertyByPath(this.userData, storagePath); await this.save(this.userData); } async deleteAllUserData() { this.userData = undefined; if (this.config.source === 'localStorage') { localStorage.removeItem(this.storageKey); } else if (this.config.source === 'server') { await this.deleteFromServer(); } else { throw new Error(`Unknown source for user preferences: ${this.config.source}`); } } async deleteFromServer() { if (!this.allowSaveUserPreferences) { return; } const response = await fetch(this.config.postUrl, { method: 'DELETE' }); if (!response.ok) { console.error(response.text); throw new Error(`Error while deleting user preferences: ${response.status}`); } } } export default UserDataManager;