diff --git a/src/Element/Textarea.tsx b/src/Element/Textarea.tsx index 116d272d..c71a92fc 100644 --- a/src/Element/Textarea.tsx +++ b/src/Element/Textarea.tsx @@ -9,8 +9,8 @@ import TextareaAutosize from "react-textarea-autosize"; import Avatar from "Element/Avatar"; import Nip05 from "Element/Nip05"; import { hexToBech32 } from "Util"; -import { db } from "Db"; -import { useQuery, MetadataCache } from "State/Users"; +import { MetadataCache } from "State/Users"; +import { useQuery } from "State/Users/Hooks"; interface EmojiItemProps { name: string diff --git a/src/Feed/ProfileFeed.ts b/src/Feed/ProfileFeed.ts index d633a611..ad1842b6 100644 --- a/src/Feed/ProfileFeed.ts +++ b/src/Feed/ProfileFeed.ts @@ -2,7 +2,8 @@ import { useLiveQuery } from "dexie-react-hooks"; import { useSelector } from "react-redux"; import { useEffect, useMemo } from "react"; import { RootState } from "State/Store"; -import { MetadataCache, find, bulkGet, useQuery, useKey, useKeys } from "State/Users"; +import { MetadataCache } from "State/Users"; +import { useKey, useKeys } from "State/Users/Hooks"; import { HexKey } from "Nostr"; import { System } from "Nostr/System"; diff --git a/src/State/Users.ts b/src/State/Users.ts index 5932fbe6..38dbfbaf 100644 --- a/src/State/Users.ts +++ b/src/State/Users.ts @@ -1,6 +1,4 @@ -import { useMemo } from "react"; import { createSlice, PayloadAction } from '@reduxjs/toolkit' -import { useLiveQuery } from "dexie-react-hooks"; import { HexKey, TaggedRawEvent, UserMetadata } from "Nostr"; import { hexToBech32 } from "../Util"; import { db } from "Db"; @@ -68,11 +66,6 @@ function groupByPubkey(acc: Record, user: MetadataCache) return { ...acc, [user.pubkey]: user } } -function groupByPubkeyMap(acc: Map, user: MetadataCache) { - acc.set(user.pubkey, user) - return acc -} - export const add = async (user: MetadataCache) => { try { return await db.users.add(user) @@ -150,76 +143,4 @@ export const bulkPut = async (newUsers: MetadataCache[]) => { } } -export function useQuery(query: string, limit: number = 5) { - const state = store.getState() - const { users } = state.users - - const inMemoryUsers = useMemo(() => { - return Object.values(users).filter((user) => { - return user.name?.includes(query) - || user.npub?.includes(query) - || user.display_name?.includes(query) - || user.nip05?.includes(query) - }) - }, [users, query]) - - const allUsers = useLiveQuery( - () => db.users - .where("npub").startsWithIgnoreCase(query) - .or("name").startsWithIgnoreCase(query) - .or("display_name").startsWithIgnoreCase(query) - .or("nip05").startsWithIgnoreCase(query) - .limit(5) - .toArray() - .catch((err) => { - return inMemoryUsers - }), - [query], - ) - - return allUsers -} - -export function useKey(pubKey: HexKey) { - const state = store.getState() - const { users } = state.users - - const inMemoryUser = useMemo(() => { - return users[pubKey] - }, [users, pubKey]) - - const user = useLiveQuery(async () => { - if (pubKey) { - return await find(pubKey); - } - }, [pubKey]); - - return user ?? inMemoryUser -} - -export function useKeys(pubKeys: HexKey[]): Map { - const state = store.getState() - const { users } = state.users - - const inMemoryUsers = useMemo(() => { - const res = new Map() - Object.values(users).forEach(u => { - if (pubKeys.includes(u.pubkey)) { - res.set(u.pubkey, u) - } - }) - return res - }, [users, pubKeys]) - - const dbUsers = useLiveQuery(async () => { - if (pubKeys) { - const ret = await bulkGet(pubKeys); - return new Map(ret.map(a => [a.pubkey, a])) - } - return new Map() - }, [pubKeys]); - - return dbUsers || inMemoryUsers -} - export const reducer = UsersSlice.reducer; diff --git a/src/State/Users/Hooks.ts b/src/State/Users/Hooks.ts new file mode 100644 index 00000000..c5a9138b --- /dev/null +++ b/src/State/Users/Hooks.ts @@ -0,0 +1,89 @@ +import { useMemo } from "react"; +import { useSelector } from "react-redux"; +import { useLiveQuery } from "dexie-react-hooks"; + +import { RootState } from "State/Store"; +import { MetadataCache } from "State/Users"; +import { HexKey } from "Nostr"; +import { db } from "Db"; + +export function useQuery(query: string, limit: number = 5) { + const { users } = useSelector((state: RootState) => state.users) + + const inMemoryUsers = useMemo(() => { + return Object.values(users).filter(user => { + const profile = user as MetadataCache + return profile.name?.includes(query) + || profile.npub?.includes(query) + || profile.display_name?.includes(query) + || profile.nip05?.includes(query) + }) + }, [users, query]) + + const allUsers = useLiveQuery( + () => db.users + .where("npub").startsWithIgnoreCase(query) + .or("name").startsWithIgnoreCase(query) + .or("display_name").startsWithIgnoreCase(query) + .or("nip05").startsWithIgnoreCase(query) + .limit(5) + .toArray() + .catch((err) => { + return inMemoryUsers + }), + [query, inMemoryUsers], + ) + + return allUsers +} + +export function useKey(pubKey: HexKey) { + const { users } = useSelector((s: RootState) => s.users) + + const inMemoryUser = useMemo(() => { + return users[pubKey] + }, [users, pubKey]) + + const user = useLiveQuery(async () => { + if (pubKey) { + try { + return await db.users.get(pubKey); + } catch (error) { + return inMemoryUser + } + } + }, [pubKey, inMemoryUser]); + + return user +} + +export function useKeys(pubKeys: HexKey[]): Map { + const { users } = useSelector((s: RootState) => s.users) + + const inMemoryUsers = useMemo(() => { + const res = new Map() + Object.values(users).forEach(u => { + const profile = u as MetadataCache + if (pubKeys.includes(profile.pubkey)) { + res.set(profile.pubkey, profile) + } + }) + return res + }, [users, pubKeys]) + + const dbUsers = useLiveQuery(async () => { + if (pubKeys) { + try { + const ret = await db.users.bulkGet(pubKeys); + // @ts-ignore + return new Map(ret.map(a => [a.pubkey, a])) + } catch (error) { + return inMemoryUsers + } + } + return new Map() + }, [pubKeys, inMemoryUsers]); + + return dbUsers || inMemoryUsers +} +