Files
zap.stream/src/hooks/badges.ts
verbiricha 7a030c9e53 feat: badges
- render badges in cards
- render mentioned badges in chat
- render host badge awards in chat
- render accepted badges next to username
2023-08-01 08:14:33 +02:00

94 lines
2.7 KiB
TypeScript

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 };
}