diff --git a/apps/web/modules/settings/organizations/new/_components/AddNewTeamsForm.tsx b/apps/web/modules/settings/organizations/new/_components/AddNewTeamsForm.tsx index d8af291603..8adb8ce9a8 100644 --- a/apps/web/modules/settings/organizations/new/_components/AddNewTeamsForm.tsx +++ b/apps/web/modules/settings/organizations/new/_components/AddNewTeamsForm.tsx @@ -7,9 +7,10 @@ import { z } from "zod"; import { useOnboarding } from "@calcom/features/ee/organizations/lib/onboardingStore"; import { useLocale } from "@calcom/lib/hooks/useLocale"; +import slugify from "@calcom/lib/slugify"; import { trpc } from "@calcom/trpc/react"; -import { Button } from "@calcom/ui/components/button"; import classNames from "@calcom/ui/classNames"; +import { Button } from "@calcom/ui/components/button"; import { CheckboxField } from "@calcom/ui/components/form"; import { Form } from "@calcom/ui/components/form"; import { TextField } from "@calcom/ui/components/form"; @@ -102,7 +103,7 @@ const AddNewTeamsFormChild = ({ teams }: { teams: { id: number; name: string; sl } }, }); - const { register, control, watch, getValues } = form; + const { register, control, watch, getValues, setValue } = form; const { fields, append, remove } = useFieldArray({ control, name: "teams", @@ -177,6 +178,10 @@ const AddNewTeamsFormChild = ({ teams }: { teams: { id: number; name: string; sl placeholder="New Slug" defaultValue={teams.find((t) => t.id === team.id)?.slug ?? ""} {...register(`moveTeams.${index}.newSlug`)} + onChange={(e) => { + const slug = slugify(e.target.value, true); + setValue(`moveTeams.${index}.newSlug`, slug); + }} className="mt-2" label="" /> diff --git a/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts b/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts index de7b1f91a9..94724870ea 100644 --- a/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts +++ b/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.test.ts @@ -313,6 +313,39 @@ describe("createOrganizationFromOnboarding", () => { ).rejects.toThrow("organization_url_taken"); }); + it("should create team with slugified slug", async () => { + const teamToMove = await createTestTeam({ + name: "Sales", + slug: "Company Sales", + }); + + const { organizationOnboarding } = await createOnboardingEligibleUserAndOnboarding({ + user: { + email: "test@example.com", + }, + organizationOnboarding: { + slug: "UPPERCASE-SLUG", + teams: [{ id: teamToMove.id, name: "Sales", isBeingMigrated: true, slug: "sales-team" }], + }, + }); + + const { organization } = await createOrganizationFromOnboarding({ + organizationOnboarding, + paymentSubscriptionId: "mock_subscription_id", + paymentSubscriptionItemId: "mock_subscription_item_id", + }); + + expect(createTeamsHandler).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + orgId: organization.id, + teamNames: [], + moveTeams: expect.arrayContaining([expect.objectContaining({ id: 1, newSlug: "sales-team" })]), + }), + }) + ); + }); + it("should update stripe customer ID for existing user", async () => { const { user: existingUser, organizationOnboarding } = await createOnboardingEligibleUserAndOnboarding({ user: { diff --git a/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.ts b/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.ts index c65acc0e99..55bbb35561 100644 --- a/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.ts +++ b/packages/features/ee/organizations/lib/server/createOrganizationFromOnboarding.ts @@ -16,6 +16,7 @@ import { getTranslation } from "@calcom/lib/server/i18n"; import { OrganizationRepository } from "@calcom/lib/server/repository/organization"; import { OrganizationOnboardingRepository } from "@calcom/lib/server/repository/organizationOnboarding"; import { UserRepository } from "@calcom/lib/server/repository/user"; +import slugify from "@calcom/lib/slugify"; import { prisma } from "@calcom/prisma"; import type { Prisma } from "@calcom/prisma/client"; import type { Team, User } from "@calcom/prisma/client"; @@ -254,7 +255,7 @@ async function createOrMoveTeamsToOrganization(teams: TeamData[], owner: User, o .filter((team) => team.isBeingMigrated) .map((team) => ({ id: team.id, - newSlug: team.slug, + newSlug: team.slug ? slugify(team.slug) : team.slug, shouldMove: true, })); diff --git a/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts b/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts index edcf5dfd80..77ee3573af 100644 --- a/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts +++ b/packages/trpc/server/routers/viewer/organizations/createTeams.handler.ts @@ -10,11 +10,11 @@ import { prisma } from "@calcom/prisma"; import type { CreationSource } from "@calcom/prisma/enums"; import { MembershipRole, RedirectType } from "@calcom/prisma/enums"; import { teamMetadataSchema } from "@calcom/prisma/zod-utils"; + import { TRPCError } from "@trpc/server"; -import type { TCreateTeamsSchema } from "./createTeams.schema"; -import type { TrpcSessionUser } from "../../../types"; import { inviteMembersWithNoInviterPermissionCheck } from "../teams/inviteMember/inviteMember.handler"; +import type { TCreateTeamsSchema } from "./createTeams.schema"; const log = logger.getSubLogger({ prefix: ["viewer/organizations/createTeams.handler"] }); type CreateTeamsOptions = {