diff --git a/apps/web/app/api/teams/create/route.ts b/apps/web/app/api/teams/create/route.ts index 3d936872ae..09a3a231cb 100644 --- a/apps/web/app/api/teams/create/route.ts +++ b/apps/web/app/api/teams/create/route.ts @@ -8,6 +8,7 @@ import { Plan, SubscriptionStatus } from "@calcom/features/ee/billing/repository import { StripeBillingService } from "@calcom/features/ee/billing/stripe-billing-service"; import { InternalTeamBilling } from "@calcom/features/ee/billing/teams/internal-team-billing"; import stripe from "@calcom/features/ee/payments/server/stripe"; +import { WEBAPP_URL } from "@calcom/lib/constants"; import { HttpError } from "@calcom/lib/http-error"; import prisma from "@calcom/prisma"; import { MembershipRole } from "@calcom/prisma/enums"; @@ -20,6 +21,7 @@ const checkoutSessionMetadataSchema = z.object({ teamName: z.string(), teamSlug: z.string(), userId: z.string().transform(Number), + isOnboarding: z.string().optional(), }); const generateRandomString = () => { @@ -66,6 +68,7 @@ async function getHandler(req: NextRequest) { teamName: checkoutSession?.metadata?.teamName ?? generateRandomString(), teamSlug: checkoutSession?.metadata?.teamSlug ?? generateRandomString(), userId: checkoutSession.metadata.userId, + isOnboarding: checkoutSession.metadata.isOnboarding, }; const team = await prisma.team.create({ @@ -102,6 +105,16 @@ async function getHandler(req: NextRequest) { }); } + // Check if this is from onboarding flow and redirect accordingly + const isOnboarding = checkoutSessionMetadata.isOnboarding === "true"; + + if (isOnboarding) { + // Redirect to event-types for onboarding flow + return NextResponse.redirect(new URL("/onboarding/personal/settings", WEBAPP_URL), { + status: 302, + }); + } + // redirect to team screen return NextResponse.redirect( new URL(`/settings/teams/${team.id}/onboard-members?event=team_created`, req.nextUrl.origin), diff --git a/apps/web/modules/onboarding/hooks/useCreateTeam.ts b/apps/web/modules/onboarding/hooks/useCreateTeam.ts index 005514fc51..6cb0ef5144 100644 --- a/apps/web/modules/onboarding/hooks/useCreateTeam.ts +++ b/apps/web/modules/onboarding/hooks/useCreateTeam.ts @@ -24,6 +24,7 @@ export function useCreateTeam() { name: teamDetails.name, slug: teamDetails.slug, logo: teamBrand.logo, + isOnboarding: true, }); // If there's a checkout URL, redirect to Stripe payment diff --git a/packages/features/ee/teams/lib/payments.ts b/packages/features/ee/teams/lib/payments.ts index 4dc5f3a04c..79111c9af1 100644 --- a/packages/features/ee/teams/lib/payments.ts +++ b/packages/features/ee/teams/lib/payments.ts @@ -49,10 +49,12 @@ export const generateTeamCheckoutSession = async ({ teamName, teamSlug, userId, + isOnboarding, }: { teamName: string; teamSlug: string; userId: number; + isOnboarding?: boolean; }) => { const [customer, dubCustomer] = await Promise.all([ getStripeCustomerIdFromUserId(userId), @@ -98,6 +100,7 @@ export const generateTeamCheckoutSession = async ({ teamSlug, userId, dubCustomerId: userId, // pass the userId during checkout creation for sales conversion tracking: https://d.to/conversions/stripe + ...(isOnboarding !== undefined && { isOnboarding: isOnboarding.toString() }), }, }); return session; diff --git a/packages/trpc/server/routers/viewer/teams/create.handler.ts b/packages/trpc/server/routers/viewer/teams/create.handler.ts index 8dcbb87dfa..8a0caba944 100644 --- a/packages/trpc/server/routers/viewer/teams/create.handler.ts +++ b/packages/trpc/server/routers/viewer/teams/create.handler.ts @@ -22,10 +22,12 @@ const generateCheckoutSession = async ({ teamSlug, teamName, userId, + isOnboarding, }: { teamSlug: string; teamName: string; userId: number; + isOnboarding?: boolean; }) => { if (!IS_TEAM_BILLING_ENABLED) { console.info("Team billing is disabled, not generating a checkout session."); @@ -36,6 +38,7 @@ const generateCheckoutSession = async ({ teamSlug, teamName, userId, + isOnboarding, }); if (!checkoutSession.url) @@ -48,7 +51,7 @@ const generateCheckoutSession = async ({ export const createHandler = async ({ ctx, input }: CreateOptions) => { const { user } = ctx; - const { slug, name } = input; + const { slug, name, isOnboarding } = input; const isOrgChildTeam = !!user.profile?.organizationId; // For orgs we want to create teams under the org @@ -80,6 +83,7 @@ export const createHandler = async ({ ctx, input }: CreateOptions) => { teamSlug: slug, teamName: name, userId: user.id, + isOnboarding, }); // If there is a checkout session, return it. Otherwise, it means it's disabled. diff --git a/packages/trpc/server/routers/viewer/teams/create.schema.ts b/packages/trpc/server/routers/viewer/teams/create.schema.ts index 846228be2b..0bd67da017 100644 --- a/packages/trpc/server/routers/viewer/teams/create.schema.ts +++ b/packages/trpc/server/routers/viewer/teams/create.schema.ts @@ -10,6 +10,7 @@ export const ZCreateInputSchema = z.object({ .optional() .nullable() .transform((v) => v || null), + isOnboarding: z.boolean().optional(), }); export type TCreateInputSchema = z.infer;