feat: improve profile cache (again)

This commit is contained in:
2023-03-03 14:30:31 +00:00
parent 27edf5f592
commit 32549522d4
32 changed files with 316 additions and 472 deletions

View File

@ -1,7 +1,9 @@
import "./Avatar.css";
import Nostrich from "nostrich.webp";
import { CSSProperties, useEffect, useState } from "react";
import type { UserMetadata } from "@snort/nostr";
import useImgProxy from "Hooks/useImgProxy";
const Avatar = ({ user, ...rest }: { user?: UserMetadata; onClick?: () => void }) => {

View File

@ -5,8 +5,8 @@ import { FormattedMessage } from "react-intl";
import { dedupeByPubkey } from "Util";
import Note from "Element/Note";
import { HexKey, TaggedRawEvent } from "@snort/nostr";
import { useUserProfiles } from "Feed/ProfileFeed";
import { RootState } from "State/Store";
import { UserCache } from "State/Users/UserCache";
import messages from "./messages";
@ -22,10 +22,9 @@ const Bookmarks = ({ pubkey, bookmarks, related }: BookmarksProps) => {
const ps = useMemo(() => {
return dedupeByPubkey(bookmarks).map(ev => ev.pubkey);
}, [bookmarks]);
const profiles = useUserProfiles(ps);
function renderOption(p: HexKey) {
const profile = profiles?.get(p);
const profile = UserCache.get(p);
return profile ? <option value={p}>{profile?.display_name || profile?.name}</option> : null;
}

View File

@ -54,7 +54,7 @@ export default function DM(props: DMProps) {
<NoteTime from={props.data.created_at * 1000} fallback={formatMessage(messages.JustNow)} />
</div>
<div className="w-max">
<Text content={content} tags={[]} users={new Map()} creator={otherPubkey} />
<Text content={content} tags={[]} creator={otherPubkey} />
</div>
</div>
);

View File

@ -1,6 +1,6 @@
import { useMemo } from "react";
import { Link } from "react-router-dom";
import { useUserProfile } from "Feed/ProfileFeed";
import { useUserProfile } from "Hooks/useUserProfile";
import { HexKey } from "@snort/nostr";
import { hexToBech32, profileLink } from "Util";

View File

@ -17,7 +17,7 @@ import {
import AsyncButton from "Element/AsyncButton";
import SendSats from "Element/SendSats";
import Copy from "Element/Copy";
import { useUserProfile } from "Feed/ProfileFeed";
import { useUserProfile } from "Hooks/useUserProfile";
import useEventPublisher from "Feed/EventPublisher";
import { debounce } from "Util";
import { UserMetadata } from "@snort/nostr";

View File

@ -18,14 +18,15 @@ import {
hexToBech32,
normalizeReaction,
Reaction,
profileLink,
} from "Util";
import NoteFooter, { Translation } from "Element/NoteFooter";
import NoteTime from "Element/NoteTime";
import { useUserProfiles } from "Feed/ProfileFeed";
import { TaggedRawEvent, u256, HexKey, Event as NEvent, EventKind } from "@snort/nostr";
import useModeration from "Hooks/useModeration";
import { setPinned, setBookmarked } from "State/Login";
import type { RootState } from "State/Store";
import { UserCache } from "State/Users/UserCache";
import messages from "./messages";
@ -72,8 +73,6 @@ export default function Note(props: NoteProps) {
const { data, related, highlight, options: opt, ["data-ev"]: parsedEvent, ignoreModeration = false } = props;
const [showReactions, setShowReactions] = useState(false);
const ev = useMemo(() => parsedEvent ?? new NEvent(data), [data]);
const pubKeys = useMemo(() => ev.Thread?.PubKeys || [], [ev]);
const users = useUserProfiles(pubKeys);
const deletions = useMemo(() => getReactions(related, ev.Id, EventKind.Deletion), [related]);
const { isMuted } = useModeration();
const isOpMuted = isMuted(ev.PubKey);
@ -162,7 +161,7 @@ export default function Note(props: NoteProps) {
</b>
);
}
return <Text content={body} tags={ev.Tags} users={users || new Map()} creator={ev.PubKey} />;
return <Text content={body} tags={ev.Tags} creator={ev.PubKey} />;
}, [ev]);
useLayoutEffect(() => {
@ -188,22 +187,14 @@ export default function Note(props: NoteProps) {
const replyId = ev.Thread?.ReplyTo?.Event ?? ev.Thread?.Root?.Event;
const mentions: { pk: string; name: string; link: ReactNode }[] = [];
for (const pk of ev.Thread?.PubKeys ?? []) {
const u = users?.get(pk);
const u = UserCache.get(pk);
const npub = hexToBech32("npub", pk);
const shortNpub = npub.substring(0, 12);
if (u) {
mentions.push({
pk,
name: u.name ?? shortNpub,
link: <Link to={`/p/${npub}`}>{u.name ? `@${u.name}` : shortNpub}</Link>,
});
} else {
mentions.push({
pk,
name: shortNpub,
link: <Link to={`/p/${npub}`}>{shortNpub}</Link>,
});
}
mentions.push({
pk,
name: u?.name ?? shortNpub,
link: <Link to={profileLink(pk)}>{u?.name ? `@${u.name}` : shortNpub}</Link>,
});
}
mentions.sort(a => (a.name.startsWith("npub") ? 1 : -1));
const othersLength = mentions.length - maxMentions;

View File

@ -15,7 +15,7 @@ import { NoteCreator } from "Element/NoteCreator";
import Reactions from "Element/Reactions";
import SendSats from "Element/SendSats";
import { ParsedZap, ZapsSummary } from "Element/Zap";
import { useUserProfile } from "Feed/ProfileFeed";
import { useUserProfile } from "Hooks/useUserProfile";
import { RootState } from "State/Store";
import { UserPreferences, setPinned, setBookmarked } from "State/Login";
import useModeration from "Hooks/useModeration";

View File

@ -2,7 +2,7 @@ import "./ProfileImage.css";
import { useMemo } from "react";
import { Link, useNavigate } from "react-router-dom";
import { useUserProfile } from "Feed/ProfileFeed";
import { useUserProfile } from "Hooks/useUserProfile";
import { hexToBech32, profileLink } from "Util";
import Avatar from "Element/Avatar";
import Nip05 from "Element/Nip05";

View File

@ -3,7 +3,7 @@ import { ReactNode } from "react";
import ProfileImage from "Element/ProfileImage";
import FollowButton from "Element/FollowButton";
import { useUserProfile } from "Feed/ProfileFeed";
import { useUserProfile } from "Hooks/useUserProfile";
import { HexKey } from "@snort/nostr";
import { useInView } from "react-intersection-observer";

View File

@ -10,7 +10,6 @@ import Invoice from "Element/Invoice";
import Hashtag from "Element/Hashtag";
import { Tag } from "@snort/nostr";
import { MetadataCache } from "State/Users";
import Mention from "Element/Mention";
import HyperText from "Element/HyperText";
import { HexKey } from "@snort/nostr";
@ -21,17 +20,15 @@ export type Fragment = string | React.ReactNode;
export interface TextFragment {
body: React.ReactNode[];
tags: Tag[];
users: Map<string, MetadataCache>;
}
export interface TextProps {
content: string;
creator: HexKey;
tags: Tag[];
users: Map<string, MetadataCache>;
}
export default function Text({ content, tags, creator, users }: TextProps) {
export default function Text({ content, tags, creator }: TextProps) {
function extractLinks(fragments: Fragment[]) {
return fragments
.map(f => {
@ -143,9 +140,9 @@ export default function Text({ content, tags, creator, users }: TextProps) {
const components = useMemo(() => {
return {
p: (x: { children?: React.ReactNode[] }) => transformParagraph({ body: x.children ?? [], tags, users }),
p: (x: { children?: React.ReactNode[] }) => transformParagraph({ body: x.children ?? [], tags }),
a: (x: { href?: string }) => <HyperText link={x.href ?? ""} creator={creator} />,
li: (x: { children?: Fragment[] }) => transformLi({ body: x.children ?? [], tags, users }),
li: (x: { children?: Fragment[] }) => transformLi({ body: x.children ?? [], tags }),
};
}, [content]);

View File

@ -1,7 +1,6 @@
import "@webscopeio/react-textarea-autocomplete/style.css";
import "./Textarea.css";
import { useState } from "react";
import { useIntl } from "react-intl";
import ReactTextareaAutocomplete from "@webscopeio/react-textarea-autocomplete";
import emoji from "@jukben/emoji-search";
@ -11,7 +10,7 @@ import Avatar from "Element/Avatar";
import Nip05 from "Element/Nip05";
import { hexToBech32 } from "Util";
import { MetadataCache } from "State/Users";
import { useQuery } from "State/Users/Hooks";
import { UserCache } from "State/Users/UserCache";
import messages from "./messages";
@ -53,14 +52,10 @@ interface TextareaProps {
}
const Textarea = (props: TextareaProps) => {
const [query, setQuery] = useState("");
const { formatMessage } = useIntl();
const allUsers = useQuery(query);
const userDataProvider = (token: string) => {
setQuery(token);
return allUsers ?? [];
const userDataProvider = async (token: string) => {
return await UserCache.search(token);
};
const emojiDataProvider = (token: string) => {

View File

@ -109,7 +109,7 @@ const Zap = ({ zap, showZapped = true }: { zap: ParsedZap; showZapped?: boolean
</div>
{content.length > 0 && zapper && (
<div className="body">
<Text creator={zapper} content={content} tags={[]} users={new Map()} />
<Text creator={zapper} content={content} tags={[]} />
</div>
)}
</div>

View File

@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useState } from "react";
import { HexKey } from "@snort/nostr";
import { useUserProfile } from "Feed/ProfileFeed";
import { useUserProfile } from "Hooks/useUserProfile";
import SendSats from "Element/SendSats";
const ZapButton = ({ pubkey, lnurl }: { pubkey: HexKey; lnurl?: string }) => {