Skip to content

Commit d9700df

Browse files
committed
[TOOL-4292] Dashboard: Show Team selector page for '~' team slug
1 parent c803893 commit d9700df

File tree

2 files changed

+115
-13
lines changed

2 files changed

+115
-13
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { type Team, getTeams } from "@/api/team";
2+
import { GradientAvatar } from "@/components/blocks/Avatars/GradientAvatar";
3+
import { getThirdwebClient } from "@/constants/thirdweb.server";
4+
import { ChevronRightIcon, UsersIcon } from "lucide-react";
5+
import Link from "next/link";
6+
import { notFound, redirect } from "next/navigation";
7+
import { getAuthToken } from "../../../api/lib/getAuthToken";
8+
import { TeamPlanBadge } from "../../../components/TeamPlanBadge";
9+
import { TeamHeader } from "../../components/TeamHeader/team-header";
10+
11+
export default async function Page(props: {
12+
params: Promise<{
13+
paths?: string[];
14+
}>;
15+
searchParams: Promise<Record<string, string | undefined | string[]>>;
16+
}) {
17+
const params = await props.params;
18+
const searchParams = await props.searchParams;
19+
20+
const teams = await getTeams();
21+
const authToken = await getAuthToken();
22+
23+
if (!teams || !authToken) {
24+
notFound();
25+
}
26+
27+
const searchParamsString = Object.entries(searchParams)
28+
.map(([key, value]) => {
29+
if (Array.isArray(value)) {
30+
return value.map((v) => `${key}=${v}`).join("&");
31+
}
32+
return `${key}=${value}`;
33+
})
34+
.join("&");
35+
36+
// if there is a single team, redirect to the team page directly
37+
if (teams.length === 1 && teams[0]) {
38+
redirect(
39+
createTeamLink({
40+
team: teams[0],
41+
paths: params.paths,
42+
searchParams: searchParamsString,
43+
}),
44+
);
45+
}
46+
47+
const client = getThirdwebClient({
48+
jwt: authToken,
49+
teamId: undefined,
50+
});
51+
52+
return (
53+
<div className="flex min-h-dvh flex-col">
54+
<div className="border-b bg-card">
55+
<TeamHeader />
56+
</div>
57+
58+
<div className="container flex grow flex-col items-center justify-center">
59+
<div className="w-full max-w-lg rounded-xl border bg-card shadow-2xl">
60+
<div className="border-b p-6">
61+
<div className="mb-1 inline-block rounded-full border p-2">
62+
<UsersIcon className="size-5 text-muted-foreground" />
63+
</div>
64+
<h1 className="mb-0.5 font-semibold text-xl tracking-tight">
65+
Select a team
66+
</h1>
67+
<p className="text-muted-foreground text-sm">
68+
You are currently a member of multiple teams
69+
<br />
70+
Select a team to view this page
71+
</p>
72+
</div>
73+
74+
<div className="flex flex-col [&>*:not(:last-child)]:border-b">
75+
{teams.map((team) => {
76+
return (
77+
<div
78+
key={team.id}
79+
className="group relative flex items-center gap-3 px-6 py-4 hover:bg-accent/50"
80+
>
81+
<GradientAvatar
82+
src={team.image || ""}
83+
id={team.id}
84+
className="size-8 rounded-full border"
85+
client={client}
86+
/>
87+
<Link
88+
href={createTeamLink({
89+
team,
90+
paths: params.paths,
91+
searchParams: searchParamsString,
92+
})}
93+
className="before:absolute before:inset-0"
94+
>
95+
{team.name}
96+
</Link>
97+
<TeamPlanBadge plan={team.billingPlan} />
98+
<ChevronRightIcon className="ml-auto size-4 text-muted-foreground group-hover:text-foreground" />
99+
</div>
100+
);
101+
})}
102+
</div>
103+
</div>
104+
</div>
105+
</div>
106+
);
107+
}
108+
109+
function createTeamLink(params: {
110+
team: Team;
111+
paths: string[] | undefined;
112+
searchParams: string | undefined;
113+
}) {
114+
return `/team/${params.team.slug}/${(params.paths || [])?.join("/") || ""}${params.searchParams ? `?${params.searchParams}` : ""}`;
115+
}

apps/dashboard/src/middleware.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { getDefaultTeam } from "@/api/team";
21
import { isLoginRequired } from "@/constants/auth";
32
import { COOKIE_ACTIVE_ACCOUNT, COOKIE_PREFIX_TOKEN } from "@/constants/cookie";
43
import { type NextRequest, NextResponse } from "next/server";
@@ -188,18 +187,6 @@ export async function middleware(request: NextRequest) {
188187
}
189188
}
190189

191-
// redirect /team/~/... to /team/<first_team_slug>/...
192-
if (paths[0] === "team" && paths[1] === "~") {
193-
const firstTeam = await getDefaultTeam();
194-
if (firstTeam) {
195-
const modifiedPaths = [...paths];
196-
modifiedPaths[1] = firstTeam.slug;
197-
return redirect(request, `/${modifiedPaths.join("/")}`, {
198-
searchParams: request.nextUrl.searchParams.toString(),
199-
cookiesToSet,
200-
});
201-
}
202-
}
203190
// END /<address>/... case
204191
// all other cases are handled by the file system router so we just fall through
205192
if (cookiesToSet) {

0 commit comments

Comments
 (0)