aboutsummaryrefslogtreecommitdiffstats
path: root/code/frontend/src/utils/persistent-store.ts
diff options
context:
space:
mode:
authorivar <i@oiee.no>2024-04-28 22:37:30 +0200
committerivar <i@oiee.no>2024-04-28 22:37:30 +0200
commitced66c5807575cd29f6aa5632e8ad02b38c8448a (patch)
tree01760648ee293a2aef2288328014b5747d2192b4 /code/frontend/src/utils/persistent-store.ts
parent691ad60d7bff5934053d87267c4e303ef3ed5f97 (diff)
downloadgreatoffice-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.ts110
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,
+};
+