diff --git a/tauri-app/src/lib/stores/orderDetail.ts b/tauri-app/src/lib/stores/orderDetail.ts index e52dd2600..409d417ed 100644 --- a/tauri-app/src/lib/stores/orderDetail.ts +++ b/tauri-app/src/lib/stores/orderDetail.ts @@ -1,32 +1,7 @@ -import { get, writable } from 'svelte/store'; +import { get } from 'svelte/store'; import type { Order } from '$lib/typeshare/orderDetail'; import { invoke } from '@tauri-apps/api'; import { subgraphUrl } from '$lib/stores/settings'; +import { detailStore } from '$lib/storesGeneric/detailStore'; -function useOrderDetailStore() { - const STORAGE_KEY = "orders.orderDetail"; - - const { subscribe, update } = writable<{[id: string]: Order}>(localStorage.getItem(STORAGE_KEY) ? JSON.parse(localStorage.getItem(STORAGE_KEY) as string) : {}); - - subscribe(value => { - if(value) { - localStorage.setItem(STORAGE_KEY, JSON.stringify(value)); - } else { - localStorage.setItem(STORAGE_KEY, JSON.stringify({})); - } - }); - - async function refetch(id: string) { - const res: Order = await invoke("order_detail", {id, subgraphArgs: { url: get(subgraphUrl)} }); - update((value) => { - return {... value, [id]: res}; - }); - } - - return { - subscribe, - refetch - } -} - -export const orderDetail = useOrderDetailStore(); \ No newline at end of file +export const orderDetail = detailStore("orders.orderDetail", (id: string) => invoke("order_detail", {id, subgraphArgs: { url: get(subgraphUrl)} })); \ No newline at end of file diff --git a/tauri-app/src/lib/stores/ordersList.ts b/tauri-app/src/lib/stores/ordersList.ts index 05c8e18fd..42ee59ca8 100644 --- a/tauri-app/src/lib/stores/ordersList.ts +++ b/tauri-app/src/lib/stores/ordersList.ts @@ -2,9 +2,9 @@ import { get } from 'svelte/store'; import type { Order } from '$lib/typeshare/ordersList'; import { invoke } from '@tauri-apps/api'; import { subgraphUrl } from '$lib/stores/settings'; -import { usePaginatedCachedStore } from '$lib/stores/paginatedStore'; +import { listStore } from '$lib/storesGeneric/listStore'; -export const ordersList = usePaginatedCachedStore( +export const ordersList = listStore( 'ordersList', (page) => invoke("orders_list", {subgraphArgs: { url: get(subgraphUrl)}, paginationArgs: { page, page_size: 10 } }), (path) => invoke("orders_list_write_csv", { path, subgraphArgs: { url: get(subgraphUrl)}, paginationArgs: { page: 1, page_size: 1000 } }) diff --git a/tauri-app/src/lib/stores/settings.ts b/tauri-app/src/lib/stores/settings.ts index 3e89f977e..c7f9dd61d 100644 --- a/tauri-app/src/lib/stores/settings.ts +++ b/tauri-app/src/lib/stores/settings.ts @@ -1,39 +1,21 @@ import { isUrlValid } from '$lib/utils/url'; -import { writable, derived } from 'svelte/store'; +import { derived } from 'svelte/store'; import every from 'lodash/every'; import { isAddress } from 'viem'; import { updateChainId } from '$lib/stores/chain'; +import { cachedWritableInt, cachedWritableString } from '$lib/storesGeneric/cachedWritableStore'; -export const rpcUrl = writable(localStorage.getItem("settings.rpcUrl") || ''); -export const subgraphUrl = writable(localStorage.getItem("settings.subgraphUrl") || ''); -export const orderbookAddress = writable(localStorage.getItem("settings.orderbookAddress") || ''); -export const walletAddress = writable(localStorage.getItem("settings.walletAddress") || ''); -export const walletDerivationIndex = writable(parseInt(localStorage.getItem("settings.walletDerivationIndex") || '0')); -export const forkBlockNumber = writable(parseInt(localStorage.getItem("settings.forkBlockNumber") || '45122616')); +export const rpcUrl = cachedWritableString("settings.rpcUrl", ''); +export const subgraphUrl = cachedWritableString("settings.subgraphUrl", ''); +export const orderbookAddress = cachedWritableString("settings.orderbookAddress", ''); +export const walletAddress = cachedWritableString("settings.walletAddress", ''); +export const walletDerivationIndex = cachedWritableInt("settings.walletDerivationIndex", 0); +export const forkBlockNumber = cachedWritableInt("settings.forkBlockNumber", 53247376); -rpcUrl.subscribe(value => { - localStorage.setItem("settings.rpcUrl", value || ''); -}); -subgraphUrl.subscribe(value => { - localStorage.setItem("settings.subgraphUrl", value || ''); -}); -orderbookAddress.subscribe(value => { - localStorage.setItem("settings.orderbookAddress", value || ''); -}); -walletAddress.subscribe(value => { - localStorage.setItem("settings.walletAddress", value || ''); -}); -walletDerivationIndex.subscribe(value => { - localStorage.setItem("settings.walletDerivationIndex", (value || 0).toString()); -}); -forkBlockNumber.subscribe(value => { - localStorage.setItem("settings.forkBlockNumber", (value || 45122616).toString()); -}); - -export const isRpcUrlValid = derived(rpcUrl, (val) => isUrlValid(val)); -export const isSubgraphUrlValid = derived(subgraphUrl, (val) => isUrlValid(val)); -export const isOrderbookAddressValid = derived(orderbookAddress, (val) => isAddress(val)); -export const isWalletAddressValid = derived(walletAddress, (val) => isAddress(val)); +export const isRpcUrlValid = derived(rpcUrl, (val) => val && isUrlValid(val)); +export const isSubgraphUrlValid = derived(subgraphUrl, (val) => val && isUrlValid(val)); +export const isOrderbookAddressValid = derived(orderbookAddress, (val) => val && isAddress(val)); +export const isWalletAddressValid = derived(walletAddress, (val) => val && isAddress(val)); isRpcUrlValid.subscribe(value => { if(value) { diff --git a/tauri-app/src/lib/stores/vaultDetail.ts b/tauri-app/src/lib/stores/vaultDetail.ts index 23d0e6fd5..68c6f0794 100644 --- a/tauri-app/src/lib/stores/vaultDetail.ts +++ b/tauri-app/src/lib/stores/vaultDetail.ts @@ -1,32 +1,7 @@ -import { get, writable } from 'svelte/store'; import type { TokenVault } from '$lib/typeshare/vaultDetail'; +import { get } from 'svelte/store'; import { invoke } from '@tauri-apps/api'; import { subgraphUrl } from '$lib/stores/settings'; +import { detailStore } from '$lib/storesGeneric/detailStore'; -function useVaultDetailStore() { - const STORAGE_KEY = "vaults.vaultsDetail"; - - const { subscribe, update } = writable<{[id: string]: TokenVault}>(localStorage.getItem(STORAGE_KEY) ? JSON.parse(localStorage.getItem(STORAGE_KEY) as string) : {}); - - subscribe(value => { - if(value) { - localStorage.setItem(STORAGE_KEY, JSON.stringify(value)); - } else { - localStorage.setItem(STORAGE_KEY, JSON.stringify({})); - } - }); - - async function refetch(id: string) { - const res: TokenVault = await invoke("vault_detail", {id, subgraphArgs: { url: get(subgraphUrl)} }); - update((value) => { - return {... value, [id]: res}; - }); - } - - return { - subscribe, - refetch - } -} - -export const vaultDetail = useVaultDetailStore(); \ No newline at end of file +export const vaultDetail = detailStore("vaults.vaultsDetail", (id: string) => invoke("vault_detail", {id, subgraphArgs: { url: get(subgraphUrl)} })); \ No newline at end of file diff --git a/tauri-app/src/lib/stores/vaultListBalanceChanges.ts b/tauri-app/src/lib/stores/vaultListBalanceChanges.ts index 062152c8d..972f1908e 100644 --- a/tauri-app/src/lib/stores/vaultListBalanceChanges.ts +++ b/tauri-app/src/lib/stores/vaultListBalanceChanges.ts @@ -1,11 +1,10 @@ import { get } from 'svelte/store'; import { invoke } from '@tauri-apps/api'; import { subgraphUrl } from '$lib/stores/settings'; -import { usePaginatedCachedStore } from './paginatedStore'; +import { listStore } from '$lib/storesGeneric/listStore'; import type { VaultBalanceChange } from '$lib/typeshare/vaultListBalanceChanges'; - -export const useVaultListBalanceChanges = (id: string) => usePaginatedCachedStore( +export const useVaultListBalanceChanges = (id: string) => listStore( `vaultListBalanceChanges-${id}`, (page) => invoke("vault_list_balance_changes", {subgraphArgs: { url: get(subgraphUrl)}, id, paginationArgs: { page, page_size: 10 } }), (path) => invoke("vault_list_balance_changes_write_csv", {path, subgraphArgs: { url: get(subgraphUrl)}, id, paginationArgs: { page: 1, page_size: 1000 } }) diff --git a/tauri-app/src/lib/stores/vaultsList.ts b/tauri-app/src/lib/stores/vaultsList.ts index 7b9d98b76..ab40015c0 100644 --- a/tauri-app/src/lib/stores/vaultsList.ts +++ b/tauri-app/src/lib/stores/vaultsList.ts @@ -2,10 +2,10 @@ import { get } from 'svelte/store'; import type { TokenVault } from '$lib/typeshare/vaultsList'; import { invoke } from '@tauri-apps/api'; import { subgraphUrl } from '$lib/stores/settings'; -import { usePaginatedCachedStore } from './paginatedStore'; +import { listStore } from '$lib/storesGeneric/listStore'; -export const vaultsList = usePaginatedCachedStore( +export const vaultsList = listStore( 'vaultsList', (page) => invoke("vaults_list", {subgraphArgs: { url: get(subgraphUrl)}, paginationArgs: { page, page_size: 10 } }), (path) => invoke("vaults_list_write_csv", {path, subgraphArgs: { url: get(subgraphUrl)}, paginationArgs: { page: 1, page_size: 1000 } }) diff --git a/tauri-app/src/lib/storesGeneric/cachedWritableStore.ts b/tauri-app/src/lib/storesGeneric/cachedWritableStore.ts new file mode 100644 index 000000000..21f8fb4e8 --- /dev/null +++ b/tauri-app/src/lib/storesGeneric/cachedWritableStore.ts @@ -0,0 +1,41 @@ +import { writable } from "svelte/store"; + +export function cachedWritableStore( + key: string, + defaultValue: T, + serialize: (value: T) => string, + deserialize: (serialized: string) => T +) { + const getCache = () => { + const cached = localStorage.getItem(key); + return cached ? deserialize(cached) : defaultValue; + } + const setCache = (value?: T) => { + if(value !== undefined) { + localStorage.setItem(key, serialize(value)); + } else { + localStorage.removeItem(key); + } + } + + const data = writable(getCache()); + + data.subscribe((value) => { + setCache(value); + }) + + return data; +} + +export const cachedWritableString = (key: string, defaultValue = '') => cachedWritableStore(key, defaultValue, (v) => v, (v) => v); +export const cachedWritableInt = (key: string, defaultValue = 0) => cachedWritableStore(key, defaultValue, (v) => v.toString(), (v) => parseInt(v)); + + +export const cachedWritableOptionalStore = ( + key: string, + defaultValue: T | undefined = undefined, + serialize: (value: T) => string, + deserialize: (serialized: string) => T +) => cachedWritableStore(key, defaultValue, (v) => v ? serialize(v) : '', (v) => v ? deserialize(v) : undefined); + +export const cachedWritableIntOptional = (key: string, defaultValue = undefined) => cachedWritableOptionalStore(key, defaultValue, (v) => v.toString(), (v) => parseInt(v)); diff --git a/tauri-app/src/lib/storesGeneric/detailStore.ts b/tauri-app/src/lib/storesGeneric/detailStore.ts new file mode 100644 index 000000000..743cb9836 --- /dev/null +++ b/tauri-app/src/lib/storesGeneric/detailStore.ts @@ -0,0 +1,25 @@ +import { cachedWritableStore } from '$lib/storesGeneric/cachedWritableStore'; + +export function detailStore(key: string, fetchById: (id: string) => Promise) { + const {subscribe, update} = cachedWritableStore<{[id: string]: T}>(key, {}, (value) => JSON.stringify(value), (value) => JSON.parse(value)); + + subscribe(value => { + if(value) { + localStorage.setItem(key, JSON.stringify(value)); + } else { + localStorage.setItem(key, JSON.stringify({})); + } + }); + + async function refetch(id: string) { + const res: T = await fetchById(id); + update((value) => { + return {... value, [id]: res}; + }); + } + + return { + subscribe, + refetch + } +} diff --git a/tauri-app/src/lib/stores/paginatedStore.ts b/tauri-app/src/lib/storesGeneric/listStore.ts similarity index 84% rename from tauri-app/src/lib/stores/paginatedStore.ts rename to tauri-app/src/lib/storesGeneric/listStore.ts index 47d088d8f..e5a2e4f4e 100644 --- a/tauri-app/src/lib/stores/paginatedStore.ts +++ b/tauri-app/src/lib/storesGeneric/listStore.ts @@ -1,8 +1,9 @@ import { derived, get, writable, type Invalidator, type Subscriber } from 'svelte/store'; -import { toasts } from './toasts'; +import { toasts } from '../stores/toasts'; import { save } from '@tauri-apps/api/dialog'; import dayjs from 'dayjs'; import { ToastMessageType } from '$lib/typeshare/toast'; +import { cachedWritableStore } from '$lib/storesGeneric/cachedWritableStore'; type Unsubscriber = () => void; @@ -26,20 +27,15 @@ export interface AllPages { [pageIndex: number]: Array } -export function usePaginatedCachedStore(key: string, fetchPageHandler: (page: number) => Promise>, writeCsvHandler: (path: string) => Promise) { - const allPages = writable>(localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key) as string) : []); + +const cachedWritablePages = (key: string) => cachedWritableStore>(key, [], (value) => JSON.stringify(value), (value) => JSON.parse(value)); + +export function listStore(key: string, fetchPageHandler: (page: number) => Promise>, writeCsvHandler: (path: string) => Promise) { + const allPages = cachedWritablePages(key); const pageIndex = writable(1); const isFetching = writable(false); const isExporting = writable(false); - allPages.subscribe(value => { - if(value) { - localStorage.setItem(key, JSON.stringify(value)); - } else { - localStorage.setItem(key, JSON.stringify([])); - } - }); - const page = derived(allPages, $allPages => (page: number) => $allPages[page] || []); const { subscribe } = derived([page, pageIndex, isFetching, isExporting], ([$page, $pageIndex, $isFetching, $isExporting]) => ({