diff options
| author | Fuwn <[email protected]> | 2025-06-12 22:06:31 -0700 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2025-06-12 22:06:31 -0700 |
| commit | e8612618fb20f779ebe2e85edf32d71961d2f1d4 (patch) | |
| tree | fa8565afb8584bbf55f4f4d496c2c350a5a25210 | |
| parent | refactor(List): Simplify get-set structure of stateBin usage (diff) | |
| download | due.moe-e8612618fb20f779ebe2e85edf32d71961d2f1d4.tar.xz due.moe-e8612618fb20f779ebe2e85edf32d71961d2f1d4.zip | |
feat: Move remaining localStorage usages to localforage
| -rw-r--r-- | src/app.html | 205 | ||||
| -rw-r--r-- | src/lib/Error/LogInRestricted.svelte | 5 | ||||
| -rw-r--r-- | src/lib/Landing.svelte | 5 | ||||
| -rw-r--r-- | src/lib/List/Anime/AnimeListTemplate.svelte | 8 | ||||
| -rw-r--r-- | src/lib/List/Anime/CleanAnimeList.svelte | 5 | ||||
| -rw-r--r-- | src/lib/List/Manga/CleanMangaList.svelte | 8 | ||||
| -rw-r--r-- | src/lib/List/Manga/MangaListTemplate.svelte | 5 | ||||
| -rw-r--r-- | src/lib/Settings/Categories/Debug.svelte | 6 | ||||
| -rw-r--r-- | src/routes/+layout.svelte | 28 | ||||
| -rw-r--r-- | src/routes/user/+page.svelte | 26 | ||||
| -rw-r--r-- | src/routes/user/[user]/badges/+page.svelte | 7 | ||||
| -rw-r--r-- | src/stores/announcementHash.ts | 17 | ||||
| -rw-r--r-- | src/stores/identity.ts | 43 | ||||
| -rw-r--r-- | src/stores/lastPruneTimes.ts | 46 | ||||
| -rw-r--r-- | src/stores/settings.ts | 61 | ||||
| -rw-r--r-- | src/stores/stateBin.ts | 15 |
16 files changed, 273 insertions, 217 deletions
diff --git a/src/app.html b/src/app.html index 498e3f9c..d485fc70 100644 --- a/src/app.html +++ b/src/app.html @@ -84,99 +84,124 @@ document.addEventListener('DOMContentLoaded', () => { const mai = document.getElementById('mai'); + const openRequest = indexedDB.open('localforage'); - aoButa = JSON.parse(localStorage.getItem('settings')).displayAoButa; - mai.style.display = 'block'; - - if (aoButa === 'random') { - const random = Math.floor(Math.random() * 8); - - switch (random) { - case 0: - aoButa = 'mai'; - break; - case 1: - aoButa = 'nodoka'; - break; - case 2: - aoButa = 'kaede'; - break; - case 3: - aoButa = 'rio'; - break; - case 4: - aoButa = 'sakuta'; - break; - case 5: - aoButa = 'shouko'; - break; - case 6: - aoButa = 'tomoe'; - break; - case 6: - default: - aoButa = 'mai_2'; - break; - } - } - - switch (aoButa) { - case 'mai_2': - { - mai.src = '/aobuta/mai.png'; - mai.alt = 'Mai Sakurajima'; - } - break; - case 'mai': - { - mai.src = '/aobuta/mai_2.webp'; - mai.alt = 'Mai Sakurajima'; - } - break; - case 'nodoka': - { - mai.src = '/aobuta/nodoka.webp'; - mai.alt = 'Nodoka Toyohama'; - } - break; - case 'kaede': - { - mai.src = '/aobuta/kaede.png'; - mai.alt = 'Kaede Azusagawa'; - } - break; - case 'rio': - { - mai.src = '/aobuta/rio.webp'; - mai.alt = 'Rio Futaba'; - } - break; - case 'sakuta': - { - mai.src = '/aobuta/sakuta.webp'; - mai.alt = 'Sakuta Azusagawa'; - } - break; - case 'shouko': - { - mai.src = '/aobuta/shouko.webp'; - mai.alt = 'Shouko Makinohara'; - } - break; - case 'tomoe': - { - mai.src = '/aobuta/tomoe.webp'; - mai.alt = 'Tomoe Koga'; + openRequest.onsuccess = (event) => { + const database = event.target.result; + const transaction = database.transaction(['keyvaluepairs'], 'readonly'); + const objectStore = transaction.objectStore('keyvaluepairs'); + const getRequest = objectStore.get('settings'); + + getRequest.onsuccess = () => { + const settings = getRequest.result; + + aoButa = settings?.displayAoButa || 'none'; + mai.style.display = 'block'; + + if (aoButa === 'random') { + const random = Math.floor(Math.random() * 8); + + switch (random) { + case 0: + aoButa = 'mai'; + + break; + + case 1: + aoButa = 'nodoka'; + + break; + + case 2: + aoButa = 'kaede'; + + break; + + case 3: + aoButa = 'rio'; + + break; + + case 4: + aoButa = 'sakuta'; + + break; + + case 5: + aoButa = 'shouko'; + + break; + + case 6: + aoButa = 'tomoe'; + + break; + + default: + aoButa = 'mai_2'; + + break; + } } - break; - case 'none': { - { - mai.style.display = 'none'; - mai.alt = 'No one'; + + switch (aoButa) { + case 'mai_2': + mai.src = '/aobuta/mai.png'; + mai.alt = 'Mai Sakurajima'; + + break; + + case 'mai': + mai.src = '/aobuta/mai_2.webp'; + mai.alt = 'Mai Sakurajima'; + + break; + + case 'nodoka': + mai.src = '/aobuta/nodoka.webp'; + mai.alt = 'Nodoka Toyohama'; + + break; + + case 'kaede': + mai.src = '/aobuta/kaede.png'; + mai.alt = 'Kaede Azusagawa'; + + break; + + case 'rio': + mai.src = '/aobuta/rio.webp'; + mai.alt = 'Rio Futaba'; + + break; + + case 'sakuta': + mai.src = '/aobuta/sakuta.webp'; + mai.alt = 'Sakuta Azusagawa'; + + break; + + case 'shouko': + mai.src = '/aobuta/shouko.webp'; + mai.alt = 'Shouko Makinohara'; + + break; + + case 'tomoe': + mai.src = '/aobuta/tomoe.webp'; + mai.alt = 'Tomoe Koga'; + + break; + + case 'none': + default: + mai.style.display = 'none'; + mai.alt = 'No one'; + + break; } - break; - } - } + }; + }; }); </script> diff --git a/src/lib/Error/LogInRestricted.svelte b/src/lib/Error/LogInRestricted.svelte index 07a9adec..54ea5ee1 100644 --- a/src/lib/Error/LogInRestricted.svelte +++ b/src/lib/Error/LogInRestricted.svelte @@ -1,14 +1,15 @@ <script> import Popup from '$lib/Layout/Popup.svelte'; import { env } from '$env/dynamic/public'; + import localforage from 'localforage'; </script> <Popup fullscreen locked> <div class="message"> Please <a href={`https://anilist.co/api/v2/oauth/authorize?client_id=${env.PUBLIC_ANILIST_CLIENT_ID}&redirect_uri=${env.PUBLIC_ANILIST_REDIRECT_URI}&response_type=code`} - on:click={() => { - localStorage.setItem( + on:click={async () => { + await localforage.setItem( 'redirect', window.location.origin + window.location.pathname + window.location.search ); diff --git a/src/lib/Landing.svelte b/src/lib/Landing.svelte index 9986d1b9..f688eacf 100644 --- a/src/lib/Landing.svelte +++ b/src/lib/Landing.svelte @@ -4,6 +4,7 @@ import tooltip from './Tooltip/tooltip'; import CompletedAnimeList from './List/Anime/CompletedAnimeList.svelte'; import MangaListTemplate from './List/Manga/MangaListTemplate.svelte'; + import localforage from 'localforage'; </script> <div class="example-item card"> @@ -92,8 +93,8 @@ <span class="medium-text"> <a href={`https://anilist.co/api/v2/oauth/authorize?client_id=${env.PUBLIC_ANILIST_CLIENT_ID}&redirect_uri=${env.PUBLIC_ANILIST_REDIRECT_URI}&response_type=code`} - on:click={() => { - localStorage.setItem( + on:click={async () => { + await localforage.setItem( 'redirect', window.location.origin + window.location.pathname + window.location.search ); diff --git a/src/lib/List/Anime/AnimeListTemplate.svelte b/src/lib/List/Anime/AnimeListTemplate.svelte index 08583d7c..99d2e888 100644 --- a/src/lib/List/Anime/AnimeListTemplate.svelte +++ b/src/lib/List/Anime/AnimeListTemplate.svelte @@ -13,6 +13,7 @@ import { onMount } from 'svelte'; import subsPlease from '$stores/subsPlease'; import identity from '$stores/identity'; + import localforage from 'localforage'; export let endTime: number; export let cleanMedia: ( @@ -35,13 +36,14 @@ let pendingUpdate: number | null = null; let lastListSize = 8; - onMount(() => { + onMount(async () => { if (browser) { - const lastStoredList = localStorage.getItem( + const lastStoredList = (await localforage.getItem( `last${ notYetReleased ? 'NotYetReleased' : upcoming ? 'Upcoming' : completed ? 'Completed' : '' }AnimeListLength` - ); + )) as string | null; + if (lastStoredList) lastListSize = parseInt(lastStoredList); } }); diff --git a/src/lib/List/Anime/CleanAnimeList.svelte b/src/lib/List/Anime/CleanAnimeList.svelte index 22e8f581..a9026d1d 100644 --- a/src/lib/List/Anime/CleanAnimeList.svelte +++ b/src/lib/List/Anime/CleanAnimeList.svelte @@ -16,6 +16,7 @@ import CleanGrid from '$lib/List/CleanGrid.svelte'; import CleanList from '../CleanList.svelte'; import stateBin from '$stores/stateBin'; + import localforage from 'localforage'; export let media: Media[]; export let title: any; @@ -74,7 +75,7 @@ ? media : media.filter((m) => m.mediaListEntry?.customLists?.[selectedList]); - onMount(() => { + onMount(async () => { if (dummy) return; keyCacher = setInterval( @@ -105,7 +106,7 @@ ); if (browser) - localStorage.setItem( + await localforage.setItem( `last${ notYetReleased ? 'NotYetReleased' : upcoming ? 'Upcoming' : completed ? 'Completed' : '' }AnimeListLength`, diff --git a/src/lib/List/Manga/CleanMangaList.svelte b/src/lib/List/Manga/CleanMangaList.svelte index eb54df8c..aeb1bc7e 100644 --- a/src/lib/List/Manga/CleanMangaList.svelte +++ b/src/lib/List/Manga/CleanMangaList.svelte @@ -14,6 +14,7 @@ import CleanGrid from '../CleanGrid.svelte'; import CleanList from '../CleanList.svelte'; import stateBin from '$stores/stateBin'; + import localforage from 'localforage'; export let media: Media[]; export let cleanCache: () => void; @@ -58,11 +59,14 @@ ? media : media.filter((m) => m.mediaListEntry?.customLists?.[selectedList]); - onMount(() => { + onMount(async () => { serviceStatusResponse = fetch(proxy('https://api.mangadex.org/ping')); if (browser) - localStorage.setItem(`last${due ? '' : 'Completed'}MangaListLength`, media.length.toString()); + await localforage.setItem( + `last${due ? '' : 'Completed'}MangaListLength`, + media.length.toString() + ); }); const increment = (manga: Media) => { diff --git a/src/lib/List/Manga/MangaListTemplate.svelte b/src/lib/List/Manga/MangaListTemplate.svelte index 0b38158b..d7f00616 100644 --- a/src/lib/List/Manga/MangaListTemplate.svelte +++ b/src/lib/List/Manga/MangaListTemplate.svelte @@ -20,6 +20,7 @@ import { browser } from '$app/environment'; import identity from '$stores/identity'; import privilegedUser from '$lib/Utility/privilegedUser'; + import localforage from 'localforage'; export let user: AniListAuthorisation = { accessToken: '', @@ -57,7 +58,9 @@ onMount(async () => { if (browser) { - const lastStoredList = localStorage.getItem(`last${due ? '' : 'Completed'}MangaListLength`); + const lastStoredList = (await localforage.getItem( + `last${due ? '' : 'Completed'}MangaListLength` + )) as number | null; if (lastStoredList) lastListSize = parseInt(lastStoredList); } diff --git a/src/lib/Settings/Categories/Debug.svelte b/src/lib/Settings/Categories/Debug.svelte index 8ba6ade9..c21edb44 100644 --- a/src/lib/Settings/Categories/Debug.svelte +++ b/src/lib/Settings/Categories/Debug.svelte @@ -13,8 +13,6 @@ const clearCaches = async () => { if (!browser) return; - localStorage.removeItem('anime'); - localStorage.removeItem('manga'); await localforage.removeItem('anime'); await localforage.removeItem('manga'); addNotification( @@ -50,8 +48,8 @@ <p /> <button - on:click={() => { - localStorage.clear(); + on:click={async () => { + await localforage.clear(); addNotification( options({ heading: '<code>localStorage</code> successfully cleared' diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 1dd069a0..d9caca74 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -76,22 +76,22 @@ onMount(async () => { if (browser) { - if (localStorage.getItem('redirect')) { - window.location.href = localStorage.getItem('redirect') ?? '/'; + if (await localforage.getItem('redirect')) { + window.location.href = (await localforage.getItem('redirect')) ?? '/'; - localStorage.removeItem('redirect'); + await localforage.removeItem('redirect'); } window.addEventListener('scroll', handleScroll); - if (localStorage.getItem('commit') !== data.commit) { - localStorage.removeItem('identity'); - localStorage.removeItem('anime'); - localStorage.removeItem('manga'); + if ((await localforage.getItem('commit')) !== data.commit) { + await localforage.removeItem('identity'); await localforage.removeItem('anime'); await localforage.removeItem('manga'); - localStorage.removeItem('lastPruneTimes'); - localStorage.setItem('commit', data.commit); + await localforage.removeItem('anime'); + await localforage.removeItem('manga'); + await localforage.removeItem('lastPruneTimes'); + await localforage.setItem('commit', data.commit); } } @@ -213,9 +213,9 @@ name: $locale().navigation.logOut, url: '#', preventDefault: true, - onClick: () => { - localStorage.removeItem('identity'); - localStorage.removeItem('commit'); + onClick: async () => { + await localforage.removeItem('identity'); + await localforage.removeItem('commit'); document.cookie = 'user=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'; @@ -235,8 +235,8 @@ <a class="header-item" href={`https://anilist.co/api/v2/oauth/authorize?client_id=${env.PUBLIC_ANILIST_CLIENT_ID}&redirect_uri=${env.PUBLIC_ANILIST_REDIRECT_URI}&response_type=code`} - on:click={() => { - localStorage.setItem( + on:click={async () => { + await localforage.setItem( 'redirect', window.location.origin + window.location.pathname + window.location.search ); diff --git a/src/routes/user/+page.svelte b/src/routes/user/+page.svelte index 29bd132b..eab089c6 100644 --- a/src/routes/user/+page.svelte +++ b/src/routes/user/+page.svelte @@ -7,23 +7,23 @@ import HeadTitle from '$lib/Home/HeadTitle.svelte'; import root from '$lib/Utility/root'; import { page } from '$app/stores'; + import localforage from 'localforage'; - const user = - browser && localStorage.getItem('identity') - ? (JSON.parse(localStorage.getItem('identity') || '') as UserIdentity).name - : null; + onMount(async () => { + if (browser) { + const user = ((await localforage.getItem('identity')) as UserIdentity).name; - onMount(() => { - if (user) { - if (browser && $page.url.searchParams.get('badges') !== null) { - goto(root(`/user/${user}/badges`)); + if (user) { + if (browser && $page.url.searchParams.get('badges') !== null) { + goto(root(`/user/${user}/badges`)); + } else { + goto(root(`/user/${user}`)); + } } else { - goto(root(`/user/${user}`)); + goto( + `https://anilist.co/api/v2/oauth/authorize?client_id=${env.PUBLIC_ANILIST_CLIENT_ID}&redirect_uri=${env.PUBLIC_ANILIST_REDIRECT_URI}&response_type=code` + ); } - } else { - goto( - `https://anilist.co/api/v2/oauth/authorize?client_id=${env.PUBLIC_ANILIST_CLIENT_ID}&redirect_uri=${env.PUBLIC_ANILIST_REDIRECT_URI}&response_type=code` - ); } }); </script> diff --git a/src/routes/user/[user]/badges/+page.svelte b/src/routes/user/[user]/badges/+page.svelte index 9fca60b2..43beddea 100644 --- a/src/routes/user/[user]/badges/+page.svelte +++ b/src/routes/user/[user]/badges/+page.svelte @@ -23,6 +23,7 @@ import type { IndexedBadge } from '$lib/User/BadgeWall/badge'; import { graphql } from '$houdini'; import type { Preferences } from '../../../../graphql/user/$types'; + import localforage from 'localforage'; export let data; @@ -205,7 +206,7 @@ }); onMount(async () => { - if (browser && localStorage.getItem('badgeWallNoticeDismissed')) noticeDismissed = true; + if (browser && (await localforage.getItem('badgeWallNoticeDismissed'))) noticeDismissed = true; badger = isId ? { @@ -573,10 +574,10 @@ of all badges from your Badge Wall. <p /> <button - on:click={() => { + on:click={async () => { noticeDismissed = true; - localStorage.setItem('badgeWallNoticeDismissed', 'true'); + await localforage.setItem('badgeWallNoticeDismissed', 'true'); }} > Dismiss diff --git a/src/stores/announcementHash.ts b/src/stores/announcementHash.ts index 0ff57b3b..d14c305e 100644 --- a/src/stores/announcementHash.ts +++ b/src/stores/announcementHash.ts @@ -1,12 +1,17 @@ import { browser } from '$app/environment'; import { writable } from 'svelte/store'; +import localforage from 'localforage'; -const announcementHash = writable<number>( - browser ? parseInt(localStorage.getItem('announcementHash') || '1') : 0 -); +const announcementHash = writable<number>(1); -announcementHash.subscribe((value) => { - if (browser) localStorage.setItem('announcementHash', value.toString()); -}); +if (browser) { + localforage.getItem<number>('announcementHash').then((value) => { + if (typeof value === 'number') announcementHash.set(value); + }); + + announcementHash.subscribe((value) => { + localforage.setItem('announcementHash', value); + }); +} export default announcementHash; diff --git a/src/stores/identity.ts b/src/stores/identity.ts index 2618d744..596c7176 100644 --- a/src/stores/identity.ts +++ b/src/stores/identity.ts @@ -1,6 +1,7 @@ import { browser } from '$app/environment'; import type { UserIdentity } from '$lib/Data/AniList/identity'; import { writable } from 'svelte/store'; +import localforage from 'localforage'; export const defaultIdentity: UserIdentity = { name: '', @@ -9,22 +10,26 @@ export const defaultIdentity: UserIdentity = { }; const createStore = () => { - const { subscribe, set, update } = writable<UserIdentity>( - JSON.parse( - browser - ? (localStorage.getItem('identity') ?? JSON.stringify(defaultIdentity)) - : JSON.stringify(defaultIdentity) - ) - ); - let state: UserIdentity; + const store = writable<UserIdentity>(defaultIdentity); + let state: UserIdentity = defaultIdentity; - subscribe((value) => (state = value)); + if (browser) + localforage.getItem<UserIdentity>('identity').then((value) => { + if (value && typeof value === 'object') store.set(value); + }); + + store.subscribe((value) => { + state = value; + + if (browser) localforage.setItem('identity', value); + }); return { - subscribe, - set, - update, - reset: () => set(defaultIdentity), + subscribe: store.subscribe, + set: store.set, + update: store.update, + reset: () => store.set(defaultIdentity), + get: () => { const keys = Object.keys(defaultIdentity); const identityKeys = Object.keys(state); @@ -32,22 +37,18 @@ const createStore = () => { for (const key of keys) if (!identityKeys.includes(key)) - (updatedIdentity[key as keyof UserIdentity] as unknown) = - defaultIdentity[key as keyof UserIdentity]; + updatedIdentity[key as keyof UserIdentity] = defaultIdentity[key as keyof UserIdentity]; - if (browser) localStorage.setItem('identity', JSON.stringify(updatedIdentity)); + if (browser) localforage.setItem('identity', updatedIdentity); return updatedIdentity; }, + setKey: (key: keyof UserIdentity, value: unknown) => - update((identity) => ({ ...identity, [key]: value })) + store.update((identity) => ({ ...identity, [key]: value })) }; }; const identity = createStore(); -identity.subscribe((value) => { - if (browser) localStorage.setItem('identity', JSON.stringify(value)); -}); - export default identity; diff --git a/src/stores/lastPruneTimes.ts b/src/stores/lastPruneTimes.ts index 9c4afc5b..212f2bc9 100644 --- a/src/stores/lastPruneTimes.ts +++ b/src/stores/lastPruneTimes.ts @@ -1,5 +1,6 @@ import { browser } from '$app/environment'; import { writable } from 'svelte/store'; +import localforage from 'localforage'; interface LastPruneTimes { anime: number; @@ -14,41 +15,42 @@ const defaultTimes: LastPruneTimes = { }; const createStore = () => { - const { subscribe, set, update } = writable<LastPruneTimes>( - JSON.parse( - browser - ? (localStorage.getItem('lastPruneTimes') ?? JSON.stringify(defaultTimes)) - : JSON.stringify(defaultTimes) - ) - ); - let state: LastPruneTimes; + const store = writable<LastPruneTimes>(defaultTimes); + let state: LastPruneTimes = defaultTimes; - subscribe((value) => (state = value)); + if (browser) + localforage.getItem<LastPruneTimes>('lastPruneTimes').then((value) => { + if (value && Object.keys(value).length === Object.keys(defaultTimes).length) store.set(value); + }); + + store.subscribe((value) => { + state = value; + + if (browser) localforage.setItem('lastPruneTimes', value); + }); return { - subscribe, - set, - update, - reset: () => set(defaultTimes), + subscribe: store.subscribe, + set: store.set, + update: store.update, + reset: () => store.set(defaultTimes), + get: () => { const keys = Object.keys(defaultTimes); - const lastPruneTimesKeys = Object.keys(state); + const stateKeys = Object.keys(state); - if (keys.length !== lastPruneTimesKeys.length) return defaultTimes; + if (keys.length !== stateKeys.length) return defaultTimes; - for (const key of keys) if (!lastPruneTimesKeys.includes(key)) return defaultTimes; + for (const key of keys) if (!stateKeys.includes(key)) return defaultTimes; return state; }, - setKey: (key: keyof LastPruneTimes, value: unknown) => - update((lastPruneTimes) => ({ ...lastPruneTimes, [key]: value })) + + setKey: (key: keyof LastPruneTimes, value: number) => + store.update((times) => ({ ...times, [key]: value })) }; }; const lastPruneTimes = createStore(); -lastPruneTimes.subscribe((value) => { - if (browser) localStorage.setItem('lastPruneTimes', JSON.stringify(value)); -}); - export default lastPruneTimes; diff --git a/src/stores/settings.ts b/src/stores/settings.ts index fef0debf..c8ae9c94 100644 --- a/src/stores/settings.ts +++ b/src/stores/settings.ts @@ -4,6 +4,7 @@ import { get, writable } from 'svelte/store'; import settingsSyncPulled from './settingsSyncPulled'; import settingsSyncTimes from './settingsSyncTimes'; import identity from './identity'; +import localforage from 'localforage'; const VERSION = '1.0.1'; @@ -135,22 +136,26 @@ const defaultSettings: Settings = { }; const createStore = () => { - const { subscribe, set, update } = writable<Settings>( - JSON.parse( - browser - ? (localStorage.getItem('settings') ?? JSON.stringify(defaultSettings)) - : JSON.stringify(defaultSettings) - ) - ); - let state: Settings; + const store = writable<Settings>(defaultSettings); + let state: Settings = defaultSettings; - subscribe((value) => (state = value)); + if (browser) + localforage.getItem<Settings>('settings').then((value) => { + if (value && typeof value === 'object') store.set(value); + }); + + store.subscribe((value) => { + state = value; + + if (browser) localforage.setItem('settings', value); + }); return { - subscribe, - set, - update, - reset: () => set(defaultSettings), + subscribe: store.subscribe, + set: store.set, + update: store.update, + reset: () => store.set(defaultSettings), + get: () => { const keys = Object.keys(defaultSettings); const settingsKeys = Object.keys(state); @@ -158,51 +163,53 @@ const createStore = () => { for (const key of keys) if (!settingsKeys.includes(key)) - (updatedSettings[key as keyof Settings] as unknown) = - defaultSettings[key as keyof Settings]; + updatedSettings[key as keyof Settings] = defaultSettings[key as keyof Settings]; - if (browser) localStorage.setItem('settings', JSON.stringify(updatedSettings)); + if (browser) localforage.setItem('settings', updatedSettings); return updatedSettings; }, + setKey: (key: keyof Settings, value: unknown) => - update((settings) => ({ ...settings, [key]: value })) + store.update((settings) => ({ ...settings, [key]: value })) }; }; const settings = createStore(); settings.subscribe((value) => { - if (browser) localStorage.setItem('settings', JSON.stringify(value)); + if (!browser) return; - if (value.settingsSync && get(settingsSyncPulled) == true) + if (value.settingsSync && get(settingsSyncPulled) === true) { fetch(root(`/api/configuration?id=${get(identity).id}`)).then((response) => { if (response.ok) response.json().then((data) => { - const isEqualsJson = (object1: Settings, object2: Settings) => { + const isEqualsJson = (firstObject: Settings, secondObject: Settings) => { type AnyObject = { [key: string]: unknown }; return ( - Object.keys(object1).length === Object.keys(object2).length && - Object.keys(object1).every( - (key) => - (object1 as unknown as AnyObject)[key] == (object2 as unknown as AnyObject)[key] + Object.keys(firstObject).length === Object.keys(secondObject).length && + Object.keys(firstObject).every( + (key) => (firstObject as AnyObject)[key] === (secondObject as AnyObject)[key] ) ); }; - if (data && data.configuration && !isEqualsJson(data.configuration, value)) { + if (data?.configuration && !isEqualsJson(data.configuration, value)) fetch(root(`/api/configuration`), { method: 'PUT', body: JSON.stringify(value) }).then((response) => { if (response.ok) console.log('Pushed local configuration'); - settingsSyncTimes.update((times) => ({ ...times, lastPush: new Date() })); + settingsSyncTimes.update((times) => ({ + ...times, + lastPush: new Date() + })); }); - } }); }); + } }); export default settings; diff --git a/src/stores/stateBin.ts b/src/stores/stateBin.ts index 74ea510f..082a07dc 100644 --- a/src/stores/stateBin.ts +++ b/src/stores/stateBin.ts @@ -1,17 +1,22 @@ import { browser } from '$app/environment'; import { writable, get, type Writable } from 'svelte/store'; +import localforage from 'localforage'; type StateBin = Record<string, unknown>; const STORAGE_KEY = 'stateBin'; -const initialState = browser ? JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '{}') : {}; -const baseStore = writable<StateBin>(initialState); +const baseStore = writable<StateBin>({}); -if (browser) - baseStore.subscribe((val) => { - localStorage.setItem(STORAGE_KEY, JSON.stringify(val)); +if (browser) { + localforage.getItem<StateBin>(STORAGE_KEY).then((value) => { + if (value && typeof value === 'object') baseStore.set(value); }); + baseStore.subscribe((value) => { + localforage.setItem(STORAGE_KEY, value); + }); +} + const createProxyStore = (store: Writable<StateBin>) => { return new Proxy(store, { get(target, prop: string) { |