- render badges in cards - render mentioned badges in chat - render host badge awards in chat - render accepted badges next to username
94 lines
2.7 KiB
TypeScript
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 };
|
|
}
|