Skip to content

Commit

Permalink
Show recent badge awards on badges page
Browse files Browse the repository at this point in the history
  • Loading branch information
hzrd149 committed Oct 9, 2023
1 parent 21a1a8a commit cdfdc71
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/mighty-pans-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nostrudel": minor
---

Show recent badge awards on badges page
2 changes: 1 addition & 1 deletion src/hooks/use-user-profile-badges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function useUserProfileBadges(pubkey: string, additionalRelays: s
const badge = badges.find((e) => getEventCoordinate(e) === p.badgeCord);
const award = awardEvents.find((e) => e.id === p.awardEventId);

if (badge && award) final.push({ badge, award });
if (badge && award && badge.pubkey === award.pubkey) final.push({ badge, award });
}

return final;
Expand Down
15 changes: 10 additions & 5 deletions src/views/badges/badge-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import { NostrEvent } from "../../types/nostr-event";
import { getEventCoordinate } from "../../helpers/nostr/events";
import { UserAvatarLink } from "../../components/user-avatar-link";
import { UserLink } from "../../components/user-link";
import { ErrorBoundary } from "../../components/error-boundary";
import Timestamp from "../../components/timestamp";
import VerticalPageLayout from "../../components/vertical-page-layout";

Expand Down Expand Up @@ -70,7 +69,7 @@ function BadgeDetailsPage({ badge }: { badge: NostrEvent }) {

<Flex direction={{ base: "column", lg: "row" }} gap="2">
{image && <Image src={image.src} maxW="3in" mr="2" mb="2" mx={{ base: "auto", lg: "initial" }} />}
<Flex direction="column" gap="2">
<Flex direction="column">
<Heading size="md">{getBadgeName(badge)}</Heading>
<Text>
Created by: <UserAvatarLink pubkey={badge.pubkey} size="xs" />{" "}
Expand All @@ -79,15 +78,21 @@ function BadgeDetailsPage({ badge }: { badge: NostrEvent }) {
<Text>
Created: <Timestamp timestamp={badge.created_at} />
</Text>
{description && <Text pb="2">{description}</Text>}
{description && (
<>
<Heading size="md" mt="2">
Description
</Heading>
<Text pb="2">{description}</Text>
</>
)}
</Flex>
</Flex>

{awards.length > 0 && (
<>
<IntersectionObserverProvider callback={callback}>
<Heading size="md">Awarded to</Heading>
<Divider />
<Heading size="lg">Awarded to</Heading>
<SimpleGrid columns={{ base: 1, lg: 2, xl: 3 }} spacing="2">
{awards.map((award) => (
<>
Expand Down
102 changes: 97 additions & 5 deletions src/views/badges/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,90 @@
import { Button, Flex, Image, Link, Spacer } from "@chakra-ui/react";
import { useRef } from "react";
import {
AvatarGroup,
Button,
Card,
Flex,
Heading,
Image,
Link,
LinkBox,
LinkOverlay,
Spacer,
Text,
} from "@chakra-ui/react";
import { Navigate, Link as RouterLink } from "react-router-dom";
import { Kind } from "nostr-tools";

import { useCurrentAccount } from "../../hooks/use-current-account";
import { ExternalLinkIcon } from "../../components/icons";
import VerticalPageLayout from "../../components/vertical-page-layout";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import PeopleListProvider, { usePeopleListContext } from "../../providers/people-list-provider";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import { useReadRelayUrls } from "../../hooks/use-client-relays";
import useSubject from "../../hooks/use-subject";
import { NostrEvent, isPTag } from "../../types/nostr-event";
import { UserLink } from "../../components/user-link";
import { UserAvatar } from "../../components/user-avatar";
import { getBadgeAwardBadge, getBadgeImage, getBadgeName } from "../../helpers/nostr/badges";
import useReplaceableEvent from "../../hooks/use-replaceable-event";
import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../../providers/intersection-observer";
import { getEventUID } from "../../helpers/nostr/events";
import { getSharableEventAddress } from "../../helpers/nip19";
import { UserAvatarLink } from "../../components/user-avatar-link";
import Timestamp from "../../components/timestamp";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";

function BadgeAwardCard({ award }: { award: NostrEvent }) {
const badge = useReplaceableEvent(getBadgeAwardBadge(award));

// if there is a parent intersection observer, register this card
const ref = useRef<HTMLDivElement | null>(null);
useRegisterIntersectionEntity(ref, badge && getEventUID(badge));

if (!badge) return null;

const naddr = getSharableEventAddress(badge);
return (
<Card p="2" variant="outline" gap="2" flexDirection={["column", null, "row"]} ref={ref}>
<Flex as={LinkBox} direction="column" overflow="hidden" gap="2" w="40" mx="auto">
<Image aspectRatio={1} src={getBadgeImage(badge)?.src ?? ""} w="40" />
<Heading size="sm" isTruncated>
<LinkOverlay as={RouterLink} to={`/badges/${naddr}`}>
{getBadgeName(badge)}
</LinkOverlay>
</Heading>
</Flex>
<Flex gap="2" direction="column" flex={1}>
<Flex gap="2" alignItems="center">
<UserAvatar pubkey={award.pubkey} size="sm" />
<UserLink pubkey={award.pubkey} fontWeight="bold" />
<Text>Awarded:</Text>
<Spacer />
<Timestamp timestamp={award.created_at} />
</Flex>
<Flex gap="2" wrap="wrap">
{award.tags.filter(isPTag).map((t) => (
<Flex key={t[1]} gap="2" alignItems="center">
<UserAvatarLink pubkey={t[1]} size="sm" />
<UserLink pubkey={t[1]} fontWeight="bold" />
</Flex>
))}
</Flex>
</Flex>
</Card>
);
}

function BadgesPage() {
const account = useCurrentAccount()!;
const { filter, listId } = usePeopleListContext();
const readRelays = useReadRelayUrls();
const timeline = useTimelineLoader(`${listId}-lists`, readRelays, {
...filter,
kinds: [Kind.BadgeAward],
});

const awards = useSubject(timeline.timeline);
const callback = useTimelineCurserIntersectionCallback(timeline);

return (
<VerticalPageLayout>
Expand All @@ -25,11 +103,25 @@ function BadgesPage() {
Badges
</Button>
</Flex>
<Flex gap="2" alignItems="center">
<Heading size="lg">Recent awards</Heading>
<PeopleListSelection />
</Flex>
<IntersectionObserverProvider callback={callback}>
{awards.map((award) => (
<BadgeAwardCard key={award.id} award={award} />
))}
</IntersectionObserverProvider>
</VerticalPageLayout>
);
}

export default function BadgesView() {
const account = useCurrentAccount();
return account ? <BadgesPage /> : <Navigate to="/lists/browse" />;
// const account = useCurrentAccount();
// return account ? <BadgesPage /> : <Navigate to="/lists/browse" />;
return (
<PeopleListProvider initList="global">
<BadgesPage />
</PeopleListProvider>
);
}
1 change: 1 addition & 0 deletions src/views/user/about/user-profile-badges.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function Badge({ pubkey, badge, award }: { pubkey: string; badge: NostrEvent; aw
<Image w="14" h="14" src={getBadgeImage(badge)?.src ?? ""} />
</Tooltip>
</Link>

<Modal isOpen={modal.isOpen} onClose={modal.onClose}>
<ModalOverlay />
<ModalContent>
Expand Down

0 comments on commit cdfdc71

Please sign in to comment.