Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add contribution collection to /profile, improve card #1454

Merged
merged 23 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b6f500d
feat: add collection and checkmark
dominik-stumpf Aug 26, 2024
1952a73
Merge branch 'profiles-page' into add-collection
dominik-stumpf Aug 27, 2024
59cdbcd
chore: add extended collection
dominik-stumpf Aug 27, 2024
6e5db41
fix: add line clamp to edit contribution select
dominik-stumpf Aug 28, 2024
5ff8979
feat: add point image to contribution
dominik-stumpf Aug 28, 2024
23f9436
Merge branch 'profiles-page' of github.com:guildxyz/guild.xyz into ad…
dominik-stumpf Aug 28, 2024
d1c4a49
fix: show cards if no point is received
dominik-stumpf Aug 28, 2024
3ea5fab
Merge branch 'main' into add-collection
dominik-stumpf Aug 30, 2024
a24fb28
chore: merge profiles-page branch
dominik-stumpf Aug 30, 2024
e796093
feat: add points text and leaderboard ranking
dominik-stumpf Aug 30, 2024
6137c97
chore: copy static folder to public
dominik-stumpf Aug 30, 2024
a4e3272
feat: add contribution collection, adjust style
dominik-stumpf Sep 5, 2024
7792ec2
chore: render contribution card if no collection is present
dominik-stumpf Sep 5, 2024
1d8fbbc
chore: merge profiles-page branch
dominik-stumpf Sep 6, 2024
b671808
feat: add nft to collection
dominik-stumpf Sep 6, 2024
ead936c
feat: add pins
dominik-stumpf Sep 6, 2024
b9d406e
refactor: cleanup collection
dominik-stumpf Sep 6, 2024
0cf062e
fix: remove checkmark, allow longer label
dominik-stumpf Sep 9, 2024
b536a63
feat: add tooltip to collection
dominik-stumpf Sep 9, 2024
6c6bcc4
fix: prevent wrap on points text
dominik-stumpf Sep 9, 2024
e510af4
chore: remove NFT from tooltip
dominik-stumpf Sep 9, 2024
797a6a8
chore: remove src/static dir duplication
dominik-stumpf Sep 9, 2024
62cb6dd
chore: polish borders
dominik-stumpf Sep 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
23 changes: 23 additions & 0 deletions src/app/(marketing)/profile/[username]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<Schemas["ContributionCollection"]>(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)
)
Expand All @@ -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 {
Expand All @@ -145,6 +167,7 @@ const fetchPublicProfileData = async ({
[farcasterProfilesRequest.pathname, farcasterProfiles],
[neynarRequest?.href, fcFollowers],
[referredUsersRequest.pathname, referredUsers],
...collectionsZipped,
...guildsZipped,
...rolesZipped,
].filter(([key, value]) => key && value)
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -22,7 +21,7 @@ export const CardWithGuildLabel = ({
style={{ background: guild.theme.color }}
title={guild.name}
>
<div className="sm:-translate-x-1/2 sm:-rotate-90 flex h-full items-center gap-1 sm:absolute sm:left-1/2 sm:justify-center">
<div className="sm:-translate-x-1/2 sm:-rotate-90 flex h-full items-center gap-1 sm:absolute sm:left-1/2 sm:max-w-28 sm:justify-center">
<Avatar size="xs">
<AvatarImage
src={guild.imageUrl}
Expand All @@ -34,13 +33,12 @@ export const CardWithGuildLabel = ({
</Avatar>
<div
className={cn(
"-mt-0.5 truncate font-bold font-display text-foreground max-sm:text-sm sm:max-w-12",
"-mt-0.5 truncate font-bold font-display text-foreground text-sm",
color && (color.isDark() ? "text-white" : "text-black")
)}
>
{guild.name}
</div>
<CheckMark className="sm:hidden" />
</div>
</div>
<div className="mt-9 size-full rounded-2xl bg-card sm:mt-0 sm:ml-8">
Expand Down
24 changes: 20 additions & 4 deletions src/app/(marketing)/profile/_components/ContributionCard.tsx
Original file line number Diff line number Diff line change
@@ -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 = ({
Expand All @@ -11,6 +11,22 @@ export const ContributionCard = ({
const role = useSWRImmutable<Role>(
`/v2/guilds/${contribution.guildId}/roles/${contribution.roleId}`
)
if (!role.data || !guild.data) return
return <ContributionCardView guild={guild.data} role={role.data} />
const profile = useProfile()
const collection = useSWRImmutable<Schemas["ContributionCollection"]>(
profile.data
? `/v2/profiles/${profile.data.username}/contributions/${contribution.id}/collection`
: null
)

if (!role.data || !guild.data) {
return <Skeleton className="h-32 w-full rounded-2xl" />
}

return (
<ContributionCardView
guild={guild.data}
role={role.data}
collection={collection.data}
/>
)
}
31 changes: 22 additions & 9 deletions src/app/(marketing)/profile/_components/ContributionCardView.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<CardWithGuildLabel guild={guild}>
<div className="grid grid-cols-[auto_1fr] items-center gap-4 p-5 md:grid-cols-[auto_auto_1fr] md:p-6">
Expand All @@ -34,13 +42,18 @@ export const ContributionCardView = ({
</p>
</div>
</div>
<div className="col-span-2 flex w-full flex-col gap-2 justify-self-end md:col-span-1 md:w-auto md:flex-row md:items-center">
<Separator className="mb-2 md:hidden" />
<div className="font-extrabold text-muted-foreground text-xs uppercase">
COLLECTION:
{collection && !!collections.length && (
<div className="col-span-2 flex w-full flex-col gap-2 justify-self-end md:col-span-1 md:w-auto md:flex-row md:items-center">
<Separator className="mb-2 md:hidden" />
<div className="font-extrabold text-muted-foreground text-xs uppercase">
COLLECTION:
</div>

<div className="ml-3 flex">
<ContributionCollection collection={collection} guildId={guild.id} />
</div>
</div>
<AvatarGroup imageUrls={["", "", ""]} count={87} size="lg" />
</div>
)}
</div>
</CardWithGuildLabel>
)
Expand Down
90 changes: 90 additions & 0 deletions src/app/(marketing)/profile/_components/ContributionCollection.tsx
Original file line number Diff line number Diff line change
@@ -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<string>(
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<GuildReward>(
collectionPoint
? `/v2/guilds/${collectionPoint.guildId}/guild-platforms/${collectionPoint.guildPlatformId}`
: null
)

return (
<>
{pin && (
<Tooltip>
<TooltipTrigger>
<Avatar size="lg" className="-ml-3 border-2 border-card">
<AvatarImage src={pin.href} alt="avatar" width={32} height={32} />
<AvatarFallback />
</Avatar>
</TooltipTrigger>
<TooltipContent>Minted Guild Pin</TooltipContent>
</Tooltip>
)}
{collectionNft?.data.imageUrl && (
<Tooltip>
<TooltipTrigger>
<Avatar size="lg" className="-ml-3 border-2 border-card">
<AvatarImage
src={collectionNft.data.imageUrl}
alt="avatar"
width={32}
height={32}
/>
<AvatarFallback />
</Avatar>
</TooltipTrigger>
<TooltipContent>
Minted <strong>{collectionNft.data.name}</strong>
</TooltipContent>
</Tooltip>
)}
{point && collectionPoint && (
<>
<Avatar size="lg" className="-ml-3 border-2 border-card">
{point.platformGuildData.imageUrl ? (
<>
<AvatarImage
src={point.platformGuildData.imageUrl}
alt="avatar"
width={32}
height={32}
/>
<AvatarFallback />
</>
) : (
<Star className="size-6" />
)}
</Avatar>
<div className="-ml-3 self-center whitespace-nowrap rounded-r-lg border bg-card-secondary py-0.5 pr-2 pl-5">
<div className="text-sm">
{collectionPoint.totalPoints}&nbsp;
<span className="font-extrabold">{point.platformGuildData.name}</span>
</div>
<div className="flex items-center gap-1 text-muted-foreground text-xs">
<Ranking weight="bold" />#{collectionPoint.rank}
</div>
</div>
</>
)}
</>
)
}
2 changes: 1 addition & 1 deletion src/v2/components/ui/AvatarGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const AvatarGroup = ({
</Avatar>
))}
{diffCount > 0 && (
<Avatar className={cn(avatarVariants(avatarProps), "-ml-3")}>
<Avatar className={cn(avatarVariants(avatarProps), "-ml-3 border")}>
<AvatarFallback>+{diffCount}</AvatarFallback>
</Avatar>
)}
Expand Down
Loading