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 guild page #1558

Draft
wants to merge 107 commits into
base: v3-main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
3a8874c
feat: add guild page routes
dominik-stumpf Nov 22, 2024
bbf915d
chore: center join guild button
dominik-stumpf Nov 22, 2024
e6df6f7
feat: add requirement ui
dominik-stumpf Nov 23, 2024
dd69324
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Nov 26, 2024
ca7ba25
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Nov 26, 2024
4393710
fix: remove the `[guild]` directory
BrickheadJohnny Nov 26, 2024
008047f
feat: GuildImage component
BrickheadJohnny Nov 26, 2024
a78e0ce
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Nov 26, 2024
90a6378
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Nov 26, 2024
5eb7e94
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Nov 27, 2024
70da86d
cleanup: remove playground and rename the components folder
BrickheadJohnny Nov 27, 2024
87c34e2
feat: role group navigation menu
BrickheadJohnny Nov 27, 2024
8ef76fa
feat: simple create page form
BrickheadJohnny Nov 27, 2024
23b5da5
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Nov 27, 2024
c1c78f5
refactor: extract the `GuildTabs` component and `getGuild` function
BrickheadJohnny Nov 27, 2024
29a0ed4
fix(CreateGuildButton): increase toast duration
BrickheadJohnny Nov 27, 2024
e1db931
feat: revalidate role groups after creation
BrickheadJohnny Nov 27, 2024
81ee35d
cleanup(CreateRoleGroup): remove console.log
BrickheadJohnny Nov 27, 2024
2908f05
feat: cache role groups
BrickheadJohnny Nov 27, 2024
6d396ee
Merge branch 'v3-main' into add-guild-page
dominik-stumpf Nov 27, 2024
e0444fa
Merge branch 'v3-main' into add-guild-page
dominik-stumpf Nov 27, 2024
e68b835
feat: align to new backend responses
dominik-stumpf Nov 27, 2024
5e30e14
chore: get guild using fetcher util
dominik-stumpf Nov 27, 2024
255680c
Merge branch 'v3-main' into add-guild-page
dominik-stumpf Nov 27, 2024
e058d5c
chore: remove console.log
dominik-stumpf Nov 28, 2024
d768d05
fix: dont put comma between url segments
dominik-stumpf Nov 28, 2024
89080a8
feat: create sort for roleGroup tabs
dominik-stumpf Nov 28, 2024
3849ec5
feat: display rewards
dominik-stumpf Nov 28, 2024
f37aa2e
chore: make role card horizontal on small
dominik-stumpf Nov 28, 2024
e1daf6b
feat: add join guild logic
dominik-stumpf Nov 28, 2024
71bd24b
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Nov 29, 2024
c2a9f52
fix(RoleCard): use the old design
BrickheadJohnny Nov 29, 2024
799b90a
feat: add logout action
dominik-stumpf Nov 29, 2024
70278f9
chore: merge v3-main, resolve conflicts
dominik-stumpf Nov 29, 2024
6358a52
feat: add guild join and leave without revalidation
dominik-stumpf Dec 2, 2024
811c65e
Merge branch 'v3-main' of github.com:guildxyz/guild.xyz into add-guil…
dominik-stumpf Dec 2, 2024
e6aac61
chore: migrate from role-group to page, rename route params
dominik-stumpf Dec 2, 2024
915509c
chore: update guild types
dominik-stumpf Dec 2, 2024
89415fe
chore: rename roleGroup to page
dominik-stumpf Dec 2, 2024
f7d1e80
chore: delete create role group
dominik-stumpf Dec 2, 2024
7f8800d
feat: RewardCard component (#1574)
BrickheadJohnny Dec 2, 2024
27cbb67
chore: replace search with batch requests
dominik-stumpf Dec 2, 2024
753d745
Merge branch 'add-guild-page' of github.com:guildxyz/guild.xyz into a…
dominik-stumpf Dec 2, 2024
bf249a8
feat: add hydration boundary to guild page
dominik-stumpf Dec 2, 2024
cfc5ed4
refactor: move explorer fetchers to server actions
dominik-stumpf Dec 2, 2024
5da0b6e
feat: add guild fetcher
dominik-stumpf Dec 2, 2024
d315dd6
chore: add auth fetcher
dominik-stumpf Dec 2, 2024
c65bf03
refactor: replace old fetchers
dominik-stumpf Dec 2, 2024
3ed89fc
feat: implement fetcher with response
dominik-stumpf Dec 2, 2024
db0db1a
feat: create different fetch utilities using composition
dominik-stumpf Dec 2, 2024
a4c6cc2
docs: add jsdoc to fetchers
dominik-stumpf Dec 2, 2024
730d90f
refactor: replace all fetcher
dominik-stumpf Dec 2, 2024
dc1beca
feat: add more control over logging
dominik-stumpf Dec 2, 2024
957c2ad
chore: remove useless optional chain
dominik-stumpf Dec 2, 2024
6517ff5
feat: add hydration for user and guild
dominik-stumpf Dec 3, 2024
b215b4e
chore: expose LOGGING env var to client
dominik-stumpf Dec 3, 2024
2cec819
fix: add default for LOGGING env var and make it shared
dominik-stumpf Dec 3, 2024
119452b
fix: use data on SignInDialog
dominik-stumpf Dec 3, 2024
7d8c2ef
feat: add join and leave using tanstack
dominik-stumpf Dec 3, 2024
2a051dc
fix: close nav menu after navigating
dominik-stumpf Dec 3, 2024
cb51eae
fix: address unique index error
dominik-stumpf Dec 3, 2024
a00c64c
chore: move request to client side, mutate cache on success
dominik-stumpf Dec 3, 2024
82ad909
feat: show join progress using toasts and event stream
dominik-stumpf Dec 3, 2024
ae82d83
chore: disable retry on error
dominik-stumpf Dec 3, 2024
e58ea8e
chore: disable retry on error
dominik-stumpf Dec 3, 2024
c2fa6c6
refactor: remove unused code
dominik-stumpf Dec 3, 2024
6053a91
refactor: move auth into main fetcher, renamings
dominik-stumpf Dec 3, 2024
4cbbfde
refactor: move token into associated guilds
dominik-stumpf Dec 3, 2024
a832ed5
feat: add form data option for fetcher
dominik-stumpf Dec 3, 2024
038ffc8
refactor: move and rename fetchers, options
dominik-stumpf Dec 4, 2024
34a9177
chore: remove token on 401, remove empty file
dominik-stumpf Dec 4, 2024
b8e12cd
chore: update types package
dominik-stumpf Dec 4, 2024
debff3c
fix: use QueryClient wrapper on provider, invalidate on join
dominik-stumpf Dec 4, 2024
ed7e5e0
fix: move query client retrieval inside component
dominik-stumpf Dec 4, 2024
cbd681f
cleanup: remove empty Button component
BrickheadJohnny Dec 4, 2024
5c7d310
fix: validate join flow using event stream
dominik-stumpf Dec 4, 2024
21d1af9
Merge branch 'add-guild-page' of github.com:guildxyz/guild.xyz into a…
dominik-stumpf Dec 4, 2024
d9c46d2
refactor: use tanstack query on explorer
dominik-stumpf Dec 4, 2024
6e5da40
Merge branch 'v3-main' of github.com:guildxyz/guild.xyz into add-guil…
dominik-stumpf Dec 4, 2024
46f1c28
Merge branch 'v3-main' of github.com:guildxyz/guild.xyz into add-guil…
dominik-stumpf Dec 4, 2024
4529d6c
feat: requirements (#1572)
BrickheadJohnny Dec 4, 2024
71c34ce
Merge branch 'v3-main' of github.com:guildxyz/guild.xyz into add-guil…
dominik-stumpf Dec 4, 2024
b7e43c0
Merge branch 'add-guild-page' of github.com:guildxyz/guild.xyz into a…
dominik-stumpf Dec 4, 2024
8347a7e
refactor: use rq in guild tabs
dominik-stumpf Dec 4, 2024
bb23575
feat: add tq to role and reward
dominik-stumpf Dec 4, 2024
6f6d33a
refactor: fetch guild on demand
dominik-stumpf Dec 4, 2024
755af6d
fix: await `prefetchInfiniteQuery` call
BrickheadJohnny Dec 5, 2024
99798ef
fix(JoinButton): simplify toast and fix the join flow
BrickheadJohnny Dec 5, 2024
3d4459e
feat(JoinButton): add icon to success toast
BrickheadJohnny Dec 5, 2024
2e1b646
fix(JoinButton): don't fallback to a sign in button
BrickheadJohnny Dec 5, 2024
0075ebb
fix: more discreet leave button
BrickheadJohnny Dec 5, 2024
70945c5
Merge branch 'add-guild-page' of github.com:guildxyz/guild.xyz into a…
dominik-stumpf Dec 6, 2024
01cf3c3
fix: add type package and update deprecated types
dominik-stumpf Dec 6, 2024
cff8e91
Merge branch 'v3-main' into add-guild-page
dominik-stumpf Dec 6, 2024
9975906
feat: add prefetch to all entities
dominik-stumpf Dec 6, 2024
a38d33d
Merge branch 'v3-main' of github.com:guildxyz/guild.xyz into add-guil…
dominik-stumpf Dec 9, 2024
b5215ec
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Dec 9, 2024
0d6a0df
Merge branch 'v3-main' into add-guild-page
BrickheadJohnny Dec 11, 2024
8f10e63
feat: rewards (#1579)
BrickheadJohnny Dec 12, 2024
a525286
feat: basic access indicators
BrickheadJohnny Dec 12, 2024
6932741
feat: store join modal open state in an atom
BrickheadJohnny Dec 12, 2024
c9d2564
fix: fine-tune colors in light mode
BrickheadJohnny Dec 12, 2024
77b5ddd
fix: fine-tune primary subtle button color
BrickheadJohnny Dec 12, 2024
3945561
feat(JoinGuild): better toasts
BrickheadJohnny Dec 12, 2024
e764e1f
fix: move confetti provider to the root layout
BrickheadJohnny Dec 12, 2024
5624e27
fix(JoinGuild): close join modal on success
BrickheadJohnny Dec 12, 2024
6a059d3
fix(DiscordRoleRewardDataSchema): add name prop
BrickheadJohnny Dec 12, 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ bun.lockb
/playwright/.cache/
/playwright/.auth/
/playwright/results

certificates
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ Open source interface for Guild.xyz -- a tool for platformless membership manage
### Running the interface locally

1. `bun i`
2. `bun run dev`
3. If you don't have the secret environment variables, copy the `.env.example` as `.env.local`.
2. Append `127.0.0.1 local.openguild.xyz` to `/etc/hosts`
3. If you don't have the secret environment variables, copy the `.env.example` as `.env.local`
4. Run `bun dev`, create certificate if prompted
5. Open `https://local.openguild.xyz:3000` and dismiss the unsecure site warning

Open [http://localhost:3000](http://localhost:3000) in your browser to see the result.

### Getting secret environment variables (for core team members):

Expand Down
56 changes: 28 additions & 28 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"scripts": {
"prepare": "husky",
"dev": "next dev --turbo",
"dev": "next dev --turbo --experimental-https",
"build": "next build",
"start": "next start",
"type-check": "tsc --pretty --noEmit --incremental false",
Expand All @@ -31,19 +31,19 @@
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.4",
"@t3-oss/env-nextjs": "^0.11.1",
"@tailwindcss/container-queries": "^0.1.1",
"@tailwindcss/typography": "^0.5.15",
"@tanstack/react-query": "^5.60.2",
"@tanstack/react-query-devtools": "^5.61.0",
"@tanstack/react-query": "^5.62.2",
"@tanstack/react-query-devtools": "^5.62.2",
"autoprefixer": "^10.4.20",
"class-variance-authority": "^0.7.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"event-source-plus": "^0.1.8",
"foxact": "^0.2.41",
"jotai": "^2.10.2",
"jwt-decode": "^4.0.0",
"foxact": "^0.2.43",
"jotai": "^2.10.3",
"mini-svg-data-uri": "^1.4.4",
"next": "15.0.3",
"next-themes": "^0.4.3",
"next-themes": "^0.4.4",
"pinata-web3": "^0.5.2",
"react": "19.0.0-rc-66855b96-20241106",
"react-canvas-confetti": "^2.0.7",
Expand All @@ -56,38 +56,38 @@
"remark-textr": "^6.1.0",
"server-only": "^0.0.1",
"sonner": "^1.7.0",
"tailwind-merge": "^2.5.4",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"typographic-base": "^1.0.4",
"vaul": "^1.1.1",
"viem": "^2.21.45",
"wagmi": "^2.12.32",
"viem": "^2.21.54",
"wagmi": "^2.13.3",
"zod": "^3.23.8"
},
"devDependencies": {
"@biomejs/biome": "1.9.0",
"@chromatic-com/storybook": "^3.2.2",
"@storybook/addon-essentials": "^8.4.4",
"@storybook/addon-interactions": "^8.4.4",
"@storybook/addon-onboarding": "^8.4.4",
"@storybook/addon-essentials": "^8.4.7",
"@storybook/addon-interactions": "^8.4.7",
"@storybook/addon-onboarding": "^8.4.7",
"@storybook/addon-styling-webpack": "^1.0.1",
"@storybook/addon-themes": "^8.4.4",
"@storybook/blocks": "^8.4.4",
"@storybook/nextjs": "^8.4.4",
"@storybook/react": "^8.4.4",
"@storybook/test": "^8.4.4",
"@storybook/addon-themes": "^8.4.7",
"@storybook/blocks": "^8.4.7",
"@storybook/nextjs": "^8.4.7",
"@storybook/react": "^8.4.7",
"@storybook/test": "^8.4.7",
"@svgr/webpack": "^8.1.0",
"@total-typescript/ts-reset": "^0.6.1",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"husky": "^9.1.6",
"@types/node": "^20.17.9",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.1",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",
"postcss": "^8",
"storybook": "^8.4.4",
"tailwindcss": "^3.4.1",
"type-fest": "^4.29.1",
"typescript": "^5"
"postcss": "^8.4.49",
"storybook": "^8.4.7",
"tailwindcss": "^3.4.16",
"type-fest": "^4.30.0",
"typescript": "^5.7.2"
},
"overrides": {
"react": "19.0.0-rc-66855b96-20241106",
Expand Down
52 changes: 0 additions & 52 deletions src/actions/auth.ts

This file was deleted.

14 changes: 0 additions & 14 deletions src/actions/me.ts

This file was deleted.

198 changes: 198 additions & 0 deletions src/app/(dashboard)/[guildUrlName]/[pageUrlName]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
"use client";

import { RequirementDisplayComponent } from "@/components/requirements/RequirementDisplayComponent";
import { rewardCards } from "@/components/rewards/rewardCards";
import { Badge } from "@/components/ui/Badge";
import { Button, buttonVariants } from "@/components/ui/Button";
import { Card } from "@/components/ui/Card";
import { Skeleton } from "@/components/ui/Skeleton";
import { cn } from "@/lib/cssUtils";
import { fetchGuildApiData } from "@/lib/fetchGuildApi";
import { roleBatchOptions, userOptions } from "@/lib/options";
import type { GuildReward, GuildRewardType } from "@/lib/schemas/guildReward";
import type { Role } from "@/lib/schemas/role";
import { Check, ImageSquare, LockSimple } from "@phosphor-icons/react/dist/ssr";
import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
import { useSetAtom } from "jotai";
import { useParams } from "next/navigation";
import { Suspense } from "react";
import { joinModalAtom } from "../atoms";
import { useGuild } from "../hooks/useGuild";

const GuildPage = () => {
const { pageUrlName, guildUrlName } = useParams<{
pageUrlName: string;
guildUrlName: string;
}>();
const { data: roles } = useSuspenseQuery(
roleBatchOptions({
guildIdLike: guildUrlName,
pageIdLike: pageUrlName,
}),
);

return (
<div className="my-4 space-y-4">
{roles.map((role) => (
<Suspense
fallback={<Skeleton className="h-40 w-full rounded-xl" />}
key={role.id}
>
<RoleCard role={role} />
</Suspense>
))}
</div>
);
};

const RoleCard = ({ role }: { role: Role }) => (
<Card className="flex flex-col md:flex-row" key={role.id}>
<div className="@container flex flex-col border-r p-5 md:w-1/2">
<div className="mb-2 flex items-center gap-3">
{role.imageUrl ? (
<img
className="size-14 rounded-full border"
src={role.imageUrl}
alt="role avatar"
/>
) : (
<div className="flex size-14 items-center justify-center rounded-full bg-image text-white">
<ImageSquare weight="duotone" className="size-6" />
</div>
)}
<h3 className="font-extrabold text-xl">{role.name}</h3>
</div>
<p className="mb-4 text-foreground-dimmed leading-relaxed">
{role.description}
</p>

<Suspense fallback={<p>Loading rewards...</p>}>
<RoleRewards roleId={role.id} roleRewards={role.rewards} />
</Suspense>
</div>

<div className="bg-card-secondary md:w-1/2">
<div className="flex items-center justify-between p-5">
<span className="font-bold text-foreground-secondary text-xs">
REQUIREMENTS
</span>

<AccessIndicator roleId={role.id} className="hidden sm:flex" />
</div>

{/* TODO group rules by access groups */}
<div className="grid px-5 pb-5">
{role.accessGroups[0].rules?.map((rule) => (
<RequirementDisplayComponent
key={rule.accessRuleId}
requirement={rule}
/>
))}
</div>

<AccessIndicator roleId={role.id} className="sm:hidden" />
</div>
</Card>
);

const RoleRewards = ({
roleId,
roleRewards,
}: { roleId: string; roleRewards: Role["rewards"] }) => {
const { data: guild } = useGuild();
const { data: rewards } = useSuspenseQuery<GuildReward[]>({
queryKey: ["reward", "search", guild.id],
queryFn: () =>
fetchGuildApiData<{ items: GuildReward[] }>(
`reward/search?customQuery=@guildId:{${guild.id}}`,
).then((data) => data.items), // TODO: we shouldn't do this, we should just get back an array on this endpoint in my opinion
});

return roleRewards?.length > 0 && rewards?.length > 0 ? (
<div className="mt-auto grid @[26rem]:grid-cols-2 gap-2">
{roleRewards.map((roleReward) => {
const guildReward = rewards.find((gr) => gr.id === roleReward.rewardId);
if (!guildReward) return null;

const hasRewardCard = (
rewardType: GuildRewardType,
): rewardType is keyof typeof rewardCards => rewardType in rewardCards;

const RewardCard = hasRewardCard(guildReward.type)
? rewardCards[guildReward.type]
: null;

if (!RewardCard) return null;

return (
<RewardCard
key={roleReward.rewardId}
roleId={roleId}
reward={{
guildReward,
roleReward,
}}
/>
);
})}
</div>
) : null;
};

// TODO: handle state during join & error/no access states too
const ACCESS_INDICATOR_CLASS =
"rounded-b-2xl rounded-t-none min-w-full justify-between sm:rounded-b-xl sm:rounded-t-xl sm:min-w-max";
const AccessIndicator = ({
roleId,
className,
}: { roleId: Role["id"]; className?: string }) => {
const { data: guild } = useGuild();

const { data: user } = useQuery(userOptions());
const isGuildMember = user?.guilds?.find((g) => g.guildId === guild.id);
const isRoleMember = !!user?.guilds
?.flatMap((g) => g.roles)
?.find((r) => r?.roleId === roleId);

const onJoinModalOpenChange = useSetAtom(joinModalAtom);

if (!isGuildMember)
return (
<Button
size="sm"
leftIcon={<LockSimple weight="bold" />}
className={cn(ACCESS_INDICATOR_CLASS, className)}
onClick={() => onJoinModalOpenChange(true)}
>
Join guild to collect rewards
</Button>
);

if (!isRoleMember)
return (
<Button
size="sm"
leftIcon={<LockSimple weight="bold" />}
className={cn(ACCESS_INDICATOR_CLASS, className)}
onClick={() => onJoinModalOpenChange(true)}
>
Check access to collect rewards
</Button>
);

return (
<Badge
className={buttonVariants({
size: "sm",
colorScheme: "success",
variant: "subtle",
className: [ACCESS_INDICATOR_CLASS, className, "pointer-events-none"],
})}
>
<Check weight="bold" />
<span>You have access</span>
</Badge>
);
};

export default GuildPage;
3 changes: 3 additions & 0 deletions src/app/(dashboard)/[guildUrlName]/atoms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { atom } from "jotai";

export const joinModalAtom = atom(false);
Loading
Loading