Skip to content

Add cachedWritableStores to shared lib, and update hideZeroBalanceVaults to use the cached version #1698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
May 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/ui-components/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ export { lightCodeMirrorTheme, darkCodeMirrorTheme } from './utils/codeMirrorThe

// Stores
export { default as transactionStore } from './stores/transactionStore';
export {
cachedWritableStore,
cachedWritableIntOptional,
cachedWritableStringOptional,
cachedWritableString
} from './storesGeneric/cachedWritableStore';

// Assets
export { default as logoLight } from './assets/logo-light.svg';
Expand Down
137 changes: 137 additions & 0 deletions packages/ui-components/src/lib/storesGeneric/cachedWritableStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { writable } from 'svelte/store';

/**
* Creates a writable Svelte store that persists its value to localStorage.
*
* @template T - The type of the value stored in the store
* @param {string} key - The localStorage key used to store the value
* @param {T} defaultValue - The default value to use when no value is found in localStorage
* @param {function(T): string} serialize - Function to convert the store value to a string for storage
* @param {function(string): T} deserialize - Function to convert the stored string back to the original type
* @returns {import('svelte/store').Writable<T>} A writable store that automatically syncs with localStorage
*
* @example
* // Create a store for a boolean value
* const darkMode = cachedWritableStore(
* 'darkMode',
* false,
* value => JSON.stringify(value),
* str => JSON.parse(str)
* );
*
* // Create a store for a complex object
* const userPreferences = cachedWritableStore(
* 'userPrefs',
* { theme: 'light', fontSize: 14 },
* value => JSON.stringify(value),
* str => JSON.parse(str)
* );
*/
export function cachedWritableStore<T>(
key: string,
defaultValue: T,
serialize: (value: T) => string,
deserialize: (serialized: string) => T
) {
const getCache = () => {
try {
const cached = localStorage.getItem(key);
return cached !== null ? deserialize(cached) : defaultValue;
} catch {
return defaultValue;
}
};
const setCache = (value?: T) => {
try {
if (value !== undefined) {
localStorage.setItem(key, serialize(value));
} else {
localStorage.removeItem(key);
}
} catch {
// Silently ignore localStorage errors to allow the application to function
// without persistence in environments where localStorage is unavailable
}
};

const data = writable<T>(getCache());

data.subscribe((value) => {
setCache(value);
});

return data;
}

export const cachedWritableString = (key: string, defaultValue = '') =>
cachedWritableStore<string>(
key,
defaultValue,
(v) => v,
(v) => v
);
export const cachedWritableInt = (key: string, defaultValue = 0) =>
cachedWritableStore<number>(
key,
defaultValue,
(v) => v.toString(),
(v) => {
const parsed = Number.parseInt(v);
return isNaN(parsed) ? defaultValue : parsed;
}
);
/**
* Creates a writable store that can hold an optional value of type T and persists to localStorage.
*
* @template T - The type of the value stored
* @param {string} key - The localStorage key to use for persistence
* @param {T | undefined} defaultValue - The default value if nothing is found in localStorage
* @param {function} serialize - Function to convert the value to a string for storage
* @param {function} deserialize - Function to convert the stored string back to a value
* @returns A writable store that persists to localStorage and can hold undefined values
*/
export const cachedWritableOptionalStore = <T>(
key: string,
defaultValue: T | undefined = undefined,
serialize: (value: T) => string,
deserialize: (serialized: string) => T
) =>
cachedWritableStore<T | undefined>(
key,
defaultValue,
(v) => (v !== undefined ? serialize(v) : ''),
(v) => (v !== '' ? deserialize(v) : undefined)
);

/**
* Creates a writable store that can hold an optional number value and persists to localStorage.
*
* @param {string} key - The localStorage key to use for persistence
* @param {number | undefined} defaultValue - The default value if nothing is found in localStorage
* @returns A writable store that persists to localStorage and can hold an optional number
*/
export const cachedWritableIntOptional = (key: string, defaultValue = undefined) =>
cachedWritableOptionalStore<number>(
key,
defaultValue,
(v) => v.toString(),
(v) => {
const parsed = Number.parseInt(v);
return isNaN(parsed) ? (defaultValue ?? 0) : parsed;
}
);

/**
* Creates a writable store that can hold an optional string value and persists to localStorage.
*
* @param {string} key - The localStorage key to use for persistence
* @param {string | undefined} defaultValue - The default value if nothing is found in localStorage
* @returns A writable store that persists to localStorage and can hold an optional string
*/
export const cachedWritableStringOptional = (key: string, defaultValue = undefined) =>
cachedWritableOptionalStore<string>(
key,
defaultValue,
(v) => v,
(v) => v
);
1 change: 0 additions & 1 deletion packages/webapp/src/lib/index.ts

This file was deleted.

23 changes: 23 additions & 0 deletions packages/webapp/src/lib/stores/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { cachedWritableStore } from '@rainlanguage/ui-components';

/**
* A persistent store that controls whether vaults with zero balance should be hidden in the UI.
*
* This setting is saved to local storage and persists between sessions.
*
* @default true - Zero balance vaults are hidden by default
* @returns A writable store containing a boolean value
*/
export const hideZeroBalanceVaults = cachedWritableStore<boolean>(
'settings.hideZeroBalanceVaults',
true, // default value is true
(value) => JSON.stringify(value),
(str) => {
try {
const value = JSON.parse(str);
return typeof value === 'boolean' ? value : true;
} catch {
return true;
}
}
);
6 changes: 3 additions & 3 deletions packages/webapp/src/routes/vaults/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
import { page } from '$app/stores';
import { connected } from '$lib/stores/wagmi';
import { writable } from 'svelte/store';
import { hideZeroBalanceVaults } from '$lib/stores/settings';

const {
activeOrderbook,
subgraphUrl,
orderHash,
activeSubgraphs,
settings,
accounts,
activeAccountsItems,
activeOrderStatus,
hideZeroBalanceVaults,
activeNetworkRef,
activeOrderbookRef,
activeAccounts,
activeNetworkOrderbooks,
showMyItemsOnly = writable(false)
showMyItemsOnly = writable(false),
activeSubgraphs
} = $page.data.stores;

export async function resetActiveNetworkRef() {
Expand Down
37 changes: 37 additions & 0 deletions tauri-app/src/lib/mocks/mockConfigSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { ConfigSource } from '@rainlanguage/orderbook';

export const mockConfigSource: ConfigSource = {
networks: {
mainnet: {
rpc: 'https://mainnet.infura.io/v3/YOUR-PROJECT-ID',
'chain-id': 1,
label: 'Ethereum Mainnet',
currency: 'ETH',
},
},
subgraphs: {
mainnet: 'https://api.thegraph.com/subgraphs/name/mainnet',
},
orderbooks: {
orderbook1: {
address: '0xOrderbookAddress1',
network: 'mainnet',
subgraph: 'uniswap',
label: 'Orderbook 1',
},
},
deployers: {
deployer1: {
address: '0xDeployerAddress1',
network: 'mainnet',
label: 'Deployer 1',
},
},
metaboards: {
metaboard1: 'https://example.com/metaboard1',
},
accounts: {
name_one: 'address_one',
name_two: 'address_two',
},
};
144 changes: 0 additions & 144 deletions tauri-app/src/lib/stores/settings.test.ts

This file was deleted.

Loading