refactor: reactions grouping and other fixes
This commit is contained in:
@ -30,7 +30,6 @@ export class EventInteractionCache extends FeedCache<EventInteraction> {
|
||||
});
|
||||
await this.bulkSet(toImport);
|
||||
|
||||
console.debug(`Imported dumb-zap-cache events: `, toImport.length);
|
||||
window.localStorage.removeItem("zap-cache");
|
||||
}
|
||||
await this.buffer([...this.onTable]);
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { unixNow, unixNowMs } from "@snort/shared";
|
||||
import { EventKind, RequestBuilder, SystemInterface, TaggedNostrEvent } from "@snort/system";
|
||||
import debug from "debug";
|
||||
|
||||
import { db } from "@/Db";
|
||||
import { Day, Hour } from "@/Utils/Const";
|
||||
@ -68,8 +67,7 @@ export class FollowsFeedCache extends RefreshFeedCache<TaggedNostrEvent> {
|
||||
const oldest = await this.table?.orderBy("created_at").first();
|
||||
this.#oldest = oldest?.created_at;
|
||||
this.emit("change", latest?.map(a => this.key(a)) ?? []);
|
||||
|
||||
debug(this.name)(`Loaded %d/%d in %d ms`, latest?.length ?? 0, keys.length, (unixNowMs() - start).toLocaleString());
|
||||
this.log(`Loaded %d/%d in %d ms`, latest?.length ?? 0, keys.length, (unixNowMs() - start).toLocaleString());
|
||||
}
|
||||
|
||||
async loadMore(system: SystemInterface, session: LoginSession, before: number) {
|
||||
@ -132,7 +130,7 @@ export class FollowsFeedCache extends RefreshFeedCache<TaggedNostrEvent> {
|
||||
const allKeys = new Set(everything?.map(a => a.pubkey));
|
||||
const missingKeys = keys.filter(a => !allKeys.has(a));
|
||||
await this.backFill(system, missingKeys);
|
||||
debug(this.name)(`Backfilled %d keys in %d ms`, missingKeys.length, (unixNowMs() - start).toLocaleString());
|
||||
this.log(`Backfilled %d keys in %d ms`, missingKeys.length, (unixNowMs() - start).toLocaleString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,13 +32,8 @@ export function LongFormText(props: LongFormTextProps) {
|
||||
const [reading, setReading] = useState(false);
|
||||
const [showMore, setShowMore] = useState(false);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const related = useReactions(
|
||||
NostrLink.fromEvent(props.ev).id + "related",
|
||||
[NostrLink.fromEvent(props.ev)],
|
||||
undefined,
|
||||
false,
|
||||
);
|
||||
const { reactions, reposts, zaps } = useEventReactions(NostrLink.fromEvent(props.ev), related.data ?? []);
|
||||
const related = useReactions("note:reactions", [NostrLink.fromEvent(props.ev)], undefined, false);
|
||||
const { reactions, reposts, zaps } = useEventReactions(NostrLink.fromEvent(props.ev), related);
|
||||
|
||||
function previewText() {
|
||||
return (
|
||||
|
@ -10,8 +10,8 @@ import { findTag } from "@/Utils";
|
||||
export default function NostrFileHeader({ link }: { link: NostrLink }) {
|
||||
const ev = useEventFeed(link);
|
||||
|
||||
if (!ev.data) return <PageSpinner />;
|
||||
return <NostrFileElement ev={ev.data} />;
|
||||
if (!ev) return <PageSpinner />;
|
||||
return <NostrFileElement ev={ev} />;
|
||||
}
|
||||
|
||||
export function NostrFileElement({ ev }: { ev: NostrEvent }) {
|
||||
|
@ -36,8 +36,8 @@ export default function NoteFooter(props: NoteFooterProps) {
|
||||
const link = useMemo(() => NostrLink.fromEvent(ev), [ev.id]);
|
||||
const ids = useMemo(() => [link], [link]);
|
||||
|
||||
const related = useReactions(link.id + "related", ids, undefined, false);
|
||||
const { reactions, zaps, reposts } = useEventReactions(link, related.data ?? []);
|
||||
const related = useReactions("note:reactions", ids, undefined, false);
|
||||
const { reactions, zaps, reposts } = useEventReactions(link, related);
|
||||
const { positive } = reactions;
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
|
@ -11,11 +11,11 @@ const options = {
|
||||
|
||||
export default function NoteQuote({ link, depth }: { link: NostrLink; depth?: number }) {
|
||||
const ev = useEventFeed(link);
|
||||
if (!ev.data)
|
||||
if (!ev)
|
||||
return (
|
||||
<div className="note-quote flex items-center justify-center h-[110px]">
|
||||
<PageSpinner />
|
||||
</div>
|
||||
);
|
||||
return <Note data={ev.data} className="note-quote" depth={(depth ?? 0) + 1} options={options} />;
|
||||
return <Note data={ev} className="note-quote" depth={(depth ?? 0) + 1} options={options} />;
|
||||
}
|
||||
|
@ -26,11 +26,11 @@ const ReactionsModal = ({ show, setShow, event }: ReactionsModalProps) => {
|
||||
|
||||
const link = NostrLink.fromEvent(event);
|
||||
|
||||
const related = useReactions(link.id + "related", [link], undefined, false);
|
||||
const { reactions, zaps, reposts } = useEventReactions(link, related.data ?? []);
|
||||
const related = useReactions("note:reactions", [link], undefined, false);
|
||||
const { reactions, zaps, reposts } = useEventReactions(link, related);
|
||||
const { positive, negative } = reactions;
|
||||
|
||||
const sortEvents = events =>
|
||||
const sortEvents = (events: Array<TaggedNostrEvent>) =>
|
||||
events.sort(
|
||||
(a, b) => socialGraphInstance.getFollowDistance(a.pubkey) - socialGraphInstance.getFollowDistance(b.pubkey),
|
||||
);
|
||||
|
@ -16,7 +16,7 @@ export default function Articles() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{orderDescending(data.data ?? []).map(a => (
|
||||
{orderDescending(data).map(a => (
|
||||
<Note
|
||||
data={a}
|
||||
key={a.id}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { NostrLink, NoteCollection, ReqFilter, RequestBuilder } from "@snort/system";
|
||||
import { NostrLink, ReqFilter, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
@ -6,7 +6,6 @@ import { TimelineRenderer } from "@/Components/Feed/TimelineRenderer";
|
||||
|
||||
export function GenericFeed({ link }: { link: NostrLink }) {
|
||||
const sub = useMemo(() => {
|
||||
console.debug(link);
|
||||
const sub = new RequestBuilder("generic");
|
||||
sub.withOptions({ leaveOpen: true });
|
||||
const reqs = JSON.parse(link.id) as Array<ReqFilter>;
|
||||
@ -17,11 +16,11 @@ export function GenericFeed({ link }: { link: NostrLink }) {
|
||||
return sub;
|
||||
}, [link]);
|
||||
|
||||
const evs = useRequestBuilder(NoteCollection, sub);
|
||||
const evs = useRequestBuilder(sub);
|
||||
|
||||
return (
|
||||
<TimelineRenderer
|
||||
frags={[{ events: evs.data ?? [], refTime: 0 }]}
|
||||
frags={[{ events: evs, refTime: 0 }]}
|
||||
latest={[]}
|
||||
showLatest={() => {
|
||||
//nothing
|
||||
|
@ -70,7 +70,7 @@ const TimelineFollows = (props: TimelineFollowsProps) => {
|
||||
};
|
||||
const mixinFiltered = useMemo(() => {
|
||||
const mainFeedIds = new Set(mainFeed.map(a => a.id));
|
||||
return (mixin.data.data ?? [])
|
||||
return (mixin.data ?? [])
|
||||
.filter(a => !mainFeedIds.has(a.id) && postsOnly(a) && !isEventMuted(a))
|
||||
.filter(a => a.tags.filter(a => a[0] === "t").length < 5)
|
||||
.filter(a => !oldest || a.created_at >= oldest)
|
||||
|
@ -38,7 +38,7 @@ export default function SearchBox() {
|
||||
const subject: TimelineSubject = {
|
||||
type: "profile_keyword",
|
||||
discriminator: search,
|
||||
items: [search],
|
||||
items: search ? [search] : [],
|
||||
relay: undefined,
|
||||
streams: false,
|
||||
};
|
||||
|
@ -84,10 +84,8 @@ export default function SendSats(props: SendSatsProps) {
|
||||
useEffect(() => {
|
||||
if (props.targets && props.show) {
|
||||
try {
|
||||
console.debug("loading zapper");
|
||||
const zapper = new Zapper(system, publisher);
|
||||
zapper.load(props.targets).then(() => {
|
||||
console.debug(zapper);
|
||||
setZapper(zapper);
|
||||
});
|
||||
} catch (e) {
|
||||
|
@ -31,7 +31,7 @@ export default function TrendingNotes({ count = Infinity, small = false }: { cou
|
||||
return removeUndefined(
|
||||
data.notes.map(a => {
|
||||
const ev = a.event;
|
||||
if (!System.Optimizer.schnorrVerify(ev)) {
|
||||
if (!System.optimizer.schnorrVerify(ev)) {
|
||||
console.error(`Event with invalid sig\n\n${ev}\n\nfrom ${trendingNotesUrl}`);
|
||||
return;
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ export function ProfileLink({
|
||||
children?: ReactNode;
|
||||
} & Omit<LinkProps, "to">) {
|
||||
const system = useContext(SnortContext);
|
||||
const relays = system.relayCache.getFromCache(pubkey)
|
||||
const relays = system.relayCache
|
||||
.getFromCache(pubkey)
|
||||
?.relays?.filter(a => a.settings.write)
|
||||
?.map(a => a.url);
|
||||
|
||||
|
@ -20,11 +20,8 @@ export default function useProfileBadges(pubkey?: HexKey) {
|
||||
const profileBadges = useRequestBuilder(sub);
|
||||
|
||||
const profile = useMemo(() => {
|
||||
if (profileBadges.data) {
|
||||
return chunks(
|
||||
profileBadges.data[0].tags.filter(t => t[0] === "a" || t[0] === "e"),
|
||||
2,
|
||||
).reduce((acc, [a, e]) => {
|
||||
if (profileBadges) {
|
||||
return chunks(profileBadges[0]?.tags.filter(t => t[0] === "a" || t[0] === "e"), 2).reduce((acc, [a, e]) => {
|
||||
return {
|
||||
...acc,
|
||||
[e[1]]: a[1],
|
||||
@ -60,8 +57,8 @@ export default function useProfileBadges(pubkey?: HexKey) {
|
||||
const awards = useRequestBuilder(awardsSub);
|
||||
|
||||
const result = useMemo(() => {
|
||||
if (awards.data) {
|
||||
return awards.data
|
||||
if (awards) {
|
||||
return awards
|
||||
.map((award, _, arr) => {
|
||||
const [, pubkey, d] =
|
||||
award.tags
|
||||
|
@ -13,7 +13,7 @@ export default function useFollowersFeed(pubkey?: HexKey) {
|
||||
const followersFeed = useRequestBuilder(sub);
|
||||
|
||||
const followers = useMemo(() => {
|
||||
const contactLists = followersFeed.data?.filter(
|
||||
const contactLists = followersFeed?.filter(
|
||||
a => a.kind === EventKind.ContactList && a.tags.some(b => b[0] === "p" && b[1] === pubkey),
|
||||
);
|
||||
return [...new Set(contactLists?.map(a => a.pubkey))].sort((a, b) => {
|
||||
|
@ -21,7 +21,7 @@ export default function useFollowsFeed(pubkey?: HexKey) {
|
||||
return follows.item;
|
||||
}
|
||||
|
||||
return getFollowing(contactFeed.data ?? [], pubkey);
|
||||
return getFollowing(contactFeed ?? [], pubkey);
|
||||
}, [contactFeed, follows, pubkey]);
|
||||
}
|
||||
|
||||
|
@ -100,8 +100,8 @@ export default function useLoginFeed() {
|
||||
|
||||
// update relays and follow lists
|
||||
useEffect(() => {
|
||||
if (loginFeed.data) {
|
||||
const contactList = getNewest(loginFeed.data.filter(a => a.kind === EventKind.ContactList));
|
||||
if (loginFeed) {
|
||||
const contactList = getNewest(loginFeed.filter(a => a.kind === EventKind.ContactList));
|
||||
if (contactList) {
|
||||
const pTags = contactList.tags.filter(a => a[0] === "p").map(a => a[1]);
|
||||
setFollows(login.id, pTags, contactList.created_at * 1000);
|
||||
@ -109,17 +109,17 @@ export default function useLoginFeed() {
|
||||
FollowsFeed.backFillIfMissing(system, pTags);
|
||||
}
|
||||
|
||||
const relays = getNewest(loginFeed.data.filter(a => a.kind === EventKind.Relays));
|
||||
const relays = getNewest(loginFeed.filter(a => a.kind === EventKind.Relays));
|
||||
if (relays) {
|
||||
const parsedRelays = parseRelayTags(relays.tags.filter(a => a[0] === "r")).map(a => [a.url, a.settings]);
|
||||
setRelays(login, Object.fromEntries(parsedRelays), relays.created_at * 1000);
|
||||
}
|
||||
|
||||
Nip4Chats.onEvent(loginFeed.data);
|
||||
Nip28Chats.onEvent(loginFeed.data);
|
||||
Nip4Chats.onEvent(loginFeed);
|
||||
Nip28Chats.onEvent(loginFeed);
|
||||
|
||||
if (publisher) {
|
||||
const subs = loginFeed.data.filter(
|
||||
const subs = loginFeed.filter(
|
||||
a => a.kind === EventKind.SnortSubscriptions && a.pubkey === bech32ToHex(SnortPubKey),
|
||||
);
|
||||
Promise.all(
|
||||
@ -135,7 +135,7 @@ export default function useLoginFeed() {
|
||||
}),
|
||||
).then(a => addSubscription(login, ...a.filter(a => a !== undefined).map(unwrap)));
|
||||
|
||||
const appData = getNewest(loginFeed.data.filter(a => a.kind === EventKind.AppData));
|
||||
const appData = getNewest(loginFeed.filter(a => a.kind === EventKind.AppData));
|
||||
if (appData) {
|
||||
publisher.decryptGeneric(appData.content, appData.pubkey).then(d => {
|
||||
setAppData(login, JSON.parse(d) as SnortAppData, appData.created_at * 1000);
|
||||
@ -200,20 +200,20 @@ export default function useLoginFeed() {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (loginFeed.data) {
|
||||
const mutedFeed = loginFeed.data.filter(a => a.kind === EventKind.MuteList);
|
||||
if (loginFeed) {
|
||||
const mutedFeed = loginFeed.filter(a => a.kind === EventKind.MuteList);
|
||||
handleMutedFeed(mutedFeed);
|
||||
|
||||
const pinnedFeed = loginFeed.data.filter(a => a.kind === EventKind.PinList);
|
||||
const pinnedFeed = loginFeed.filter(a => a.kind === EventKind.PinList);
|
||||
handlePinnedFeed(pinnedFeed);
|
||||
|
||||
const tagsFeed = loginFeed.data.filter(a => a.kind === EventKind.InterestsList);
|
||||
const tagsFeed = loginFeed.filter(a => a.kind === EventKind.InterestsList);
|
||||
handleTagFeed(tagsFeed);
|
||||
|
||||
const bookmarkFeed = loginFeed.data.filter(a => a.kind === EventKind.BookmarksList);
|
||||
const bookmarkFeed = loginFeed.filter(a => a.kind === EventKind.BookmarksList);
|
||||
handleBookmarkFeed(bookmarkFeed);
|
||||
|
||||
const publicChatsFeed = loginFeed.data.filter(a => a.kind === EventKind.PublicChatsList);
|
||||
const publicChatsFeed = loginFeed.filter(a => a.kind === EventKind.PublicChatsList);
|
||||
handlePublicChatsListFeed(publicChatsFeed);
|
||||
}
|
||||
}, [loginFeed]);
|
||||
|
@ -11,5 +11,5 @@ export default function useRelaysFeed(pubkey?: HexKey) {
|
||||
}, [pubkey]);
|
||||
|
||||
const relays = useRequestBuilder(sub);
|
||||
return parseRelayTags(relays.data?.[0].tags.filter(a => a[0] === "r") ?? []);
|
||||
return parseRelayTags(relays[0]?.tags.filter(a => a[0] === "r") ?? []);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ export function useStatusFeed(id?: string, leaveOpen = false) {
|
||||
|
||||
const status = useRequestBuilder(sub);
|
||||
|
||||
const statusFiltered = status.data?.filter(a => {
|
||||
const statusFiltered = status.filter(a => {
|
||||
const exp = Number(findTag(a, "expiration"));
|
||||
return isNaN(exp) || exp >= unixNow();
|
||||
});
|
||||
|
@ -33,8 +33,8 @@ export default function useThreadFeed(link: NostrLink) {
|
||||
const store = useRequestBuilder(sub);
|
||||
|
||||
useEffect(() => {
|
||||
if (store.data) {
|
||||
const links = store.data
|
||||
if (store) {
|
||||
const links = store
|
||||
.map(a => [
|
||||
NostrLink.fromEvent(a),
|
||||
...a.tags.filter(a => a[0] === "e" || a[0] === "a").map(v => NostrLink.fromTag(v)),
|
||||
@ -42,7 +42,7 @@ export default function useThreadFeed(link: NostrLink) {
|
||||
.flat();
|
||||
setAllEvents(links);
|
||||
|
||||
const current = store.data.find(a => link.matchesEvent(a));
|
||||
const current = store.find(a => link.matchesEvent(a));
|
||||
if (current) {
|
||||
const t = EventExt.extractThread(current);
|
||||
if (t) {
|
||||
@ -60,12 +60,12 @@ export default function useThreadFeed(link: NostrLink) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [store.data?.length]);
|
||||
}, [store?.length]);
|
||||
|
||||
const reactions = useReactions(`thread:${link.id.slice(0, 12)}:reactions`, [link, ...allEvents]);
|
||||
|
||||
return {
|
||||
thread: store.data ?? [],
|
||||
reactions: reactions.data ?? [],
|
||||
thread: store ?? [],
|
||||
reactions: reactions ?? [],
|
||||
};
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { unixNow } from "@snort/shared";
|
||||
import { EventKind, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useRequestBuilderAdvanced } from "@snort/system-react";
|
||||
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
||||
|
||||
import useLogin from "@/Hooks/useLogin";
|
||||
import useTimelineWindow from "@/Hooks/useTimelineWindow";
|
||||
@ -116,7 +116,16 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
return rb?.builder ?? null;
|
||||
}, [until, since, options.method, pref, createBuilder]);
|
||||
|
||||
const main = useRequestBuilder(sub);
|
||||
const mainQuery = useRequestBuilderAdvanced(sub);
|
||||
const main = useSyncExternalStore(
|
||||
h => {
|
||||
mainQuery?.on("event", h);
|
||||
return () => {
|
||||
mainQuery?.off("event", h);
|
||||
};
|
||||
},
|
||||
() => mainQuery?.snapshot,
|
||||
);
|
||||
|
||||
const subRealtime = useMemo(() => {
|
||||
const rb = createBuilder();
|
||||
@ -130,17 +139,25 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
return rb?.builder ?? null;
|
||||
}, [pref.autoShowLatest, createBuilder]);
|
||||
|
||||
const latest = useRequestBuilder(subRealtime);
|
||||
const latestQuery = useRequestBuilderAdvanced(subRealtime);
|
||||
const latest = useSyncExternalStore(
|
||||
h => {
|
||||
latestQuery?.on("event", h);
|
||||
return () => {
|
||||
latestQuery?.off("event", h);
|
||||
};
|
||||
},
|
||||
() => latestQuery?.snapshot,
|
||||
);
|
||||
|
||||
return {
|
||||
main: main.data,
|
||||
latest: latest.data,
|
||||
loading: main.loading(),
|
||||
main: main,
|
||||
latest: latest,
|
||||
loadMore: () => {
|
||||
if (main.data) {
|
||||
if (main) {
|
||||
console.debug("Timeline load more!");
|
||||
if (options.method === "LIMIT_UNTIL") {
|
||||
const oldest = main.data.reduce((acc, v) => (acc = v.created_at < acc ? v.created_at : acc), unixNow());
|
||||
const oldest = main.reduce((acc, v) => (acc = v.created_at < acc ? v.created_at : acc), unixNow());
|
||||
setUntil(oldest);
|
||||
} else {
|
||||
older();
|
||||
@ -148,9 +165,9 @@ export default function useTimelineFeed(subject: TimelineSubject, options: Timel
|
||||
}
|
||||
},
|
||||
showLatest: () => {
|
||||
if (latest.data) {
|
||||
main.add(latest.data);
|
||||
latest.clear();
|
||||
if (latest) {
|
||||
mainQuery?.feed.add(latest);
|
||||
latestQuery?.feed.clear();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -13,8 +13,8 @@ export default function useZapsFeed(link?: NostrLink) {
|
||||
const zapsFeed = useRequestBuilder(sub);
|
||||
|
||||
const zaps = useMemo(() => {
|
||||
if (zapsFeed.data) {
|
||||
const profileZaps = zapsFeed.data.map(a => parseZap(a)).filter(z => z.valid);
|
||||
if (zapsFeed) {
|
||||
const profileZaps = zapsFeed.map(a => parseZap(a)).filter(z => z.valid);
|
||||
profileZaps.sort((a, b) => b.amount - a.amount);
|
||||
return profileZaps;
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ export function useCommunityLeaders() {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
console.debug("CommunityLeaders", list);
|
||||
LeadersStore.setLeaders(list.map(a => a.id));
|
||||
}, [list]);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { EventKind, NostrLink, NoteCollection, RequestBuilder } from "@snort/system";
|
||||
import { EventKind, NostrLink, RequestBuilder } from "@snort/system";
|
||||
import { useEventsFeed, useRequestBuilder } from "@snort/system-react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
@ -12,18 +12,18 @@ export function useLinkList(id: string, fn: (rb: RequestBuilder) => void) {
|
||||
return rb;
|
||||
}, [id, fn]);
|
||||
|
||||
const listStore = useRequestBuilder(NoteCollection, sub);
|
||||
const listStore = useRequestBuilder(sub);
|
||||
return useMemo(() => {
|
||||
if (listStore.data && listStore.data.length > 0) {
|
||||
return listStore.data.map(e => NostrLink.fromTags(e.tags)).flat();
|
||||
if (listStore && listStore.length > 0) {
|
||||
return listStore.map(e => NostrLink.fromTags(e.tags)).flat();
|
||||
}
|
||||
return [];
|
||||
}, [listStore.data]);
|
||||
}, [listStore]);
|
||||
}
|
||||
|
||||
export function useLinkListEvents(id: string, fn: (rb: RequestBuilder) => void) {
|
||||
const links = useLinkList(id, fn);
|
||||
return useEventsFeed(`${id}:events`, links).data ?? [];
|
||||
return useEventsFeed(`${id}:events`, links);
|
||||
}
|
||||
|
||||
export function usePinList(pubkey: string | undefined) {
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { bech32ToHex } from "@snort/shared";
|
||||
import { EventKind, ReplaceableNoteStore, RequestBuilder } from "@snort/system";
|
||||
import { EventKind, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { getNewest } from "@/Utils";
|
||||
|
||||
// Snort backend publishes rates
|
||||
const SnortPubkey = "npub1sn0rtcjcf543gj4wsg7fa59s700d5ztys5ctj0g69g2x6802npjqhjjtws";
|
||||
|
||||
@ -20,12 +22,13 @@ export function useRates(symbol: string, leaveOpen = true) {
|
||||
return rb;
|
||||
}, [symbol]);
|
||||
|
||||
const data = useRequestBuilder(ReplaceableNoteStore, sub);
|
||||
const feed = useRequestBuilder(sub);
|
||||
const ev = getNewest(feed);
|
||||
|
||||
const tag = data?.data?.tags.find(a => a[0] === "d" && a[1] === symbol);
|
||||
const tag = ev?.tags.find(a => a[0] === "d" && a[1] === symbol);
|
||||
if (!tag) return undefined;
|
||||
return {
|
||||
time: data.data?.created_at,
|
||||
time: ev?.created_at,
|
||||
ask: Number(tag[2]),
|
||||
bid: Number(tag[3]),
|
||||
low: Number(tag[4]),
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { unwrap } from "@snort/shared";
|
||||
import { NoopStore, RequestBuilder, TaggedNostrEvent } from "@snort/system";
|
||||
import { RequestBuilder, TaggedNostrEvent } from "@snort/system";
|
||||
import { useEffect, useMemo } from "react";
|
||||
|
||||
import { RefreshFeedCache } from "@/Cache/RefreshFeedCache";
|
||||
@ -25,23 +25,14 @@ export function useRefreshFeedCache<T>(c: RefreshFeedCache<T>, leaveOpen = false
|
||||
|
||||
useEffect(() => {
|
||||
if (sub) {
|
||||
const q = system.Query(NoopStore, sub);
|
||||
let t: ReturnType<typeof setTimeout> | undefined;
|
||||
let tBuf: Array<TaggedNostrEvent> = [];
|
||||
q.on("event", evs => {
|
||||
if (!t) {
|
||||
tBuf = [...evs];
|
||||
t = setTimeout(() => {
|
||||
t = undefined;
|
||||
c.onEvent(tBuf, unwrap(login.publicKey), publisher);
|
||||
}, 100);
|
||||
} else {
|
||||
tBuf.push(...evs);
|
||||
}
|
||||
});
|
||||
const q = system.Query(sub);
|
||||
const handler = (evs: Array<TaggedNostrEvent>) => {
|
||||
c.onEvent(evs, unwrap(login.publicKey), publisher);
|
||||
};
|
||||
q.on("event", handler);
|
||||
q.uncancel();
|
||||
return () => {
|
||||
q.off("event");
|
||||
q.off("event", handler);
|
||||
q.cancel();
|
||||
};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { dedupe } from "@snort/shared";
|
||||
import { EventKind, NoteCollection, RequestBuilder } from "@snort/system";
|
||||
import { EventKind, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
import classNames from "classnames";
|
||||
import { useMemo } from "react";
|
||||
@ -59,8 +59,8 @@ export function HashTagHeader({ tag, events, className }: { tag: string; events?
|
||||
rb.withFilter().kinds([EventKind.InterestsList]).tag("t", [tag.toLowerCase()]);
|
||||
return rb;
|
||||
}, [tag]);
|
||||
const followsTag = useRequestBuilder(NoteCollection, sub);
|
||||
const pubkeys = dedupe((followsTag.data ?? []).map(a => a.pubkey));
|
||||
const followsTag = useRequestBuilder(sub);
|
||||
const pubkeys = dedupe(followsTag.map(a => a.pubkey));
|
||||
|
||||
return (
|
||||
<div className={classNames("flex flex-col", className)}>
|
||||
|
@ -103,10 +103,10 @@ function NoteTitle({ link }: { link: NostrLink }) {
|
||||
const ev = useEventFeed(link);
|
||||
|
||||
const values = useMemo(() => {
|
||||
return { name: <DisplayName pubkey={ev.data?.pubkey ?? ""} /> };
|
||||
}, [ev.data?.pubkey]);
|
||||
return { name: <DisplayName pubkey={ev?.pubkey ?? ""} /> };
|
||||
}, [ev?.pubkey]);
|
||||
|
||||
if (!ev.data?.pubkey) {
|
||||
if (!ev?.pubkey) {
|
||||
return <FormattedMessage defaultMessage="Note" id="qMePPG" />;
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@ import ProfilePreview from "@/Components/User/ProfilePreview";
|
||||
|
||||
export default function Nip28ChatProfile({ id, onClick }: { id: string; onClick: (id: string) => void }) {
|
||||
const channel = useEventFeed(new NostrLink(CONFIG.eventLinkPrefix, id, 40));
|
||||
if (channel?.data) {
|
||||
const meta = JSON.parse(channel.data.content) as UserMetadata;
|
||||
if (channel) {
|
||||
const meta = JSON.parse(channel.content) as UserMetadata;
|
||||
return (
|
||||
<ProfilePreview
|
||||
pubkey=""
|
||||
|
@ -252,7 +252,7 @@ function NotificationGroup({ evs, onClick }: { evs: Array<TaggedNostrEvent>; onC
|
||||
}
|
||||
|
||||
function NotificationContext({ link, onClick }: { link: NostrLink; onClick: () => void }) {
|
||||
const { data: ev } = useEventFeed(link);
|
||||
const ev = useEventFeed(link);
|
||||
if (link.type === NostrPrefix.PublicKey) {
|
||||
return <ProfilePreview pubkey={link.id} actions={<></>} />;
|
||||
}
|
||||
|
@ -415,7 +415,6 @@ const PreferencesPage = () => {
|
||||
value={perf.reactionEmoji}
|
||||
onChange={e => {
|
||||
const split = e.target.value.match(/[\p{L}\S]{1}/u);
|
||||
console.debug(e.target.value, split);
|
||||
updatePreferences(id, {
|
||||
...perf,
|
||||
reactionEmoji: split?.[0] ?? "",
|
||||
|
@ -19,7 +19,6 @@ export default function AlbyOAuth() {
|
||||
async function setupWallet(token: string) {
|
||||
try {
|
||||
const auth = await alby.getToken(token);
|
||||
console.debug(auth);
|
||||
const connection = new AlbyWallet(auth, () => {});
|
||||
const info = await connection.getInfo();
|
||||
|
||||
|
@ -221,7 +221,6 @@ export class MultiAccountStore extends ExternalStore<LoginSession> {
|
||||
updateSession(s: LoginSession) {
|
||||
if (this.#accounts.has(s.id)) {
|
||||
this.#accounts.set(s.id, s);
|
||||
console.debug("SET SESSION", s);
|
||||
this.#save();
|
||||
}
|
||||
}
|
||||
|
@ -78,8 +78,7 @@ export async function subscribeToNotifications(publisher: EventPublisher) {
|
||||
if ("Notification" in window) {
|
||||
try {
|
||||
if (Notification.permission !== "granted") {
|
||||
const res = await Notification.requestPermission();
|
||||
console.debug(res);
|
||||
await Notification.requestPermission();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ExternalStore, LNURL, unixNow } from "@snort/shared";
|
||||
import debug from "debug";
|
||||
|
||||
import { UserCache } from "@/Cache";
|
||||
import { Toastore } from "@/Components/Toaster/Toaster";
|
||||
@ -21,6 +22,7 @@ export interface ZapPoolRecipient {
|
||||
}
|
||||
|
||||
class ZapPool extends ExternalStore<Array<ZapPoolRecipient>> {
|
||||
#log = debug("ZapPool");
|
||||
#store = new Map<string, ZapPoolRecipient>();
|
||||
#isPayoutInProgress = false;
|
||||
#lastPayout = 0;
|
||||
@ -50,7 +52,7 @@ class ZapPool extends ExternalStore<Array<ZapPoolRecipient>> {
|
||||
const invoice = await svc.getInvoice(amtSend, `SnortZapPool: ${x.split}%`);
|
||||
if (invoice.pr) {
|
||||
const result = await wallet.payInvoice(invoice.pr);
|
||||
console.debug("ZPC", invoice, result);
|
||||
this.#log("%o %o", invoice, result);
|
||||
if (result.state === WalletInvoiceState.Paid) {
|
||||
x.sum -= amtSend;
|
||||
Toastore.push({
|
||||
|
@ -55,7 +55,6 @@ export async function openFile(): Promise<File | undefined> {
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
if (!lock) {
|
||||
console.debug("FOCUS WINDOW UPLOAD");
|
||||
resolve(undefined);
|
||||
}
|
||||
}, 300);
|
||||
|
Reference in New Issue
Block a user