From 8b1a60d5b6a6b29cd1d7a72f4f43040341d7048b Mon Sep 17 00:00:00 2001 From: MananTank Date: Wed, 1 Jan 2025 17:02:20 +0000 Subject: [PATCH] [TOOL-2891] Fix Team dashboard not loading if team slug contains special characters (#5867) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem solved Short description of the bug fixed or feature added --- ## PR-Codex overview This PR focuses on improving the handling of `team_slug` and validating the `teamSlug` input in the settings UI. It enhances the URL decoding process and adds error handling for invalid team URLs. ### Detailed summary - Updated `team_slug` retrieval to decode the URL component in `layout.tsx`. - Modified project retrieval logic to decode `team_slug`. - Replaced `isTeamTaken` state with `errorMessage` state for better error handling. - Added validation for `teamSlug` input to check for empty values and invalid characters. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../app/team/[team_slug]/(team)/layout.tsx | 4 +++- .../general/TeamGeneralSettingsPageUI.tsx | 22 ++++++++++++------- .../[team_slug]/[project_slug]/layout.tsx | 6 +++-- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx index fb4ac246844..5fc9fa72328 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/layout.tsx @@ -20,7 +20,9 @@ export default async function TeamLayout(props: { redirect("/login"); } - const team = teams.find((t) => t.slug === params.team_slug); + const team = teams.find( + (t) => t.slug === decodeURIComponent(params.team_slug), + ); const teamsAndProjects = await Promise.all( teams.map(async (team) => ({ team, diff --git a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx index bb43a59e5d3..ffaa29f21e2 100644 --- a/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/TeamGeneralSettingsPageUI.tsx @@ -97,8 +97,8 @@ function TeamSlugFormControl(props: { updateTeamField: (team: Partial) => Promise; }) { const [teamSlug, setTeamSlug] = useState(props.team.slug); - const [isTeamTaken] = useState(false); const maxTeamURLLength = 48; + const [errorMessage, setErrorMessage] = useState(); const updateTeamMutation = useMutation({ mutationFn: (slug: string) => props.updateTeamField({ slug: slug }), @@ -120,14 +120,10 @@ function TeamSlugFormControl(props: { "This is your team's URL namespace on thirdweb. All your team's projects and settings can be accessed using this URL", }} bottomText={`Please use ${maxTeamURLLength} characters at maximum.`} - errorText={ - isTeamTaken - ? "Team URL is taken, Please choose another one." - : undefined - } + errorText={errorMessage} saveButton={{ onClick: handleSave, - disabled: teamSlug.length === 0, + disabled: errorMessage !== undefined, isPending: updateTeamMutation.isPending, }} noPermissionText={undefined} // TODO @@ -139,7 +135,17 @@ function TeamSlugFormControl(props: { { - setTeamSlug(e.target.value.slice(0, maxTeamURLLength)); + const value = e.target.value.slice(0, maxTeamURLLength); + setTeamSlug(value); + if (value.trim().length === 0) { + setErrorMessage("Team URL can not be empty"); + } else if (/[^a-zA-Z0-9-]/.test(value)) { + setErrorMessage( + "Invalid Team URL. Only letters, numbers and hyphens are allowed", + ); + } else { + setErrorMessage(undefined); + } }} className="truncate border-0 font-mono" /> diff --git a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/layout.tsx b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/layout.tsx index 82e97357209..0b8ae3f08e7 100644 --- a/apps/dashboard/src/app/team/[team_slug]/[project_slug]/layout.tsx +++ b/apps/dashboard/src/app/team/[team_slug]/[project_slug]/layout.tsx @@ -20,7 +20,9 @@ export default async function TeamLayout(props: { redirect("/login"); } - const team = teams.find((t) => t.slug === params.team_slug); + const team = teams.find( + (t) => t.slug === decodeURIComponent(params.team_slug), + ); if (!team) { // not a valid team, redirect back to 404 @@ -35,7 +37,7 @@ export default async function TeamLayout(props: { ); const project = teamsAndProjects - .find((t) => t.team.slug === params.team_slug) + .find((t) => t.team.slug === decodeURIComponent(params.team_slug)) ?.projects.find((p) => p.slug === params.project_slug); if (!project) {