feat: badges
- render badges in cards - render mentioned badges in chat - render host badge awards in chat - render accepted badges next to username
This commit is contained in:
93
src/hooks/badges.ts
Normal file
93
src/hooks/badges.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { EventKind, NoteCollection, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
import { unixNow } from "@snort/shared";
|
||||
|
||||
import { findTag, toAddress, getTagValues } from "utils";
|
||||
import { WEEK } from "const";
|
||||
import { System } from "index";
|
||||
import type { Badge } from "types";
|
||||
|
||||
export function useBadges(pubkey: string, leaveOpen = true): Array<Badge> {
|
||||
const since = useMemo(() => unixNow() - WEEK, [pubkey]);
|
||||
const rb = useMemo(() => {
|
||||
const rb = new RequestBuilder(`badges:${pubkey.slice(0, 12)}`);
|
||||
rb.withOptions({ leaveOpen });
|
||||
rb.withFilter()
|
||||
.authors([pubkey])
|
||||
.kinds([EventKind.Badge, EventKind.BadgeAward]);
|
||||
return rb;
|
||||
}, [pubkey]);
|
||||
|
||||
const { data: badgeEvents } = useRequestBuilder<NoteCollection>(
|
||||
System,
|
||||
NoteCollection,
|
||||
rb,
|
||||
);
|
||||
|
||||
const rawBadges = useMemo(() => {
|
||||
if (badgeEvents) {
|
||||
return badgeEvents
|
||||
.filter((e) => e.kind === EventKind.Badge)
|
||||
.sort((a, b) => b.created_at - a.created_at);
|
||||
}
|
||||
return [];
|
||||
}, [badgeEvents]);
|
||||
const badgeAwards = useMemo(() => {
|
||||
if (badgeEvents) {
|
||||
return badgeEvents.filter((e) => e.kind === EventKind.BadgeAward);
|
||||
}
|
||||
return [];
|
||||
}, [badgeEvents]);
|
||||
|
||||
const acceptedSub = useMemo(() => {
|
||||
if (rawBadges.length === 0) return null;
|
||||
const rb = new RequestBuilder(
|
||||
`accepted-badges:${pubkey.slice(0, 12)}:${rawBadges.length}`,
|
||||
);
|
||||
rb.withFilter()
|
||||
.kinds([EventKind.ProfileBadges])
|
||||
.tag("d", ["profile_badges"])
|
||||
.tag("a", rawBadges.map(toAddress));
|
||||
return rb;
|
||||
}, [rawBadges]);
|
||||
|
||||
const acceptedStream = useRequestBuilder<NoteCollection>(
|
||||
System,
|
||||
NoteCollection,
|
||||
acceptedSub,
|
||||
);
|
||||
const acceptedEvents = acceptedStream.data ?? [];
|
||||
|
||||
const badges = useMemo(() => {
|
||||
return rawBadges.map((e) => {
|
||||
const name = findTag(e, "d");
|
||||
const address = toAddress(e);
|
||||
const awardEvents = badgeAwards.filter(
|
||||
(b) => findTag(b, "a") === address,
|
||||
);
|
||||
const awardees = new Set(
|
||||
awardEvents.map((e) => getTagValues(e.tags, "p")).flat(),
|
||||
);
|
||||
const accepted = new Set(
|
||||
acceptedEvents
|
||||
.filter((pb) => awardees.has(pb.pubkey))
|
||||
.filter((pb) =>
|
||||
pb.tags.find((t) => t.at(0) === "a" && t.at(1) === address),
|
||||
)
|
||||
.map((pb) => pb.pubkey),
|
||||
);
|
||||
const thumb = findTag(e, "thumb");
|
||||
const image = findTag(e, "image");
|
||||
return { name, thumb, image, awardees, accepted };
|
||||
});
|
||||
return [];
|
||||
}, [rawBadges]);
|
||||
|
||||
const awards = useMemo(() => {
|
||||
return badgeAwards.filter((e) => e.created_at > since);
|
||||
}, [badgeAwards]);
|
||||
|
||||
return { badges, awards };
|
||||
}
|
Reference in New Issue
Block a user