Simplify thread loading
This commit is contained in:
parent
6a9314d513
commit
04239123bb
@ -1,101 +1,48 @@
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { u256, EventKind, NostrLink, FlatNoteStore, RequestBuilder, NostrPrefix } from "@snort/system";
|
import { EventKind, NostrLink, RequestBuilder, NoteCollection } from "@snort/system";
|
||||||
import { useRequestBuilder } from "@snort/system-react";
|
import { useRequestBuilder } from "@snort/system-react";
|
||||||
|
|
||||||
import { appendDedupe } from "SnortUtils";
|
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
import { useReactions } from "./FeedReactions";
|
||||||
|
|
||||||
interface RelayTaggedEventId {
|
|
||||||
id: u256;
|
|
||||||
relay?: string;
|
|
||||||
}
|
|
||||||
export default function useThreadFeed(link: NostrLink) {
|
export default function useThreadFeed(link: NostrLink) {
|
||||||
const [trackingEvents, setTrackingEvent] = useState<Array<RelayTaggedEventId>>([]);
|
const [allEvents, setAllEvents] = useState<Array<NostrLink>>([]);
|
||||||
const [trackingATags, setTrackingATags] = useState<string[]>([]);
|
|
||||||
const [allEvents, setAllEvents] = useState<Array<RelayTaggedEventId>>([]);
|
|
||||||
const pref = useLogin().preferences;
|
const pref = useLogin().preferences;
|
||||||
|
|
||||||
const sub = useMemo(() => {
|
const sub = useMemo(() => {
|
||||||
const sub = new RequestBuilder(`thread:${link.id.substring(0, 8)}`);
|
const sub = new RequestBuilder(`thread:${link.id}`);
|
||||||
sub.withOptions({
|
sub.withOptions({
|
||||||
leaveOpen: true,
|
leaveOpen: true,
|
||||||
});
|
});
|
||||||
if (trackingEvents.length > 0) {
|
sub.withFilter()
|
||||||
for (const te of trackingEvents) {
|
.kinds([EventKind.TextNote])
|
||||||
const fTracking = sub.withFilter();
|
.link(link);
|
||||||
fTracking.ids([te.id]);
|
|
||||||
if (te.relay) {
|
|
||||||
fTracking.relay(te.relay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allEvents.length > 0) {
|
if (allEvents.length > 0) {
|
||||||
sub
|
const f = sub
|
||||||
.withFilter()
|
.withFilter()
|
||||||
.kinds(
|
.kinds([EventKind.TextNote]);
|
||||||
pref.enableReactions
|
allEvents.forEach(x => f.replyToLink(x));
|
||||||
? [EventKind.Reaction, EventKind.TextNote, EventKind.Repost, EventKind.ZapReceipt]
|
|
||||||
: [EventKind.TextNote, EventKind.ZapReceipt, EventKind.Repost],
|
|
||||||
)
|
|
||||||
.tag(
|
|
||||||
"e",
|
|
||||||
allEvents.map(a => a.id),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (trackingATags.length > 0) {
|
|
||||||
const parsed = trackingATags.map(a => a.split(":"));
|
|
||||||
sub
|
|
||||||
.withFilter()
|
|
||||||
.kinds(parsed.map(a => Number(a[0])))
|
|
||||||
.authors(parsed.map(a => a[1]))
|
|
||||||
.tag(
|
|
||||||
"d",
|
|
||||||
parsed.map(a => a[2]),
|
|
||||||
);
|
|
||||||
sub.withFilter().tag("a", trackingATags);
|
|
||||||
}
|
}
|
||||||
return sub;
|
return sub;
|
||||||
}, [trackingEvents, trackingATags, allEvents, pref]);
|
}, [allEvents.length, pref]);
|
||||||
|
|
||||||
const store = useRequestBuilder(FlatNoteStore, sub);
|
const store = useRequestBuilder(NoteCollection, sub);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (link.type === NostrPrefix.Address) {
|
|
||||||
setTrackingATags([`${link.kind}:${link.author}:${link.id}`]);
|
|
||||||
} else {
|
|
||||||
const lnk = {
|
|
||||||
id: link.id,
|
|
||||||
relay: link.relays?.[0],
|
|
||||||
};
|
|
||||||
setTrackingEvent([lnk]);
|
|
||||||
setAllEvents([lnk]);
|
|
||||||
}
|
|
||||||
}, [link.id]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (store.data) {
|
if (store.data) {
|
||||||
const mainNotes = store.data?.filter(a => a.kind === EventKind.TextNote || a.kind === EventKind.Polls) ?? [];
|
const mainNotes = store.data?.filter(a => a.kind === EventKind.TextNote || a.kind === EventKind.Polls) ?? [];
|
||||||
|
const links = mainNotes.map(a => [
|
||||||
const eTags = mainNotes
|
NostrLink.fromEvent(a),
|
||||||
.map(a =>
|
...a.tags.filter(a => a[0] === "e" || a[0] === "a").map(v => NostrLink.fromTag(v))
|
||||||
a.tags
|
]).flat();
|
||||||
.filter(b => b[0] === "e")
|
setAllEvents(links);
|
||||||
.map(b => {
|
|
||||||
return {
|
|
||||||
id: b[1],
|
|
||||||
relay: b[2],
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.flat();
|
|
||||||
const eTagsMissing = eTags.filter(a => !mainNotes.some(b => b.id === a.id));
|
|
||||||
setTrackingEvent(s => appendDedupe(s, eTagsMissing));
|
|
||||||
setAllEvents(s => appendDedupe(s, eTags));
|
|
||||||
|
|
||||||
const aTags = mainNotes.map(a => a.tags.filter(b => b[0] === "a").map(b => b[1])).flat();
|
|
||||||
setTrackingATags(s => appendDedupe(s, aTags));
|
|
||||||
}
|
}
|
||||||
}, [store]);
|
}, [store.data?.length]);
|
||||||
|
|
||||||
return store;
|
const reactions = useReactions(`thread:${link.id}:reactions`, allEvents);
|
||||||
|
|
||||||
|
return {
|
||||||
|
thread: store.data ?? [],
|
||||||
|
reactions: reactions.data ?? [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -25,19 +25,19 @@ export const ThreadContext = createContext({} as ThreadContext);
|
|||||||
export function ThreadContextWrapper({ link, children }: { link: NostrLink; children?: ReactNode }) {
|
export function ThreadContextWrapper({ link, children }: { link: NostrLink; children?: ReactNode }) {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const [currentId, setCurrentId] = useState(link.id);
|
const [currentId, setCurrentId] = useState(link.id);
|
||||||
const thread = useThreadFeed(link);
|
const feed = useThreadFeed(link);
|
||||||
|
|
||||||
const chains = useMemo(() => {
|
const chains = useMemo(() => {
|
||||||
const chains = new Map<u256, Array<TaggedNostrEvent>>();
|
const chains = new Map<u256, Array<TaggedNostrEvent>>();
|
||||||
if (thread.data) {
|
if (feed.thread) {
|
||||||
thread.data
|
feed.thread
|
||||||
?.sort((a, b) => b.created_at - a.created_at)
|
?.sort((a, b) => b.created_at - a.created_at)
|
||||||
.forEach(v => {
|
.forEach(v => {
|
||||||
const t = EventExt.extractThread(v);
|
const t = EventExt.extractThread(v);
|
||||||
let replyTo = t?.replyTo?.value ?? t?.root?.value;
|
let replyTo = t?.replyTo?.value ?? t?.root?.value;
|
||||||
if (t?.root?.key === "a" && t?.root?.value) {
|
if (t?.root?.key === "a" && t?.root?.value) {
|
||||||
const parsed = t.root.value.split(":");
|
const parsed = t.root.value.split(":");
|
||||||
replyTo = thread.data?.find(
|
replyTo = feed.thread?.find(
|
||||||
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2],
|
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2],
|
||||||
)?.id;
|
)?.id;
|
||||||
}
|
}
|
||||||
@ -51,12 +51,12 @@ export function ThreadContextWrapper({ link, children }: { link: NostrLink; chil
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return chains;
|
return chains;
|
||||||
}, [thread.data]);
|
}, [feed.thread]);
|
||||||
|
|
||||||
// Root is the parent of the current note or the current note if its a root note or the root of the thread
|
// Root is the parent of the current note or the current note if its a root note or the root of the thread
|
||||||
const root = useMemo(() => {
|
const root = useMemo(() => {
|
||||||
const currentNote =
|
const currentNote =
|
||||||
thread.data?.find(
|
feed.thread?.find(
|
||||||
ne =>
|
ne =>
|
||||||
ne.id === currentId ||
|
ne.id === currentId ||
|
||||||
(link.type === NostrPrefix.Address && findTag(ne, "d") === currentId && ne.pubkey === link.author),
|
(link.type === NostrPrefix.Address && findTag(ne, "d") === currentId && ne.pubkey === link.author),
|
||||||
@ -74,16 +74,16 @@ export function ThreadContextWrapper({ link, children }: { link: NostrLink; chil
|
|||||||
if (replyTo) {
|
if (replyTo) {
|
||||||
if (replyTo.key === "a" && replyTo.value) {
|
if (replyTo.key === "a" && replyTo.value) {
|
||||||
const parsed = replyTo.value.split(":");
|
const parsed = replyTo.value.split(":");
|
||||||
return thread.data?.find(
|
return feed.thread?.find(
|
||||||
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2],
|
a => a.kind === Number(parsed[0]) && a.pubkey === parsed[1] && findTag(a, "d") === parsed[2],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (replyTo.value) {
|
if (replyTo.value) {
|
||||||
return thread.data?.find(a => a.id === replyTo.value);
|
return feed.thread?.find(a => a.id === replyTo.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const possibleRoots = thread.data?.filter(a => {
|
const possibleRoots = feed.thread?.filter(a => {
|
||||||
const thread = EventExt.extractThread(a);
|
const thread = EventExt.extractThread(a);
|
||||||
return isRoot(thread);
|
return isRoot(thread);
|
||||||
});
|
});
|
||||||
@ -98,14 +98,14 @@ export function ThreadContextWrapper({ link, children }: { link: NostrLink; chil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [thread.data, currentId, location]);
|
}, [feed.thread, currentId, location]);
|
||||||
|
|
||||||
const ctxValue = useMemo(() => {
|
const ctxValue = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
current: currentId,
|
current: currentId,
|
||||||
root,
|
root,
|
||||||
chains,
|
chains,
|
||||||
data: thread.data,
|
data: feed.reactions,
|
||||||
setCurrent: v => setCurrentId(v),
|
setCurrent: v => setCurrentId(v),
|
||||||
} as ThreadContext;
|
} as ThreadContext;
|
||||||
}, [root, chains]);
|
}, [root, chains]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user