feat: profile page
This commit is contained in:
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
67
src/hooks/profile.ts
Normal 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
25
src/hooks/top-zappers.ts
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user