From 83a34bec65651341c4b40992e28f32ae7526ac92 Mon Sep 17 00:00:00 2001 From: Dominik Stumpf <122315398+dominik-stumpf@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:13:46 +0200 Subject: [PATCH] Add contribution collection to `/profile`, improve card (#1454) * feat: add collection and checkmark * chore: add extended collection * fix: add line clamp to edit contribution select * feat: add point image to contribution * fix: show cards if no point is received * feat: add points text and leaderboard ranking * chore: copy static folder to public * chore: render contribution card if no collection is present * feat: add nft to collection * feat: add pins * refactor: cleanup collection * fix: remove checkmark, allow longer label * feat: add tooltip to collection * fix: prevent wrap on points text * chore: remove NFT from tooltip * chore: remove src/static dir duplication * chore: polish borders --- package-lock.json | 8 +- package.json | 2 +- .../(marketing)/profile/[username]/page.tsx | 23 +++++ .../_components/CardWithGuildLabel.tsx | 6 +- .../profile/_components/ContributionCard.tsx | 24 ++++- .../_components/ContributionCardView.tsx | 31 +++++-- .../_components/ContributionCollection.tsx | 90 +++++++++++++++++++ src/v2/components/ui/AvatarGroup.tsx | 2 +- 8 files changed, 163 insertions(+), 23 deletions(-) create mode 100644 src/app/(marketing)/profile/_components/ContributionCollection.tsx diff --git a/package-lock.json b/package-lock.json index 410b9961cd..81a74a5162 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@emotion/styled": "^11.11.0", "@fuels/connectors": "^0.5.0", "@fuels/react": "^0.20.0", - "@guildxyz/types": "^1.10.2", + "@guildxyz/types": "^1.10.8", "@hcaptcha/react-hcaptcha": "^1.4.4", "@hookform/resolvers": "^3.3.4", "@lexical/code": "^0.12.0", @@ -5393,9 +5393,9 @@ } }, "node_modules/@guildxyz/types": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/@guildxyz/types/-/types-1.10.2.tgz", - "integrity": "sha512-zJXu2028kT79q6IZ2Z904EfvtPN0Asw2d4sFYdoQz0tTQt9k/RNo9EXhtqXOFeUMaqc/kZzbhJzZSSXihhVo0g==", + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/@guildxyz/types/-/types-1.10.8.tgz", + "integrity": "sha512-oTzLxdFQ3UFXHgsx/xjtIMgb5k9maCsdVlvKZjw/nqY3lYU9UK3DmnPEiiahCVple3zrDE41IgqZqR9McH520A==", "dependencies": { "zod": "^3.22.4" } diff --git a/package.json b/package.json index 6b0f0f36c7..626231b0ef 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "@emotion/styled": "^11.11.0", "@fuels/connectors": "^0.5.0", "@fuels/react": "^0.20.0", - "@guildxyz/types": "^1.10.2", + "@guildxyz/types": "^1.10.8", "@hcaptcha/react-hcaptcha": "^1.4.4", "@hookform/resolvers": "^3.3.4", "@lexical/code": "^0.12.0", diff --git a/src/app/(marketing)/profile/[username]/page.tsx b/src/app/(marketing)/profile/[username]/page.tsx index 9f004cc5e6..7cefabbd2d 100644 --- a/src/app/(marketing)/profile/[username]/page.tsx +++ b/src/app/(marketing)/profile/[username]/page.tsx @@ -110,6 +110,25 @@ const fetchPublicProfileData = async ({ }, } ) + const collectionRequests = contributions.map( + ({ id }) => + new URL(`v2/profiles/${username}/contributions/${id}/collection`, api) + ) + let collections: Schemas["ContributionCollection"][] | undefined + try { + collections = await Promise.all( + collectionRequests.map((req) => + ssrFetcher(req, { + next: { + tags: ["collections"], + revalidate: 3600, + }, + }) + ) + ) + } catch (e) { + console.error(e) + } const roleRequests = contributions.map( ({ roleId, guildId }) => new URL(`v2/guilds/${guildId}/roles/${roleId}`, api) ) @@ -134,6 +153,9 @@ const fetchPublicProfileData = async ({ }) ) ) + const collectionsZipped = collections + ? collectionRequests.map(({ pathname }, i) => [pathname, collections[i]]) + : [] const guildsZipped = guildRequests.map(({ pathname }, i) => [pathname, guilds[i]]) const rolesZipped = roleRequests.map(({ pathname }, i) => [pathname, roles[i]]) return { @@ -145,6 +167,7 @@ const fetchPublicProfileData = async ({ [farcasterProfilesRequest.pathname, farcasterProfiles], [neynarRequest?.href, fcFollowers], [referredUsersRequest.pathname, referredUsers], + ...collectionsZipped, ...guildsZipped, ...rolesZipped, ].filter(([key, value]) => key && value) diff --git a/src/app/(marketing)/profile/_components/CardWithGuildLabel.tsx b/src/app/(marketing)/profile/_components/CardWithGuildLabel.tsx index 9d25be61dd..626eb7664a 100644 --- a/src/app/(marketing)/profile/_components/CardWithGuildLabel.tsx +++ b/src/app/(marketing)/profile/_components/CardWithGuildLabel.tsx @@ -1,4 +1,3 @@ -import { CheckMark } from "@/components/CheckMark" import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/Avatar" import { Card } from "@/components/ui/Card" import { cn } from "@/lib/utils" @@ -22,7 +21,7 @@ export const CardWithGuildLabel = ({ style={{ background: guild.theme.color }} title={guild.name} > -
+
{guild.name}
-
diff --git a/src/app/(marketing)/profile/_components/ContributionCard.tsx b/src/app/(marketing)/profile/_components/ContributionCard.tsx index 08347d0bde..8288685002 100644 --- a/src/app/(marketing)/profile/_components/ContributionCard.tsx +++ b/src/app/(marketing)/profile/_components/ContributionCard.tsx @@ -1,7 +1,7 @@ -"use client" - +import { Skeleton } from "@/components/ui/Skeleton" import { Guild, Role, Schemas } from "@guildxyz/types" import useSWRImmutable from "swr/immutable" +import { useProfile } from "../_hooks/useProfile" import { ContributionCardView } from "./ContributionCardView" export const ContributionCard = ({ @@ -11,6 +11,22 @@ export const ContributionCard = ({ const role = useSWRImmutable( `/v2/guilds/${contribution.guildId}/roles/${contribution.roleId}` ) - if (!role.data || !guild.data) return - return + const profile = useProfile() + const collection = useSWRImmutable( + profile.data + ? `/v2/profiles/${profile.data.username}/contributions/${contribution.id}/collection` + : null + ) + + if (!role.data || !guild.data) { + return + } + + return ( + + ) } diff --git a/src/app/(marketing)/profile/_components/ContributionCardView.tsx b/src/app/(marketing)/profile/_components/ContributionCardView.tsx index 51c1b6a29c..7a44447f9e 100644 --- a/src/app/(marketing)/profile/_components/ContributionCardView.tsx +++ b/src/app/(marketing)/profile/_components/ContributionCardView.tsx @@ -1,17 +1,25 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/Avatar" -import { AvatarGroup } from "@/components/ui/AvatarGroup" import { Separator } from "@/components/ui/Separator" -import { Guild, Role } from "@guildxyz/types" +import { Guild, Role, Schemas } from "@guildxyz/types" import { Users } from "@phosphor-icons/react/dist/ssr" import { CardWithGuildLabel } from "./CardWithGuildLabel" +import { ContributionCollection } from "./ContributionCollection" export const ContributionCardView = ({ guild, role, -}: { guild: Guild; role: Role }) => { + collection, +}: { + guild: Guild + role: Role + collection?: Schemas["ContributionCollection"] +}) => { const roleAcquirementPercentage = Number( ((role.memberCount / guild.memberCount || 0) * 100).toFixed(1) ) + const collections = [collection?.NFTs, collection?.pins, collection?.points] + .filter(Boolean) + .flat() return (
@@ -34,13 +42,18 @@ export const ContributionCardView = ({

-
- -
- COLLECTION: + {collection && !!collections.length && ( +
+ +
+ COLLECTION: +
+ +
+ +
- -
+ )}
) diff --git a/src/app/(marketing)/profile/_components/ContributionCollection.tsx b/src/app/(marketing)/profile/_components/ContributionCollection.tsx new file mode 100644 index 0000000000..83295fed9d --- /dev/null +++ b/src/app/(marketing)/profile/_components/ContributionCollection.tsx @@ -0,0 +1,90 @@ +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/Avatar" +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/Tooltip" +import { GuildReward, Schemas } from "@guildxyz/types" +import { Ranking } from "@phosphor-icons/react" +import { GuildAction } from "components/[guild]/Requirements/components/GuildCheckout/MintGuildPinContext" +import { env } from "env" +import Star from "static/icons/star.svg" +import useSWRImmutable from "swr/immutable" + +export const ContributionCollection = ({ + collection, + guildId, +}: { collection: Schemas["ContributionCollection"]; guildId: number }) => { + const collectionPoint = collection.points.at(0) + const collectionNft = collection.NFTs.at(0) + const collectionPin = collection.pins.at(0) + const { data: pinHash } = useSWRImmutable( + collectionPin + ? `/v2/guilds/${guildId}/pin?guildAction=${GuildAction[collectionPin.action]}` + : null + ) + const pin = pinHash ? new URL(pinHash, env.NEXT_PUBLIC_IPFS_GATEWAY) : undefined + const { data: point } = useSWRImmutable( + collectionPoint + ? `/v2/guilds/${collectionPoint.guildId}/guild-platforms/${collectionPoint.guildPlatformId}` + : null + ) + + return ( + <> + {pin && ( + + + + + + + + Minted Guild Pin + + )} + {collectionNft?.data.imageUrl && ( + + + + + + + + + Minted {collectionNft.data.name} + + + )} + {point && collectionPoint && ( + <> + + {point.platformGuildData.imageUrl ? ( + <> + + + + ) : ( + + )} + +
+
+ {collectionPoint.totalPoints}  + {point.platformGuildData.name} +
+
+ #{collectionPoint.rank} +
+
+ + )} + + ) +} diff --git a/src/v2/components/ui/AvatarGroup.tsx b/src/v2/components/ui/AvatarGroup.tsx index a3cbd6da03..47b2a4cea5 100644 --- a/src/v2/components/ui/AvatarGroup.tsx +++ b/src/v2/components/ui/AvatarGroup.tsx @@ -26,7 +26,7 @@ export const AvatarGroup = ({ ))} {diffCount > 0 && ( - + +{diffCount} )}