diff options
| author | ivar <i@oiee.no> | 2024-04-28 22:37:30 +0200 |
|---|---|---|
| committer | ivar <i@oiee.no> | 2024-04-28 22:37:30 +0200 |
| commit | ced66c5807575cd29f6aa5632e8ad02b38c8448a (patch) | |
| tree | 01760648ee293a2aef2288328014b5747d2192b4 /code/frontend/src/utils/persistent-store.ts | |
| parent | 691ad60d7bff5934053d87267c4e303ef3ed5f97 (diff) | |
| download | greatoffice-ced66c5807575cd29f6aa5632e8ad02b38c8448a.tar.xz greatoffice-ced66c5807575cd29f6aa5632e8ad02b38c8448a.zip | |
WIP new frontend
Diffstat (limited to 'code/frontend/src/utils/persistent-store.ts')
| -rw-r--r-- | code/frontend/src/utils/persistent-store.ts | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/code/frontend/src/utils/persistent-store.ts b/code/frontend/src/utils/persistent-store.ts new file mode 100644 index 0000000..d880464 --- /dev/null +++ b/code/frontend/src/utils/persistent-store.ts @@ -0,0 +1,110 @@ +import {browser} from "$app/environment"; +import {writable as _writable, readable as _readable} from "svelte/store"; +import type {Writable, Readable, StartStopNotifier} from "svelte/store"; + +enum StoreType { + SESSION = 0, + LOCAL = 1 +} + +interface StoreOptions { + store?: StoreType; +} + +interface WritableStoreInit<T> { + name: string, + initialState: T, + options?: StoreOptions +} + +interface ReadableStoreInit<T> { + name: string, + initialState: T, + callback: StartStopNotifier<any>, + options?: StoreOptions +} + +function get_store(type: StoreType): Storage { + if (!browser) return undefined; + switch (type) { + case StoreType.SESSION: + return window.sessionStorage; + case StoreType.LOCAL: + return window.localStorage; + } +} + +function prepared_store_value(value: any): string { + try { + return JSON.stringify(value); + } catch (e) { + console.error(e); + return "__INVALID__"; + } +} + +function get_store_value<T>(init: WritableStoreInit<T> | ReadableStoreInit<T>): any { + try { + const storage = get_store(init.options.store); + if (!storage) return; + const value = storage.getItem(init.name); + if (!value) return false; + return JSON.parse(value); + } catch (e) { + console.error(e); + return {__INVALID__: true}; + } +} + +function hydrate<T>(store: Writable<T>, init: WritableStoreInit<T> | ReadableStoreInit<T>): void { + const value = get_store_value<T>(init); + if (value && store.set) store.set(value); +} + +function subscribe<T>(store: Writable<T> | Readable<T>, init: WritableStoreInit<T> | ReadableStoreInit<T>): void { + const storage = get_store(init.options.store); + if (!storage) return; + if (!store.subscribe) return; + store.subscribe((state: any) => { + storage.setItem(init.name, prepared_store_value(state)); + }); +} + +function create_writable_persistent<T>(init: WritableStoreInit<T>): Writable<T> { + if (!browser) { + console.warn("Persistent store is only available in the browser"); + return; + } + if (init.options === undefined) throw new Error("init is a required parameter"); + console.debug("Creating writable store with options: ", init); + const store = _writable<T>(init.initialState); + hydrate(store, init); + subscribe(store, init); + return store; +} + +function create_readable_persistent<T>(init: ReadableStoreInit<T>): Readable<T> { + if (!browser) { + console.warning("Persistent store is only available in the browser"); + return; + } + if (init.options === undefined) throw new Error("init is a required parameter"); + console.debug("Creating readable store with options: ", init); + const store = _readable<T>(init.initialState, init.callback); + // hydrate(store, options); + subscribe(store, init); + return store; +} + +export { + create_writable_persistent, + create_readable_persistent, + StoreType, +}; + +export type { + WritableStoreInit as WritableStore, + ReadableStoreInit as ReadableStore, + StoreOptions, +}; + |
