Show multiple pubkeys on badge award event

This commit is contained in:
hzrd149
2023-09-21 08:14:06 -05:00
parent c3de4371c8
commit 054e3f2c57
4 changed files with 64 additions and 51 deletions

View File

@@ -0,0 +1,5 @@
---
"nostrudel": patch
---
Show multiple pubkeys on badge award event

View File

@@ -1,4 +1,5 @@
import { NostrEvent, isATag, isPTag } from "../../types/nostr-event"; import { NostrEvent, isATag, isPTag } from "../../types/nostr-event";
import { getPubkeysFromList } from "./lists";
export const PROFILE_BADGES_IDENTIFIER = "profile_badges"; export const PROFILE_BADGES_IDENTIFIER = "profile_badges";
@@ -30,9 +31,7 @@ export function getBadgeThumbnails(event: NostrEvent) {
} }
export function getBadgeAwardPubkey(event: NostrEvent) { export function getBadgeAwardPubkey(event: NostrEvent) {
const pubkey = event.tags.find(isPTag)?.[1]; return getPubkeysFromList(event);
if (!pubkey) throw new Error("Missing pubkey");
return pubkey;
} }
export function getBadgeAwardBadge(event: NostrEvent) { export function getBadgeAwardBadge(event: NostrEvent) {
const badgeCord = event.tags.find(isATag)?.[1]; const badgeCord = event.tags.find(isATag)?.[1];

View File

@@ -6,7 +6,7 @@ import { ArrowLeftSIcon } from "../../components/icons";
import { useDeleteEventContext } from "../../providers/delete-event-provider"; import { useDeleteEventContext } from "../../providers/delete-event-provider";
import useReplaceableEvent from "../../hooks/use-replaceable-event"; import useReplaceableEvent from "../../hooks/use-replaceable-event";
import { EventRelays } from "../../components/note/note-relays"; import { EventRelays } from "../../components/note/note-relays";
import { getBadgeDescription, getBadgeImage, getBadgeName } from "../../helpers/nostr/badges"; import { getBadgeAwardPubkey, getBadgeDescription, getBadgeImage, getBadgeName } from "../../helpers/nostr/badges";
import BadgeMenu from "./components/badge-menu"; import BadgeMenu from "./components/badge-menu";
import BadgeAwardCard from "./components/award-card"; import BadgeAwardCard from "./components/award-card";
import useTimelineLoader from "../../hooks/use-timeline-loader"; import useTimelineLoader from "../../hooks/use-timeline-loader";
@@ -45,60 +45,62 @@ function BadgeDetailsPage({ badge }: { badge: NostrEvent }) {
const isAuthor = account?.pubkey === badge.pubkey; const isAuthor = account?.pubkey === badge.pubkey;
return ( return (
<IntersectionObserverProvider callback={callback}> <VerticalPageLayout>
<VerticalPageLayout> <Flex gap="2" alignItems="center" wrap="wrap">
<Flex gap="2" alignItems="center" wrap="wrap"> <Button onClick={() => navigate(-1)} leftIcon={<ArrowLeftSIcon />}>
<Button onClick={() => navigate(-1)} leftIcon={<ArrowLeftSIcon />}> Back
Back </Button>
<UserAvatarLink pubkey={badge.pubkey} size="sm" />
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
<Text>|</Text>
<Heading size="md">{getBadgeName(badge)}</Heading>
<Spacer />
<EventRelays event={badge} />
{isAuthor && (
<Button colorScheme="red" onClick={() => deleteEvent(badge).then(() => navigate("/lists"))}>
Delete
</Button> </Button>
)}
<BadgeMenu aria-label="More options" badge={badge} />
</Flex>
<UserAvatarLink pubkey={badge.pubkey} size="sm" /> <Flex direction={{ base: "column", lg: "row" }} gap="2">
<UserLink fontWeight="bold" pubkey={badge.pubkey} /> {image && <Image src={image.src} maxW="3in" mr="2" mb="2" mx={{ base: "auto", lg: "initial" }} />}
<Text>|</Text> <Flex direction="column" gap="2">
<Heading size="md">{getBadgeName(badge)}</Heading> <Heading size="md">{getBadgeName(badge)}</Heading>
<Text>
<Spacer /> Created by: <UserAvatarLink pubkey={badge.pubkey} size="xs" />{" "}
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
<EventRelays event={badge} /> </Text>
<Text>
{isAuthor && ( Last Updated: <Timestamp timestamp={badge.created_at} />
<Button colorScheme="red" onClick={() => deleteEvent(badge).then(() => navigate("/lists"))}> </Text>
Delete {description && <Text pb="2">{description}</Text>}
</Button>
)}
<BadgeMenu aria-label="More options" badge={badge} />
</Flex> </Flex>
</Flex>
<Flex direction={{ base: "column", lg: "row" }} gap="2"> {awards.length > 0 && (
{image && <Image src={image.src} maxW="3in" mr="2" mb="2" mx={{ base: "auto", lg: "initial" }} />} <>
<Flex direction="column" gap="2"> <IntersectionObserverProvider callback={callback}>
<Heading size="md">{getBadgeName(badge)}</Heading>
<Text>
Created by: <UserAvatarLink pubkey={badge.pubkey} size="xs" />{" "}
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
</Text>
<Text>
Last Updated: <Timestamp timestamp={badge.created_at} />
</Text>
{description && <Text pb="2">{description}</Text>}
</Flex>
</Flex>
{awards.length > 0 && (
<>
<Heading size="md">Awarded to</Heading> <Heading size="md">Awarded to</Heading>
<Divider /> <Divider />
<SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2"> <SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2">
{awards.map((award) => ( {awards.map((award) => (
<ErrorBoundary> <>
<BadgeAwardCard award={award} /> {getBadgeAwardPubkey(award).map(({ pubkey }) => (
</ErrorBoundary> <BadgeAwardCard award={award} pubkey={pubkey} />
))}
</>
))} ))}
</SimpleGrid> </SimpleGrid>
</> </IntersectionObserverProvider>
)} </>
</VerticalPageLayout> )}
</IntersectionObserverProvider> </VerticalPageLayout>
); );
} }

View File

@@ -1,16 +1,23 @@
import { useRef } from "react";
import { Card, CardBody, CardProps, Flex, Heading } from "@chakra-ui/react"; import { Card, CardBody, CardProps, Flex, Heading } from "@chakra-ui/react";
import { UserAvatar } from "../../../components/user-avatar"; import { UserAvatar } from "../../../components/user-avatar";
import { UserDnsIdentityIcon } from "../../../components/user-dns-identity-icon"; import { UserDnsIdentityIcon } from "../../../components/user-dns-identity-icon";
import { NostrEvent } from "../../../types/nostr-event"; import { NostrEvent } from "../../../types/nostr-event";
import { getBadgeAwardPubkey } from "../../../helpers/nostr/badges";
import { UserLink } from "../../../components/user-link"; import { UserLink } from "../../../components/user-link";
import { useRegisterIntersectionEntity } from "../../../providers/intersection-observer";
import { getEventUID } from "../../../helpers/nostr/events";
export default function BadgeAwardCard({ award, ...props }: Omit<CardProps, "children"> & { award: NostrEvent }) { export default function BadgeAwardCard({
const pubkey = getBadgeAwardPubkey(award); pubkey,
award,
...props
}: Omit<CardProps, "children"> & { award: NostrEvent; pubkey: string }) {
const ref = useRef<HTMLDivElement | null>(null);
useRegisterIntersectionEntity(ref, getEventUID(award));
return ( return (
<Card {...props}> <Card {...props} ref={ref}>
<CardBody p="2" display="flex" alignItems="center" overflow="hidden" gap="2"> <CardBody p="2" display="flex" alignItems="center" overflow="hidden" gap="2">
<UserAvatar pubkey={pubkey} /> <UserAvatar pubkey={pubkey} />
<Flex direction="column" flex={1} overflow="hidden"> <Flex direction="column" flex={1} overflow="hidden">