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) {