From 7fa5be53173e7c167b93e3cb30aa6ece578cde50 Mon Sep 17 00:00:00 2001 From: jnsdls Date: Fri, 6 Jun 2025 21:42:16 +0000 Subject: [PATCH] [Dashboard] Add staff mode for viewing teams without membership (#7299) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary by CodeRabbit - **New Features** - Added a "STAFF MODE" warning banner for users viewing a team they do not belong to, with a button to leave staff mode. - **User Interface** - Adjusted the team header layout for improved accessibility, ensuring the team badge is no longer nested inside the team link. --- ## PR-Codex overview This PR primarily focuses on updating the `TeamHeaderUI` component and enhancing the `TeamLayout` and `ProjectLayout` components to incorporate a "Staff Mode" feature, which restricts user actions based on team membership. ### Detailed summary - Modified the structure of the `TeamHeaderUI` component to wrap the `Link` inside a `span`. - Added a "Staff Mode" warning message in `TeamLayout` if the user is not part of the team. - Implemented the same "Staff Mode" warning in `ProjectLayout`. - Updated API calls to include `getTeamBySlug` and `getProject`. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../(app)/team/[team_slug]/(team)/layout.tsx | 32 +++++++++----- .../[project_slug]/(sidebar)/layout.tsx | 44 ++++++++++++------- .../components/TeamHeader/TeamHeaderUI.tsx | 29 ++++++------ 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx index 4780484b081..d30dcdd5391 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx @@ -1,9 +1,11 @@ import { getProjects } from "@/api/projects"; -import { getTeams } from "@/api/team"; +import { getTeamBySlug, getTeams } from "@/api/team"; import { AppFooter } from "@/components/blocks/app-footer"; +import { Button } from "@/components/ui/button"; import { TabPathLinks } from "@/components/ui/tabs"; import { getClientThirdwebClient } from "@/constants/thirdweb-client.client"; import { AnnouncementBanner } from "components/notices/AnnouncementBanner"; +import Link from "next/link"; import { redirect } from "next/navigation"; import { siwaExamplePrompts } from "../../../(dashboard)/support/page"; import { CustomChatButton } from "../../../../nebula-app/(app)/components/CustomChat/CustomChatButton"; @@ -20,25 +22,18 @@ export default async function TeamLayout(props: { }) { const params = await props.params; - const [accountAddress, account, teams, authToken] = await Promise.all([ + const [accountAddress, account, teams, authToken, team] = await Promise.all([ getAuthTokenWalletAddress(), getValidAccount(`/team/${params.team_slug}`), getTeams(), getAuthToken(), + getTeamBySlug(params.team_slug), ]); - if (!teams || !accountAddress || !authToken) { + if (!teams || !accountAddress || !authToken || !team) { redirect("/login"); } - const team = teams.find( - (t) => t.slug === decodeURIComponent(params.team_slug), - ); - - if (!team) { - redirect("/team"); - } - const teamsAndProjects = await Promise.all( teams.map(async (team) => ({ team, @@ -53,6 +48,21 @@ export default async function TeamLayout(props: { return (
+ {!teams.some((t) => t.slug === team.slug) && ( +
+
+
+

👀 STAFF MODE 👀

+

+ You can only view this team, not take any actions. +

+
+ +
+
+ )}
; }) { const params = await props.params; - const [accountAddress, teams, account, authToken] = await Promise.all([ - getAuthTokenWalletAddress(), - getTeams(), - getValidAccount(`/team/${params.team_slug}/${params.project_slug}`), - getAuthToken(), - ]); + const [accountAddress, teams, account, authToken, team, project] = + await Promise.all([ + getAuthTokenWalletAddress(), + getTeams(), + getValidAccount(`/team/${params.team_slug}/${params.project_slug}`), + getAuthToken(), + getTeamBySlug(params.team_slug), + getProject(params.team_slug, params.project_slug), + ]); if (!teams || !accountAddress || !authToken) { redirect("/login"); } - const team = teams.find( - (t) => t.slug === decodeURIComponent(params.team_slug), - ); - if (!team) { redirect("/team"); } @@ -47,10 +48,6 @@ export default async function ProjectLayout(props: { })), ); - const project = teamsAndProjects - .find((t) => t.team.slug === decodeURIComponent(params.team_slug)) - ?.projects.find((p) => p.slug === params.project_slug); - if (!project) { // not a valid project, redirect back to team page redirect(`/team/${params.team_slug}`); @@ -65,6 +62,21 @@ export default async function ProjectLayout(props: { return (
+ {!teams.some((t) => t.slug === team.slug) && ( +
+
+
+

👀 STAFF MODE 👀

+

+ You can only view this team, not take any actions. +

+
+ +
+
+ )}
- - - {currentTeam.name} - + + + + {currentTeam.name} + + + {/* may render its own link so has to be outside of the link */} - +