diff --git a/apps/web/pages/api/teams/create.ts b/apps/web/pages/api/teams/create.ts
new file mode 100644
index 0000000000..b0c8935839
--- /dev/null
+++ b/apps/web/pages/api/teams/create.ts
@@ -0,0 +1,92 @@
+import type { NextApiRequest, NextApiResponse } from "next";
+import type Stripe from "stripe";
+import { z } from "zod";
+
+import stripe from "@calcom/features/ee/payments/server/stripe";
+import { HttpError } from "@calcom/lib/http-error";
+import { defaultHandler, defaultResponder } from "@calcom/lib/server";
+import prisma from "@calcom/prisma";
+import { MembershipRole } from "@calcom/prisma/enums";
+
+const querySchema = z.object({
+ session_id: z.string().min(1),
+});
+
+const checkoutSessionMetadataSchema = z.object({
+ teamName: z.string(),
+ teamSlug: z.string(),
+ userId: z.string().transform(Number),
+});
+
+const generateRandomString = () => {
+ return Math.random().toString(36).substring(2, 10);
+};
+
+async function handler(req: NextApiRequest, res: NextApiResponse) {
+ const { session_id } = querySchema.parse(req.query);
+
+ const checkoutSession = await stripe.checkout.sessions.retrieve(session_id, {
+ expand: ["subscription"],
+ });
+ if (!checkoutSession) throw new HttpError({ statusCode: 404, message: "Checkout session not found" });
+
+ const subscription = checkoutSession.subscription as Stripe.Subscription;
+
+ if (checkoutSession.payment_status !== "paid")
+ throw new HttpError({ statusCode: 402, message: "Payment required" });
+
+ // Let's query to ensure that the team metadata carried over from the checkout session.
+ const parseCheckoutSessionMetadata = checkoutSessionMetadataSchema.safeParse(checkoutSession.metadata);
+
+ if (!parseCheckoutSessionMetadata.success) {
+ console.error(
+ "Team metadata not found in checkout session",
+ parseCheckoutSessionMetadata.error,
+ checkoutSession.id
+ );
+ }
+
+ if (!checkoutSession.metadata?.userId) {
+ throw new HttpError({
+ statusCode: 400,
+ message: "Can't publish team/org without userId",
+ });
+ }
+
+ const checkoutSessionMetadata = parseCheckoutSessionMetadata.success
+ ? parseCheckoutSessionMetadata.data
+ : {
+ teamName: checkoutSession?.metadata?.teamName ?? generateRandomString(),
+ teamSlug: checkoutSession?.metadata?.teamSlug ?? generateRandomString(),
+ userId: checkoutSession.metadata.userId,
+ };
+
+ const team = await prisma.team.create({
+ data: {
+ name: checkoutSessionMetadata.teamName,
+ slug: checkoutSessionMetadata.teamSlug,
+ members: {
+ create: {
+ userId: checkoutSessionMetadata.userId as number,
+ role: MembershipRole.OWNER,
+ accepted: true,
+ },
+ },
+ metadata: {
+ paymentId: checkoutSession.id,
+ subscriptionId: subscription.id || null,
+ subscriptionItemId: subscription.items.data[0].id || null,
+ },
+ },
+ });
+
+ // Sync Services: Close.com
+ // closeComUpdateTeam(prevTeam, team);
+
+ // redirect to team screen
+ res.redirect(302, `/settings/teams/${team.id}/onboard-members?event=team_created`);
+}
+
+export default defaultHandler({
+ GET: Promise.resolve({ default: defaultResponder(handler) }),
+});
diff --git a/apps/web/playwright/auth/forgot-password.e2e.ts b/apps/web/playwright/auth/forgot-password.e2e.ts
index 0524a538e0..ad4d30aa3a 100644
--- a/apps/web/playwright/auth/forgot-password.e2e.ts
+++ b/apps/web/playwright/auth/forgot-password.e2e.ts
@@ -24,7 +24,7 @@ test("Can reset forgotten password", async ({ page, users }) => {
// there should be one, otherwise we throw
const { id } = await prisma.resetPasswordRequest.findFirstOrThrow({
where: {
- email: `${user.username}@example.com`,
+ email: user.email,
},
select: {
id: true,
@@ -37,7 +37,7 @@ test("Can reset forgotten password", async ({ page, users }) => {
// Test when a user changes his email after starting the password reset flow
await prisma.user.update({
where: {
- email: `${user.username}@example.com`,
+ email: user.email,
},
data: {
email: `${user.username}-2@example.com`,
@@ -54,7 +54,7 @@ test("Can reset forgotten password", async ({ page, users }) => {
email: `${user.username}-2@example.com`,
},
data: {
- email: `${user.username}@example.com`,
+ email: user.email,
},
});
@@ -75,7 +75,7 @@ test("Can reset forgotten password", async ({ page, users }) => {
// we're not logging in to the UI to speed up test performance.
const updatedUser = await prisma.user.findUniqueOrThrow({
where: {
- email: `${user.username}@example.com`,
+ email: user.email,
},
select: {
id: true,
@@ -84,10 +84,10 @@ test("Can reset forgotten password", async ({ page, users }) => {
});
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- await expect(await verifyPassword(newPassword, updatedUser.password!)).toBeTruthy();
+ expect(await verifyPassword(newPassword, updatedUser.password!)).toBeTruthy();
// finally, make sure the same URL cannot be used to reset the password again, as it should be expired.
await page.goto(`/auth/forgot-password/${id}`);
- await page.waitForSelector("text=That request is expired.");
+ await expect(page.locator(`text=Whoops`)).toBeVisible();
});
diff --git a/apps/web/playwright/lib/testUtils.ts b/apps/web/playwright/lib/testUtils.ts
index 1deefb206f..5bb711d71a 100644
--- a/apps/web/playwright/lib/testUtils.ts
+++ b/apps/web/playwright/lib/testUtils.ts
@@ -295,3 +295,11 @@ export function generateTotpCode(email: string) {
totp.options = { step: 90 };
return totp.generate(secret);
}
+
+export async function fillStripeTestCheckout(page: Page) {
+ await page.fill("[name=cardNumber]", "4242424242424242");
+ await page.fill("[name=cardExpiry]", "12/30");
+ await page.fill("[name=cardCvc]", "111");
+ await page.fill("[name=billingName]", "Stripe Stripeson");
+ await page.click(".SubmitButton--complete-Shimmer");
+}
diff --git a/apps/web/playwright/managed-event-types.e2e.ts b/apps/web/playwright/managed-event-types.e2e.ts
index a0323ed8b7..3db81e362c 100644
--- a/apps/web/playwright/managed-event-types.e2e.ts
+++ b/apps/web/playwright/managed-event-types.e2e.ts
@@ -1,9 +1,15 @@
-import { expect } from "@playwright/test";
import type { Page } from "@playwright/test";
+import { expect } from "@playwright/test";
+
+import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants";
import { test } from "./lib/fixtures";
-import { selectFirstAvailableTimeSlotNextMonth, bookTimeSlot } from "./lib/testUtils";
-import { localize } from "./lib/testUtils";
+import {
+ bookTimeSlot,
+ fillStripeTestCheckout,
+ localize,
+ selectFirstAvailableTimeSlotNextMonth,
+} from "./lib/testUtils";
test.afterEach(({ users }) => users.deleteAll());
@@ -21,18 +27,20 @@ test.describe("Managed Event Types tests", () => {
await test.step("Managed event option exists for team admin", async () => {
// Filling team creation form wizard
- await page.locator('input[name="name"]').waitFor();
await page.locator('input[name="name"]').fill(`${adminUser.username}'s Team`);
- await page.locator("text=Continue").click();
- await page.waitForURL(/\/settings\/teams\/(\d+)\/onboard-members$/i);
+ await page.click("[type=submit]");
+ // TODO: Figure out a way to make this more reliable
+ // eslint-disable-next-line playwright/no-conditional-in-test
+ if (IS_TEAM_BILLING_ENABLED) await fillStripeTestCheckout(page);
+ await page.waitForURL(/\/settings\/teams\/(\d+)\/onboard-members.*$/i);
await page.getByTestId("new-member-button").click();
await page.locator('[placeholder="email\\@example\\.com"]').fill(`${memberUser.username}@example.com`);
await page.getByTestId("invite-new-member-button").click();
// wait for the second member to be added to the pending-member-list.
await page.getByTestId("pending-member-list").locator("li:nth-child(2)").waitFor();
// and publish
- await page.locator("text=Publish team").click();
- await page.waitForURL("/settings/teams/**");
+ await page.locator("[data-testid=publish-button]").click();
+ await expect(page).toHaveURL(/\/settings\/teams\/(\d+)\/profile$/i);
// Going to create an event type
await page.goto("/event-types");
await page.getByTestId("new-event-type").click();
diff --git a/apps/web/playwright/teams.e2e.ts b/apps/web/playwright/teams.e2e.ts
index ba9f2960d6..4c8cae0bd5 100644
--- a/apps/web/playwright/teams.e2e.ts
+++ b/apps/web/playwright/teams.e2e.ts
@@ -1,34 +1,32 @@
import type { Page } from "@playwright/test";
import { expect } from "@playwright/test";
+import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants";
import { prisma } from "@calcom/prisma";
import { MembershipRole, SchedulingType } from "@calcom/prisma/enums";
import { test } from "./lib/fixtures";
-import { bookTimeSlot, selectFirstAvailableTimeSlotNextMonth, testName, todo } from "./lib/testUtils";
+import {
+ bookTimeSlot,
+ fillStripeTestCheckout,
+ selectFirstAvailableTimeSlotNextMonth,
+ testName,
+ todo,
+} from "./lib/testUtils";
test.describe.configure({ mode: "parallel" });
test.describe("Teams - NonOrg", () => {
test.afterEach(({ users }) => users.deleteAll());
- test("Can create teams via Wizard", async ({ page, users }) => {
- const user = await users.create();
- const inviteeEmail = `${user.username}+invitee@example.com`;
- await user.apiLogin();
- await page.goto("/teams");
- await test.step("Can create team", async () => {
- // Click text=Create Team
- await page.locator("text=Create Team").click();
- await page.waitForURL("/settings/teams/new");
- // Fill input[name="name"]
- await page.locator('input[name="name"]').fill(`${user.username}'s Team`);
- // Click text=Continue
- await page.locator("text=Continue").click();
- await page.waitForURL(/\/settings\/teams\/(\d+)\/onboard-members$/i);
- await page.waitForSelector('[data-testid="pending-member-list"]');
- expect(await page.locator('[data-testid="pending-member-item"]').count()).toBe(1);
- });
+ test("Team Onboarding Invite Members", async ({ page, users }) => {
+ const user = await users.create(undefined, { hasTeam: true });
+ const { team } = await user.getFirstTeam();
+ const inviteeEmail = `${user.username}+invitee@example.com`;
+
+ await user.apiLogin();
+
+ page.goto(`/settings/teams/${team.id}/onboard-members`);
await test.step("Can add members", async () => {
// Click [data-testid="new-member-button"]
@@ -50,9 +48,9 @@ test.describe("Teams - NonOrg", () => {
await prisma.user.delete({ where: { email: inviteeEmail } });
});
- await test.step("Can publish team", async () => {
- await page.locator("text=Publish team").click();
- await page.waitForURL(/\/settings\/teams\/(\d+)\/profile$/i);
+ await test.step("Finishing brings you to team profile page", async () => {
+ await page.locator("[data-testid=publish-button]").click();
+ await expect(page).toHaveURL(/\/settings\/teams\/(\d+)\/profile$/i);
});
await test.step("Can disband team", async () => {
@@ -66,7 +64,6 @@ test.describe("Teams - NonOrg", () => {
});
test("Can create a booking for Collective EventType", async ({ page, users }) => {
- const ownerObj = { username: "pro-user", name: "pro-user" };
const teamMatesObj = [
{ name: "teammate-1" },
{ name: "teammate-2" },
@@ -74,11 +71,14 @@ test.describe("Teams - NonOrg", () => {
{ name: "teammate-4" },
];
- const owner = await users.create(ownerObj, {
- hasTeam: true,
- teammates: teamMatesObj,
- schedulingType: SchedulingType.COLLECTIVE,
- });
+ const owner = await users.create(
+ { username: "pro-user", name: "pro-user" },
+ {
+ hasTeam: true,
+ teammates: teamMatesObj,
+ schedulingType: SchedulingType.COLLECTIVE,
+ }
+ );
const { team } = await owner.getFirstTeam();
const { title: teamEventTitle, slug: teamEventSlug } = await owner.getFirstTeamEvent(team.id);
@@ -102,18 +102,20 @@ test.describe("Teams - NonOrg", () => {
});
test("Can create a booking for Round Robin EventType", async ({ page, users }) => {
- const ownerObj = { username: "pro-user", name: "pro-user" };
const teamMatesObj = [
{ name: "teammate-1" },
{ name: "teammate-2" },
{ name: "teammate-3" },
{ name: "teammate-4" },
];
- const owner = await users.create(ownerObj, {
- hasTeam: true,
- teammates: teamMatesObj,
- schedulingType: SchedulingType.ROUND_ROBIN,
- });
+ const owner = await users.create(
+ { username: "pro-user", name: "pro-user" },
+ {
+ hasTeam: true,
+ teammates: teamMatesObj,
+ schedulingType: SchedulingType.ROUND_ROBIN,
+ }
+ );
const { team } = await owner.getFirstTeam();
const { title: teamEventTitle, slug: teamEventSlug } = await owner.getFirstTeamEvent(team.id);
@@ -134,7 +136,7 @@ test.describe("Teams - NonOrg", () => {
// Anyone of the teammates could be the Host of the booking.
const chosenUser = await page.getByTestId("booking-host-name").textContent();
expect(chosenUser).not.toBeNull();
- expect(teamMatesObj.concat([{ name: ownerObj.name }]).some(({ name }) => name === chosenUser)).toBe(true);
+ expect(teamMatesObj.concat([{ name: owner.name! }]).some(({ name }) => name === chosenUser)).toBe(true);
// TODO: Assert whether the user received an email
});
@@ -164,8 +166,7 @@ test.describe("Teams - NonOrg", () => {
await page.goto("/settings/teams/new");
// Fill input[name="name"]
await page.locator('input[name="name"]').fill(uniqueName);
- await page.locator("text=Continue").click();
- await expect(page.locator("[data-testid=alert]")).toBeVisible();
+ await page.click("[type=submit]");
// cleanup
const org = await owner.getOrgMembership();
@@ -174,11 +175,9 @@ test.describe("Teams - NonOrg", () => {
});
test("Can create team with same name as user", async ({ page, users }) => {
+ const user = await users.create();
// Name to be used for both user and team
- const uniqueName = "test-unique-name";
- const ownerObj = { username: uniqueName, name: uniqueName, useExactUsername: true };
-
- const user = await users.create(ownerObj);
+ const uniqueName = user.username!;
await user.apiLogin();
await page.goto("/teams");
@@ -189,11 +188,14 @@ test.describe("Teams - NonOrg", () => {
// Fill input[name="name"]
await page.locator('input[name="name"]').fill(uniqueName);
// Click text=Continue
- await page.locator("text=Continue").click();
- await page.waitForURL(/\/settings\/teams\/(\d+)\/onboard-members$/i);
+ await page.click("[type=submit]");
+ // TODO: Figure out a way to make this more reliable
+ // eslint-disable-next-line playwright/no-conditional-in-test
+ if (IS_TEAM_BILLING_ENABLED) await fillStripeTestCheckout(page);
+ await page.waitForURL(/\/settings\/teams\/(\d+)\/onboard-members.*$/i);
// Click text=Continue
- await page.locator("text=Publish team").click();
- await page.waitForURL(/\/settings\/teams\/(\d+)\/profile$/i);
+ await page.locator("[data-testid=publish-button]").click();
+ await expect(page).toHaveURL(/\/settings\/teams\/(\d+)\/profile$/i);
});
await test.step("Can access user and team with same slug", async () => {
@@ -210,13 +212,11 @@ test.describe("Teams - NonOrg", () => {
await expect(page.locator("[data-testid=name-title]")).toHaveText(uniqueName);
// cleanup team
- const team = await prisma.team.findFirst({ where: { slug: uniqueName } });
- await prisma.team.delete({ where: { id: team?.id } });
+ await prisma.team.deleteMany({ where: { slug: uniqueName } });
});
});
test("Can create a private team", async ({ page, users }) => {
- const ownerObj = { username: "pro-user", name: "pro-user" };
const teamMatesObj = [
{ name: "teammate-1" },
{ name: "teammate-2" },
@@ -224,11 +224,14 @@ test.describe("Teams - NonOrg", () => {
{ name: "teammate-4" },
];
- const owner = await users.create(ownerObj, {
- hasTeam: true,
- teammates: teamMatesObj,
- schedulingType: SchedulingType.COLLECTIVE,
- });
+ const owner = await users.create(
+ { username: "pro-user", name: "pro-user" },
+ {
+ hasTeam: true,
+ teammates: teamMatesObj,
+ schedulingType: SchedulingType.COLLECTIVE,
+ }
+ );
await owner.apiLogin();
const { team } = await owner.getFirstTeam();
@@ -278,45 +281,43 @@ test.describe("Teams - Org", () => {
// Fill input[name="name"]
await page.locator('input[name="name"]').fill(`${user.username}'s Team`);
// Click text=Continue
- await page.locator("text=Continue").click();
- await page.waitForURL(/\/settings\/teams\/(\d+)\/onboard-members$/i);
+ await page.click("[type=submit]");
+ // TODO: Figure out a way to make this more reliable
+ // eslint-disable-next-line playwright/no-conditional-in-test
+ if (IS_TEAM_BILLING_ENABLED) await fillStripeTestCheckout(page);
+ await expect(page).toHaveURL(/\/settings\/teams\/(\d+)\/onboard-members.*$/i);
await page.waitForSelector('[data-testid="pending-member-list"]');
- expect(await page.locator('[data-testid="pending-member-item"]').count()).toBe(1);
+ expect(await page.getByTestId("pending-member-item").count()).toBe(1);
});
await test.step("Can add members", async () => {
- // Click [data-testid="new-member-button"]
- await page.locator('[data-testid="new-member-button"]').click();
- // Fill [placeholder="email\@example\.com"]
+ await page.getByTestId("new-member-button").click();
await page.locator('[placeholder="email\\@example\\.com"]').fill(inviteeEmail);
- // Click [data-testid="invite-new-member-button"]
- await page.locator('[data-testid="invite-new-member-button"]').click();
+ await page.getByTestId("invite-new-member-button").click();
await expect(page.locator(`li:has-text("${inviteeEmail}")`)).toBeVisible();
- expect(await page.locator('[data-testid="pending-member-item"]').count()).toBe(2);
+ expect(await page.getByTestId("pending-member-item").count()).toBe(2);
});
await test.step("Can remove members", async () => {
- expect(await page.locator('[data-testid="pending-member-item"]').count()).toBe(2);
-
- const lastRemoveMemberButton = page.locator('[data-testid="remove-member-button"]').last();
+ expect(await page.getByTestId("pending-member-item").count()).toBe(2);
+ const lastRemoveMemberButton = page.getByTestId("remove-member-button").last();
await lastRemoveMemberButton.click();
await page.waitForLoadState("networkidle");
- expect(await page.locator('[data-testid="pending-member-item"]').count()).toBe(1);
+ expect(await page.getByTestId("pending-member-item").count()).toBe(1);
// Cleanup here since this user is created without our fixtures.
await prisma.user.delete({ where: { email: inviteeEmail } });
});
await test.step("Can finish team creation", async () => {
- await page.locator("text=Finish").click();
- await page.waitForURL("/settings/teams");
+ await page.getByTestId("publish-button").click();
+ await expect(page).toHaveURL(/\/settings\/teams\/(\d+)\/profile$/i);
});
await test.step("Can disband team", async () => {
- await page.locator('[data-testid="team-list-item-link"]').click();
await page.waitForURL(/\/settings\/teams\/(\d+)\/profile$/i);
- await page.locator("text=Disband Team").click();
- await page.locator("text=Yes, disband team").click();
+ await page.getByTestId("disband-team-button").click();
+ await page.getByTestId("dialog-confirmation").click();
await page.waitForURL("/teams");
expect(await page.locator(`text=${user.username}'s Team`).count()).toEqual(0);
});
@@ -361,13 +362,13 @@ test.describe("Teams - Org", () => {
await page.goto(`/team/${team.slug}/${teamEventSlug}`);
await selectFirstAvailableTimeSlotNextMonth(page);
await bookTimeSlot(page);
- await expect(page.locator("[data-testid=success-page]")).toBeVisible();
+ await expect(page.getByTestId("success-page")).toBeVisible();
// The title of the booking
const BookingTitle = `${teamEventTitle} between ${team.name} and ${testName}`;
- await expect(page.locator("[data-testid=booking-title]")).toHaveText(BookingTitle);
+ await expect(page.getByTestId("booking-title")).toHaveText(BookingTitle);
// The booker should be in the attendee list
- await expect(page.locator(`[data-testid="attendee-name-${testName}"]`)).toHaveText(testName);
+ await expect(page.getByTestId(`attendee-name-${testName}`)).toHaveText(testName);
// All the teammates should be in the booking
for (const teammate of teamMatesObj.concat([{ name: owner.name || "" }])) {
@@ -380,18 +381,20 @@ test.describe("Teams - Org", () => {
});
test("Can create a booking for Round Robin EventType", async ({ page, users }) => {
- const ownerObj = { username: "pro-user", name: "pro-user" };
const teamMatesObj = [
{ name: "teammate-1" },
{ name: "teammate-2" },
{ name: "teammate-3" },
{ name: "teammate-4" },
];
- const owner = await users.create(ownerObj, {
- hasTeam: true,
- teammates: teamMatesObj,
- schedulingType: SchedulingType.ROUND_ROBIN,
- });
+ const owner = await users.create(
+ { username: "pro-user", name: "pro-user" },
+ {
+ hasTeam: true,
+ teammates: teamMatesObj,
+ schedulingType: SchedulingType.ROUND_ROBIN,
+ }
+ );
const { team } = await owner.getFirstTeam();
const { title: teamEventTitle, slug: teamEventSlug } = await owner.getFirstTeamEvent(team.id);
@@ -402,17 +405,17 @@ test.describe("Teams - Org", () => {
await expect(page.locator("[data-testid=success-page]")).toBeVisible();
// The person who booked the meeting should be in the attendee list
- await expect(page.locator(`[data-testid="attendee-name-${testName}"]`)).toHaveText(testName);
+ await expect(page.getByTestId(`attendee-name-${testName}`)).toHaveText(testName);
// The title of the booking
const BookingTitle = `${teamEventTitle} between ${team.name} and ${testName}`;
- await expect(page.locator("[data-testid=booking-title]")).toHaveText(BookingTitle);
+ await expect(page.getByTestId("booking-title")).toHaveText(BookingTitle);
// Since all the users have the same leastRecentlyBooked value
// Anyone of the teammates could be the Host of the booking.
const chosenUser = await page.getByTestId("booking-host-name").textContent();
expect(chosenUser).not.toBeNull();
- expect(teamMatesObj.concat([{ name: ownerObj.name }]).some(({ name }) => name === chosenUser)).toBe(true);
+ expect(teamMatesObj.concat([{ name: owner.name! }]).some(({ name }) => name === chosenUser)).toBe(true);
// TODO: Assert whether the user received an email
});
});
diff --git a/packages/features/ee/teams/components/AddNewTeamMembers.tsx b/packages/features/ee/teams/components/AddNewTeamMembers.tsx
index 750f8ecbae..da444655da 100644
--- a/packages/features/ee/teams/components/AddNewTeamMembers.tsx
+++ b/packages/features/ee/teams/components/AddNewTeamMembers.tsx
@@ -1,6 +1,6 @@
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
import InviteLinkSettingsModal from "@calcom/features/ee/teams/components/InviteLinkSettingsModal";
@@ -10,6 +10,7 @@ import { APP_NAME, WEBAPP_URL } from "@calcom/lib/constants";
import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { useTelemetry, telemetryEventTypes } from "@calcom/lib/telemetry";
import { MembershipRole } from "@calcom/prisma/enums";
import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
@@ -33,11 +34,21 @@ type FormValues = {
const AddNewTeamMembers = () => {
const searchParams = useCompatSearchParams();
const session = useSession();
+ const telemetry = useTelemetry();
+
const teamId = searchParams?.get("id") ? Number(searchParams.get("id")) : -1;
const teamQuery = trpc.viewer.teams.get.useQuery(
{ teamId },
{ enabled: session.status === "authenticated" }
);
+
+ useEffect(() => {
+ const event = searchParams?.get("event");
+ if (event === "team_created") {
+ telemetry.event(telemetryEventTypes.team_created);
+ }
+ }, []);
+
if (session.status === "loading" || !teamQuery.data) return