feat: profile page

This commit is contained in:
Alejandro Gomez
2023-06-30 13:15:31 +02:00
parent 9a08dd6768
commit 111eea3d14
24 changed files with 745 additions and 152 deletions

View File

@ -1,7 +1,13 @@
import { NostrLink, RequestBuilder, EventKind, FlatNoteStore } from "@snort/system";
import {
NostrLink,
RequestBuilder,
EventKind,
FlatNoteStore,
} from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { System } from "index";
import { useMemo } from "react";
import { LIVE_STREAM_CHAT } from "const";
export function useLiveChatFeed(link: NostrLink) {
const sub = useMemo(() => {
@ -10,11 +16,11 @@ export function useLiveChatFeed(link: NostrLink) {
leaveOpen: true,
});
rb.withFilter()
.kinds([EventKind.ZapReceipt, 1311 as EventKind])
.kinds([EventKind.ZapReceipt, LIVE_STREAM_CHAT])
.tag("a", [`${link.kind}:${link.author}:${link.id}`])
.limit(100);
return rb;
}, [link]);
return useRequestBuilder<FlatNoteStore>(System, FlatNoteStore, sub);
}
}

View File

@ -2,5 +2,8 @@ import { Login } from "index";
import { useSyncExternalStore } from "react";
export function useLogin() {
return useSyncExternalStore(c => Login.hook(c), () => Login.snapshot());
}
return useSyncExternalStore(
(c) => Login.hook(c),
() => Login.snapshot()
);
}

67
src/hooks/profile.ts Normal file
View File

@ -0,0 +1,67 @@
import { useMemo } from "react";
import {
RequestBuilder,
ReplaceableNoteStore,
FlatNoteStore,
NostrLink,
EventKind,
parseZap,
} from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { LIVE_STREAM } from "const";
import { findTag } from "utils";
import { System } from "index";
export function useProfile(link: NostrLink, leaveOpen = false) {
const sub = useMemo(() => {
const b = new RequestBuilder(`profile:${link.id.slice(0, 12)}`);
b.withOptions({
leaveOpen,
})
.withFilter()
.kinds([LIVE_STREAM])
.authors([link.id]);
return b;
}, [link, leaveOpen]);
const { data: streamsData } = useRequestBuilder<ReplaceableNoteStore>(
System,
ReplaceableNoteStore,
sub
);
const streams = Array.isArray(streamsData)
? streamsData
: streamsData
? [streamsData]
: [];
const addresses = useMemo(() => {
return streams.map((e) => `${e.kind}:${e.pubkey}:${findTag(e, "d")}`);
}, [streamsData]);
const zapsSub = useMemo(() => {
const b = new RequestBuilder(`profile-zaps:${link.id.slice(0, 12)}`);
b.withOptions({
leaveOpen,
})
.withFilter()
.kinds([EventKind.ZapReceipt])
.tag("a", addresses);
return b;
}, [link, addresses, leaveOpen]);
const { data: zapsData } = useRequestBuilder<FlatNoteStore>(
System,
FlatNoteStore,
zapsSub
);
const zaps = (zapsData ?? [])
.map((ev) => parseZap(ev, System.ProfileLoader.Cache))
.filter((z) => z && z.valid);
return {
streams,
zaps,
};
}

25
src/hooks/top-zappers.ts Normal file
View File

@ -0,0 +1,25 @@
import { useMemo } from "react";
import { ParsedZap } from "@snort/system";
function totalZapped(pubkey: string, zaps: ParsedZap[]) {
return zaps
.filter((z) => (z.anonZap ? pubkey === "anon" : z.sender === pubkey))
.reduce((acc, z) => acc + z.amount, 0);
}
export default function useTopZappers(zaps: ParsedZap[]) {
const zappers = zaps
.map((z) => (z.anonZap ? "anon" : z.sender))
.map((p) => p as string);
const sorted = useMemo(() => {
const pubkeys = [...new Set([...zappers])];
const result = pubkeys.map((pubkey) => {
return { pubkey, total: totalZapped(pubkey, zaps) };
});
result.sort((a, b) => b.total - a.total);
return result;
}, [zaps, zappers]);
return sorted;
}