Per-user search history (#7588)

* per-user search history

* move to mmkv with cool new hook

* revert accidental changes

This reverts commit 27c89fa645eff0acb7a8fd852203ff1ea3725c69.

* restore limits
This commit is contained in:
Samuel Newman
2025-02-07 11:18:51 +00:00
committed by GitHub
parent b12d39b4cf
commit 4b706c9519
4 changed files with 138 additions and 117 deletions
+69 -3
View File
@@ -1,5 +1,5 @@
import {useCallback, useEffect, useState} from 'react'
import {MMKV} from 'react-native-mmkv'
import {Did} from '@atproto/api'
import {Account, Device} from '#/storage/schema'
@@ -65,6 +65,72 @@ export class Storage<Scopes extends unknown[], Schema> {
removeMany<Key extends keyof Schema>(scopes: [...Scopes], keys: Key[]) {
keys.forEach(key => this.remove([...scopes, key]))
}
/**
* Fires a callback when the storage associated with a given key changes
*
* @returns Listener - call `remove()` to stop listening
*/
addOnValueChangedListener<Key extends keyof Schema>(
scopes: [...Scopes, Key],
callback: () => void,
) {
return this.store.addOnValueChangedListener(key => {
if (key === scopes.join(this.sep)) {
callback()
}
})
}
}
type StorageSchema<T extends Storage<any, any>> = T extends Storage<
any,
infer U
>
? U
: never
type StorageScopes<T extends Storage<any, any>> = T extends Storage<
infer S,
any
>
? S
: never
/**
* Hook to use a storage instance. Acts like a useState hook, but persists the
* value in storage.
*/
export function useStorage<
Store extends Storage<any, any>,
Key extends keyof StorageSchema<Store>,
>(
storage: Store,
scopes: [...StorageScopes<Store>, Key],
): [
StorageSchema<Store>[Key] | undefined,
(data: StorageSchema<Store>[Key]) => void,
] {
type Schema = StorageSchema<Store>
const [value, setValue] = useState<Schema[Key] | undefined>(() =>
storage.get(scopes),
)
useEffect(() => {
const sub = storage.addOnValueChangedListener(scopes, () => {
setValue(storage.get(scopes))
})
return () => sub.remove()
}, [storage, scopes])
const setter = useCallback(
(data: Schema[Key]) => {
setValue(data)
storage.set(scopes, data)
},
[storage, scopes],
)
return [value, setter] as const
}
/**
@@ -77,10 +143,10 @@ export const device = new Storage<[], Device>({id: 'bsky_device'})
/**
* Account data that's specific to the account on this device
*/
export const account = new Storage<[Did], Account>({id: 'bsky_account'})
export const account = new Storage<[string], Account>({id: 'bsky_account'})
if (__DEV__ && typeof window !== 'undefined') {
// @ts-ignore
// @ts-expect-error - dev global
window.bsky_storage = {
device,
account,
+1
View File
@@ -13,4 +13,5 @@ export type Device = {
export type Account = {
searchTermHistory?: string[]
searchAccountHistory?: string[]
}