Deprecates user plan (#5942)
* Remove isMissingSeat * Removes user plan * Deprecates User Plan * Updates website * Update eventTypes.tsx
This commit is contained in:
parent
5e86881e15
commit
e832015f26
|
@ -29,10 +29,7 @@ import { trpc } from "@calcom/trpc/react";
|
|||
import { Icon, DatePicker } from "@calcom/ui";
|
||||
|
||||
import { timeZone as localStorageTimeZone } from "@lib/clock";
|
||||
// import { timeZone } from "@lib/clock";
|
||||
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
|
||||
import useRouterQuery from "@lib/hooks/useRouterQuery";
|
||||
import { isBrandingHidden } from "@lib/isBrandingHidden";
|
||||
|
||||
import Gates, { Gate, GateState } from "@components/Gates";
|
||||
import AvailableTimes from "@components/booking/AvailableTimes";
|
||||
|
@ -280,9 +277,6 @@ const AvailabilityPage = ({ profile, eventType, ...restProps }: Props) => {
|
|||
setTimeZone(localStorageTimeZone() || dayjs.tz.guess());
|
||||
}, []);
|
||||
|
||||
// TODO: Improve this;
|
||||
useExposePlanGlobally(eventType.users.length === 1 ? eventType.users[0].plan : "PRO");
|
||||
|
||||
const [recurringEventCount, setRecurringEventCount] = useState(eventType.recurringEvent?.count);
|
||||
|
||||
const telemetry = useTelemetry();
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
/**
|
||||
* TODO: It should be exposed at a single place.
|
||||
*/
|
||||
export function useExposePlanGlobally(plan: UserPlan) {
|
||||
// Don't wait for component to mount. Do it ASAP. Delaying it would delay UI Configuration.
|
||||
if (typeof window !== "undefined") {
|
||||
// This variable is used by embed-iframe to determine if we should allow UI configuration
|
||||
window.CalComPlan = plan;
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ import { baseEventTypeSelect } from "@calcom/prisma/selects";
|
|||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { BadgeCheckIcon, EventTypeDescriptionLazy as EventTypeDescription, Icon } from "@calcom/ui";
|
||||
|
||||
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
import { EmbedProps } from "@lib/withEmbedSsr";
|
||||
|
||||
|
@ -92,7 +91,6 @@ export default function User(props: inferSSRProps<typeof getServerSideProps> & E
|
|||
const shouldAlignCentrally = !isEmbed || shouldAlignCentrallyInEmbed;
|
||||
const query = { ...router.query };
|
||||
delete query.user; // So it doesn't display in the Link (and make tests fail)
|
||||
useExposePlanGlobally("PRO");
|
||||
const nameOrUsername = user.name || user.username || "";
|
||||
const telemetry = useTelemetry();
|
||||
|
||||
|
@ -272,7 +270,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
darkBrandColor: true,
|
||||
avatar: true,
|
||||
theme: true,
|
||||
plan: true,
|
||||
away: true,
|
||||
verified: true,
|
||||
allowDynamicBooking: true,
|
||||
|
|
|
@ -72,7 +72,6 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
|||
id: true,
|
||||
username: true,
|
||||
away: true,
|
||||
plan: true,
|
||||
name: true,
|
||||
hideBranding: true,
|
||||
timeZone: true,
|
||||
|
@ -130,7 +129,7 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
|||
if (!user || !user.eventTypes.length) return { notFound: true };
|
||||
|
||||
const [eventType]: (typeof user.eventTypes[number] & {
|
||||
users: Pick<User, "name" | "username" | "hideBranding" | "plan" | "timeZone">[];
|
||||
users: Pick<User, "name" | "username" | "hideBranding" | "timeZone">[];
|
||||
})[] = [
|
||||
{
|
||||
...user.eventTypes[0],
|
||||
|
@ -139,7 +138,6 @@ async function getUserPageProps(context: GetStaticPropsContext) {
|
|||
name: user.name,
|
||||
username: user.username,
|
||||
hideBranding: user.hideBranding,
|
||||
plan: user.plan,
|
||||
timeZone: user.timeZone,
|
||||
},
|
||||
],
|
||||
|
@ -226,7 +224,6 @@ async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
|
|||
},
|
||||
},
|
||||
theme: true,
|
||||
plan: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -246,7 +243,6 @@ async function getDynamicGroupPageProps(context: GetStaticPropsContext) {
|
|||
name: user.name,
|
||||
username: user.username,
|
||||
hideBranding: user.hideBranding,
|
||||
plan: user.plan,
|
||||
timeZone: user.timeZone,
|
||||
};
|
||||
}),
|
||||
|
|
|
@ -46,7 +46,6 @@ async function handler(req: NextApiRequest) {
|
|||
name: parsedQuery.data.full_name,
|
||||
emailVerified: new Date(),
|
||||
locale: "en", // TODO: We should revisit this
|
||||
plan: "PRO",
|
||||
identityProvider: IdentityProvider.CAL,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { TRIAL_LIMIT_DAYS } from "@lib/config/constants";
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
const apiKey = req.headers.authorization || req.query.apiKey;
|
||||
if (process.env.CRON_API_KEY !== apiKey) {
|
||||
|
@ -18,35 +13,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
|
||||
/**
|
||||
* TODO:
|
||||
* We should add and extra check for non-paying customers in Stripe so we can
|
||||
* downgrade them here.
|
||||
* Remove this endpoint
|
||||
*/
|
||||
|
||||
await prisma.user.updateMany({
|
||||
data: {
|
||||
plan: "FREE",
|
||||
},
|
||||
where: {
|
||||
plan: "TRIAL",
|
||||
OR: [
|
||||
/**
|
||||
* If the user doesn't have a trial end date,
|
||||
* use the default 14 day trial from creation.
|
||||
*/
|
||||
{
|
||||
createdDate: {
|
||||
lt: dayjs().subtract(TRIAL_LIMIT_DAYS, "day").toDate(),
|
||||
},
|
||||
trialEndsAt: null,
|
||||
},
|
||||
/** If it does, then honor the trial end date. */
|
||||
{
|
||||
trialEndsAt: {
|
||||
lt: dayjs().toDate(),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
res.json({ ok: true });
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
select: {
|
||||
username: true,
|
||||
id: true,
|
||||
plan: true,
|
||||
createdDate: true,
|
||||
},
|
||||
});
|
||||
|
@ -81,7 +80,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
? new Date(lastBooking.booking.createdAt).toLocaleDateString("en-US")
|
||||
: "No info"
|
||||
}</li>
|
||||
<li><b>Plan:</b> ${user.plan}</li>
|
||||
<li><b>Account created:</b> ${new Date(user.createdDate).toLocaleDateString("en-US")}</li>
|
||||
</ul>
|
||||
`,
|
||||
|
|
|
@ -858,7 +858,6 @@ const getEventTypesFromDB = async (id: number) => {
|
|||
name: true,
|
||||
username: true,
|
||||
hideBranding: true,
|
||||
plan: true,
|
||||
theme: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
|
|
|
@ -90,7 +90,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
},
|
||||
},
|
||||
theme: true,
|
||||
plan: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -117,7 +116,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
name: u.name,
|
||||
username: u.username,
|
||||
hideBranding: u.hideBranding,
|
||||
plan: u.plan,
|
||||
timeZone: u.timeZone,
|
||||
})),
|
||||
});
|
||||
|
@ -158,7 +156,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
away: user.away,
|
||||
isDynamicGroup: false,
|
||||
profile,
|
||||
plan: user.plan,
|
||||
date,
|
||||
eventType: eventTypeObject,
|
||||
workingHours,
|
||||
|
|
|
@ -341,7 +341,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
id: true,
|
||||
avatar: true,
|
||||
email: true,
|
||||
plan: true,
|
||||
locale: true,
|
||||
defaultScheduleId: true,
|
||||
});
|
||||
|
|
|
@ -164,7 +164,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
weekStart: true,
|
||||
hideBranding: true,
|
||||
theme: true,
|
||||
plan: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
metadata: true,
|
||||
|
|
|
@ -36,7 +36,6 @@ const CtaRow = ({ title, description, className, children }: CtaRowProps) => {
|
|||
const BillingView = () => {
|
||||
const { t } = useLocale();
|
||||
const { data: user } = trpc.viewer.me.useQuery();
|
||||
const isPro = user?.plan === "PRO";
|
||||
const [, loadChat] = useChat();
|
||||
const [showChat, setShowChat] = useState(false);
|
||||
const router = useRouter();
|
||||
|
@ -53,14 +52,9 @@ const BillingView = () => {
|
|||
<Meta title={t("billing")} description={t("manage_billing_description")} />
|
||||
<div className="space-y-6 text-sm sm:space-y-8">
|
||||
<CtaRow
|
||||
className={classNames(!isPro && "pointer-events-none opacity-30")}
|
||||
title={t("billing_manage_details_title")}
|
||||
description={t("billing_manage_details_description")}>
|
||||
<Button
|
||||
color={isPro ? "primary" : "secondary"}
|
||||
href={billingHref}
|
||||
target="_blank"
|
||||
EndIcon={Icon.FiExternalLink}>
|
||||
<Button color="primary" href={billingHref} target="_blank" EndIcon={Icon.FiExternalLink}>
|
||||
{t("billing_portal")}
|
||||
</Button>
|
||||
</CtaRow>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { UserPlan } from "@prisma/client";
|
||||
import classNames from "classnames";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
import Link from "next/link";
|
||||
|
@ -14,7 +13,6 @@ import { getTeamWithMembers } from "@calcom/lib/server/queries/teams";
|
|||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||
import { Avatar, Button, EventTypeDescription, Icon } from "@calcom/ui";
|
||||
|
||||
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
|
||||
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
|
||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||
|
||||
|
@ -27,7 +25,6 @@ function TeamPage({ team }: TeamPageProps) {
|
|||
useTheme();
|
||||
const showMembers = useToggleQuery("members");
|
||||
const { t } = useLocale();
|
||||
useExposePlanGlobally("PRO");
|
||||
const isEmbed = useIsEmbed();
|
||||
const telemetry = useTelemetry();
|
||||
const router = useRouter();
|
||||
|
@ -137,10 +134,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
|
||||
if (!team) return { notFound: true } as { notFound: true };
|
||||
|
||||
const members = team.members.filter((member) => member.plan !== UserPlan.FREE);
|
||||
|
||||
team.members = members ?? [];
|
||||
|
||||
team.eventTypes = team.eventTypes.map((type) => ({
|
||||
...type,
|
||||
users: type.users.map((user) => ({
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { UserPlan } from "@prisma/client";
|
||||
import { GetServerSidePropsContext } from "next";
|
||||
|
||||
import { privacyFilteredLocations, LocationObject } from "@calcom/core/location";
|
||||
|
@ -60,7 +59,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
username: true,
|
||||
timeZone: true,
|
||||
hideBranding: true,
|
||||
plan: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
},
|
||||
|
@ -130,7 +128,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
name: user.name,
|
||||
username: user.username,
|
||||
hideBranding: user.hideBranding,
|
||||
plan: user.plan,
|
||||
timeZone: user.timeZone,
|
||||
})),
|
||||
});
|
||||
|
@ -144,8 +141,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
|
||||
return {
|
||||
props: {
|
||||
// Team is always pro
|
||||
plan: "PRO" as UserPlan,
|
||||
profile: {
|
||||
name: team.name || team.slug,
|
||||
slug: team.slug,
|
||||
|
|
|
@ -13,7 +13,7 @@ test.describe.configure({ mode: "parallel" });
|
|||
|
||||
test.describe("free user", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const free = await users.create({ plan: "FREE" });
|
||||
const free = await users.create();
|
||||
await page.goto(`/${free.username}`);
|
||||
});
|
||||
test.afterEach(async ({ users }) => {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { expect } from "@playwright/test";
|
||||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
import { getPremiumMonthlyPlanPriceId } from "@calcom/app-store/stripepayment/lib/utils";
|
||||
import stripe from "@calcom/features/ee/payments/server/stripe";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
test("dynamic booking", async ({ page, users }) => {
|
||||
const pro = await users.create();
|
||||
await pro.login();
|
||||
const free = await users.create({ plan: "FREE" });
|
||||
const free = await users.create({ username: "free" });
|
||||
await page.goto(`/${pro.username}+${free.username}`);
|
||||
|
||||
await test.step("book an event first day in next month", async () => {
|
||||
|
|
|
@ -120,37 +120,7 @@ test.describe("Event Types tests", () => {
|
|||
});
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const toast = await page.waitForSelector("div[class*='data-testid-toast-success']");
|
||||
await expect(toast).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("free user", () => {
|
||||
test.beforeEach(async ({ page, users }) => {
|
||||
const free = await users.create({ plan: "FREE" });
|
||||
await free.login();
|
||||
await page.goto("/event-types");
|
||||
// We wait until loading is finished
|
||||
await page.waitForSelector('[data-testid="event-types"]');
|
||||
});
|
||||
|
||||
test("has at least 2 events where first is enabled", async ({ page }) => {
|
||||
const $eventTypes = page.locator("[data-testid=event-types] > li a");
|
||||
const count = await $eventTypes.count();
|
||||
expect(count).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
test("edit first event", async ({ page }) => {
|
||||
const $eventTypes = page.locator("[data-testid=event-types] > li a");
|
||||
const firstEventTypeElement = $eventTypes.first();
|
||||
await firstEventTypeElement.click();
|
||||
await page.waitForNavigation({
|
||||
url: (url) => {
|
||||
return !!url.pathname.match(/\/event-types\/.+/);
|
||||
},
|
||||
});
|
||||
await page.locator("[data-testid=update-eventtype]").click();
|
||||
const toast = await page.waitForSelector("div[class*='data-testid-toast-success']");
|
||||
await expect(toast).toBeTruthy();
|
||||
expect(toast).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { Page, WorkerInfo } from "@playwright/test";
|
||||
import type Prisma from "@prisma/client";
|
||||
import { Prisma as PrismaType, UserPlan } from "@prisma/client";
|
||||
import { Prisma as PrismaType } from "@prisma/client";
|
||||
import { hash } from "bcryptjs";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
@ -238,7 +238,7 @@ const createUserFixture = (user: UserWithIncludes, page: Page) => {
|
|||
};
|
||||
};
|
||||
|
||||
type CustomUserOptsKeys = "username" | "password" | "plan" | "completedOnboarding" | "locale" | "name";
|
||||
type CustomUserOptsKeys = "username" | "password" | "completedOnboarding" | "locale" | "name";
|
||||
type CustomUserOpts = Partial<Pick<Prisma.User, CustomUserOptsKeys>> & { timeZone?: TimeZoneEnum };
|
||||
|
||||
// creates the actual user in the db.
|
||||
|
@ -247,13 +247,10 @@ const createUser = async (
|
|||
opts?: CustomUserOpts | null
|
||||
): Promise<PrismaType.UserCreateInput> => {
|
||||
// build a unique name for our user
|
||||
const uname = `${opts?.username ?? opts?.plan?.toLocaleLowerCase() ?? UserPlan.PRO.toLowerCase()}-${
|
||||
workerInfo.workerIndex
|
||||
}-${Date.now()}`;
|
||||
const uname = `${opts?.username}-${workerInfo.workerIndex}-${Date.now()}`;
|
||||
return {
|
||||
username: uname,
|
||||
name: opts?.name === undefined ? (opts?.plan ?? UserPlan.PRO).toUpperCase() : opts?.name,
|
||||
plan: opts?.plan ?? UserPlan.PRO,
|
||||
name: opts?.name,
|
||||
email: `${uname}@example.com`,
|
||||
password: await hashPassword(uname),
|
||||
emailVerified: new Date(),
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { expect } from "@playwright/test";
|
||||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
import { login } from "./fixtures/users";
|
||||
import { test } from "./lib/fixtures";
|
||||
|
@ -13,10 +12,10 @@ test.describe("user can login & logout succesfully", async () => {
|
|||
test.afterAll(async ({ users }) => {
|
||||
await users.deleteAll();
|
||||
});
|
||||
test("login flow TRAIL user & logout using dashboard", async ({ page, users }) => {
|
||||
test("login flow user & logout using dashboard", async ({ page, users }) => {
|
||||
// log in trail user
|
||||
await test.step("Log in", async () => {
|
||||
const user = await users.create({ plan: UserPlan.TRIAL });
|
||||
const user = await users.create();
|
||||
await user.login();
|
||||
|
||||
const shellLocator = page.locator(`[data-testid=dashboard-shell]`);
|
||||
|
@ -24,11 +23,6 @@ test.describe("user can login & logout succesfully", async () => {
|
|||
// expects the home page for an authorized user
|
||||
await page.goto("/");
|
||||
await expect(shellLocator).toBeVisible();
|
||||
|
||||
// Asserts to read the tested plan
|
||||
const planLocator = shellLocator.locator(`[data-testid=plan-trial]`);
|
||||
await expect(planLocator).toBeVisible();
|
||||
await expect(planLocator).toHaveText("-TRIAL");
|
||||
});
|
||||
|
||||
//
|
||||
|
@ -64,27 +58,6 @@ test.describe("Login and logout tests", () => {
|
|||
await expect(page.locator(`[data-testid=login-form]`)).toBeVisible();
|
||||
});
|
||||
|
||||
// Test login with all plans
|
||||
const plans = [UserPlan.PRO, UserPlan.FREE];
|
||||
plans.forEach((plan) => {
|
||||
test(`Should login with a ${plan} account`, async ({ page, users }) => {
|
||||
// Create user and login
|
||||
const user = await users.create({ plan });
|
||||
await user.login();
|
||||
|
||||
const shellLocator = page.locator(`[data-testid=dashboard-shell]`);
|
||||
|
||||
// expects the home page for an authorized user
|
||||
await page.goto("/");
|
||||
await expect(shellLocator).toBeVisible();
|
||||
|
||||
// Asserts to read the tested plan
|
||||
const planLocator = shellLocator.locator(`[data-testid=plan-${plan.toLowerCase()}]`);
|
||||
await expect(planLocator).toBeVisible();
|
||||
await expect(planLocator).toHaveText(`-${plan}`);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("Login flow validations", async () => {
|
||||
test("Should warn when user does not exist", async ({ page }) => {
|
||||
const alertMessage = (await localize("en"))("no_account_exists");
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable playwright/no-skipped-test */
|
||||
import { expect } from "@playwright/test";
|
||||
import { UserPlan } from "@prisma/client";
|
||||
|
||||
import { test } from "./lib/fixtures";
|
||||
|
||||
|
@ -9,7 +8,7 @@ test.describe.configure({ mode: "serial" });
|
|||
test.describe("Onboarding", () => {
|
||||
test.describe("Onboarding v2", () => {
|
||||
test("Onboarding Flow", async ({ page, users }) => {
|
||||
const user = await users.create({ plan: UserPlan.TRIAL, completedOnboarding: false, name: null });
|
||||
const user = await users.create({ completedOnboarding: false, name: null });
|
||||
await user.login();
|
||||
|
||||
// tests whether the user makes it to /getting-started
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between PRO and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"PRO","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","seatsShowAttendees":false,"uid":"[redacted/dynamic]","videoCallData":"[redacted/dynamic]","appsStatus":"[redacted/dynamic]","eventTitle":"30 min","eventDescription":null,"price":0,"currency":"usd","length":30,"bookingId":"[redacted/dynamic]","metadata":{},"status":"ACCEPTED","additionalInformation":"[redacted/dynamic]"}}
|
||||
{"triggerEvent":"BOOKING_CREATED","createdAt":"[redacted/dynamic]","payload":{"type":"30 min","title":"30 min between Nameless and Test Testson","description":"","additionalNotes":"","customInputs":{},"startTime":"[redacted/dynamic]","endTime":"[redacted/dynamic]","organizer":{"name":"Nameless","email":"[redacted/dynamic]","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"},"attendees":[{"email":"test@example.com","name":"Test Testson","timeZone":"[redacted/dynamic]","language":"[redacted/dynamic]"}],"location":"[redacted/dynamic]","destinationCalendar":null,"hideCalendarNotes":false,"requiresConfirmation":"[redacted/dynamic]","eventTypeId":"[redacted/dynamic]","seatsShowAttendees":false,"uid":"[redacted/dynamic]","videoCallData":"[redacted/dynamic]","appsStatus":"[redacted/dynamic]","eventTitle":"30 min","eventDescription":null,"price":0,"currency":"usd","length":30,"bookingId":"[redacted/dynamic]","metadata":{},"status":"ACCEPTED","additionalInformation":"[redacted/dynamic]"}}
|
|
@ -1 +1 @@
|
|||
Subproject commit 925f81ed92ee54cb1512c2836077e06d68c95123
|
||||
Subproject commit 30cbf3990bb5baae7fd4fd46c93f6e5bc402f84c
|
|
@ -14,8 +14,6 @@ import { AppGetServerSidePropsContext, AppPrisma } from "@calcom/types/AppGetSer
|
|||
import { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
import { Button, showToast } from "@calcom/ui";
|
||||
|
||||
import { useExposePlanGlobally } from "@lib/hooks/useExposePlanGlobally";
|
||||
|
||||
import FormInputFields from "../../components/FormInputFields";
|
||||
import { getSerializableForm } from "../../lib/getSerializableForm";
|
||||
import { processRoute } from "../../lib/processRoute";
|
||||
|
@ -26,7 +24,6 @@ function RoutingForm({ form, profile, ...restProps }: inferSSRProps<typeof getSe
|
|||
const formFillerIdRef = useRef(uuidv4());
|
||||
const isEmbed = useIsEmbed(restProps.isEmbed);
|
||||
useTheme(profile.theme);
|
||||
useExposePlanGlobally(profile.plan);
|
||||
// TODO: We might want to prevent spam from a single user by having same formFillerId across pageviews
|
||||
// But technically, a user can fill form multiple times due to any number of reasons and we currently can't differentiate b/w that.
|
||||
// - like a network error
|
||||
|
@ -183,7 +180,6 @@ export const getServerSideProps = async function getServerSideProps(
|
|||
theme: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
plan: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -202,7 +198,6 @@ export const getServerSideProps = async function getServerSideProps(
|
|||
theme: form.user.theme,
|
||||
brandColor: form.user.brandColor,
|
||||
darkBrandColor: form.user.darkBrandColor,
|
||||
plan: form.user.plan,
|
||||
},
|
||||
form: getSerializableForm(form),
|
||||
},
|
||||
|
|
|
@ -29,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
|
||||
const userData = await prisma.user.findFirst({
|
||||
where: { id: userId },
|
||||
select: { id: true, plan: true, metadata: true },
|
||||
select: { id: true, metadata: true },
|
||||
});
|
||||
if (!userData) {
|
||||
res.status(404).json({ message: "Missing user data" });
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
#!/usr/bin/env ts-node
|
||||
// To run this script: `yarn downgrade 2>&1 | tee result.log`
|
||||
import { Prisma, UserPlan } from "@prisma/client";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { TRIAL_LIMIT_DAYS } from "@calcom/lib/constants";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
import { getStripeCustomerIdFromUserId } from "./customer";
|
||||
import stripe from "./server";
|
||||
|
||||
/**
|
||||
* Deprecated or should be updated
|
||||
*/
|
||||
export async function downgradeIllegalProUsers() {
|
||||
const illegalProUsers = await prisma.user.findMany({
|
||||
where: {
|
||||
plan: UserPlan.PRO,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
username: true,
|
||||
plan: true,
|
||||
metadata: true,
|
||||
},
|
||||
});
|
||||
const usersDowngraded: Partial<typeof illegalProUsers[number]>[] = [];
|
||||
const downgrade = async (user: typeof illegalProUsers[number]) => {
|
||||
await prisma.user.update({
|
||||
where: { id: user.id },
|
||||
data: {
|
||||
plan: UserPlan.TRIAL,
|
||||
trialEndsAt: dayjs().add(TRIAL_LIMIT_DAYS, "day").toDate(),
|
||||
},
|
||||
});
|
||||
console.log(`Downgraded: ${user.email}`);
|
||||
usersDowngraded.push({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
plan: user.plan,
|
||||
metadata: user.metadata,
|
||||
});
|
||||
};
|
||||
for (const suspectUser of illegalProUsers) {
|
||||
console.log(`Checking: ${suspectUser.email}`);
|
||||
const metadata = (suspectUser.metadata as Prisma.JsonObject) ?? {};
|
||||
// if their pro is already sponsored by a team, do not downgrade
|
||||
if (metadata.proPaidForByTeamId !== undefined) continue;
|
||||
|
||||
const stripeCustomerId = await getStripeCustomerIdFromUserId(suspectUser.id);
|
||||
const customer = await stripe.customers.retrieve(stripeCustomerId, {
|
||||
expand: ["subscriptions.data.plan"],
|
||||
});
|
||||
if (!customer || customer.deleted) {
|
||||
await downgrade(suspectUser);
|
||||
continue;
|
||||
}
|
||||
|
||||
const subscription = customer.subscriptions?.data[0];
|
||||
if (!subscription) {
|
||||
await downgrade(suspectUser);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If they already have a premium username, do not downgrade
|
||||
// if (suspectUser.username && isPremiumUserName(suspectUser.username)) continue;
|
||||
|
||||
await downgrade(suspectUser);
|
||||
}
|
||||
return {
|
||||
usersDowngraded,
|
||||
usersDowngradedAmount: usersDowngraded.length,
|
||||
};
|
||||
}
|
||||
|
||||
downgradeIllegalProUsers()
|
||||
.then(({ usersDowngraded, usersDowngradedAmount }) => {
|
||||
console.log(`Downgraded ${usersDowngradedAmount} illegal pro users`);
|
||||
console.table(usersDowngraded);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
|
@ -780,7 +780,7 @@ async function handler(req: NextApiRequest & { userId?: number | undefined }) {
|
|||
await syncServicesUpdateWebUser(
|
||||
await prisma.user.findFirst({
|
||||
where: { id: userId },
|
||||
select: { id: true, email: true, name: true, plan: true, username: true, createdDate: true },
|
||||
select: { id: true, email: true, name: true, username: true, createdDate: true },
|
||||
})
|
||||
);
|
||||
evt.uid = booking?.uid ?? null;
|
||||
|
|
|
@ -58,7 +58,6 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
|||
name: true,
|
||||
username: true,
|
||||
hideBranding: true,
|
||||
plan: true,
|
||||
theme: true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { PrismaClient, UserPlan } from "@prisma/client";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
|
||||
import { isTeamAdmin } from "@calcom/lib/server/queries/teams";
|
||||
|
@ -59,11 +59,8 @@ export const samlTenantProduct = async (prisma: PrismaClient, email: string) =>
|
|||
};
|
||||
};
|
||||
|
||||
export const canAccess = async (
|
||||
user: { id: number; plan: UserPlan; email: string },
|
||||
teamId: number | null
|
||||
) => {
|
||||
const { id: userId, plan, email } = user;
|
||||
export const canAccess = async (user: { id: number; email: string }, teamId: number | null) => {
|
||||
const { id: userId, email } = user;
|
||||
|
||||
if (!isSAMLLoginEnabled) {
|
||||
return {
|
||||
|
@ -80,13 +77,6 @@ export const canAccess = async (
|
|||
access: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (plan != UserPlan.PRO) {
|
||||
return {
|
||||
message: "app_upgrade_description",
|
||||
access: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Self-hosted
|
||||
|
|
|
@ -108,7 +108,6 @@ export default function MemberListItem(props: Props) {
|
|||
<div className="mb-1 flex">
|
||||
<span className="mr-1 text-sm font-bold leading-4">{name}</span>
|
||||
|
||||
{props.member.isMissingSeat && <TeamPill color="red" text={t("hidden")} />}
|
||||
{!props.member.accepted && <TeamPill color="orange" text={t("pending")} />}
|
||||
{props.member.role && <TeamRole role={props.member.role} />}
|
||||
</div>
|
||||
|
|
|
@ -2,23 +2,17 @@ import { useRouter } from "next/router";
|
|||
import { useMemo, useState } from "react";
|
||||
|
||||
import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
import { Alert, Avatar, Loader, Shell } from "@calcom/ui";
|
||||
|
||||
import LicenseRequired from "../../common/components/LicenseRequired";
|
||||
import TeamAvailabilityScreen from "../components/TeamAvailabilityScreen";
|
||||
|
||||
export function TeamAvailabilityPage() {
|
||||
const { t } = useLocale();
|
||||
const router = useRouter();
|
||||
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
const me = useMeQuery();
|
||||
const isFreeUser = me.data?.plan === "FREE";
|
||||
|
||||
const { data: team, isLoading } = trpc.viewer.teams.get.useQuery(
|
||||
{ teamId: Number(router.query.id) },
|
||||
{
|
||||
|
@ -37,12 +31,11 @@ export function TeamAvailabilityPage() {
|
|||
return (
|
||||
<Shell
|
||||
backPath={!errorMessage ? `/settings/teams/${team?.id}` : undefined}
|
||||
heading={!isFreeUser && team?.name}
|
||||
heading={team?.name}
|
||||
flexChildrenContainer
|
||||
subtitle={team && !isFreeUser && "Your team's availability at a glance"}
|
||||
subtitle={team && "Your team's availability at a glance"}
|
||||
HeadingLeftIcon={
|
||||
team &&
|
||||
!isFreeUser && (
|
||||
team && (
|
||||
<Avatar
|
||||
size="sm"
|
||||
imageSrc={getPlaceholderAvatar(team?.logo, team?.name as string)}
|
||||
|
@ -54,11 +47,7 @@ export function TeamAvailabilityPage() {
|
|||
<LicenseRequired>
|
||||
{!!errorMessage && <Alert className="-mt-24 border" severity="error" title={errorMessage} />}
|
||||
{isLoading && <Loader />}
|
||||
{isFreeUser ? (
|
||||
<Alert className="-mt-24 border" severity="warning" title={t("pro_feature_teams")} />
|
||||
) : (
|
||||
TeamAvailability
|
||||
)}
|
||||
{TeamAvailability}
|
||||
</LicenseRequired>
|
||||
</Shell>
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { PeriodType, Prisma, SchedulingType, UserPlan } from "@prisma/client";
|
||||
import { PeriodType, Prisma, SchedulingType } from "@prisma/client";
|
||||
|
||||
import { DailyLocationType } from "@calcom/app-store/locations";
|
||||
import { userSelect } from "@calcom/prisma/selects";
|
||||
|
@ -15,7 +15,6 @@ type UsernameSlugLinkProps = {
|
|||
bio?: string | null;
|
||||
avatar?: string | null;
|
||||
theme?: string | null;
|
||||
plan?: UserPlan;
|
||||
away?: boolean;
|
||||
verified?: boolean | null;
|
||||
allowDynamicBooking?: boolean | null;
|
||||
|
@ -41,7 +40,6 @@ const user: User = {
|
|||
name: "John doe",
|
||||
avatar: "",
|
||||
destinationCalendar: null,
|
||||
plan: UserPlan.PRO,
|
||||
hideBranding: true,
|
||||
brandColor: "#797979",
|
||||
darkBrandColor: "#efefef",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Prisma, UserPlan } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import prisma, { baseEventTypeSelect } from "@calcom/prisma";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
@ -12,7 +12,6 @@ export async function getTeamWithMembers(id?: number, slug?: string, userId?: nu
|
|||
email: true,
|
||||
name: true,
|
||||
id: true,
|
||||
plan: true,
|
||||
bio: true,
|
||||
});
|
||||
const teamSelect = Prisma.validator<Prisma.TeamSelect>()({
|
||||
|
@ -62,7 +61,6 @@ export async function getTeamWithMembers(id?: number, slug?: string, userId?: nu
|
|||
const members = team.members.map((obj) => {
|
||||
return {
|
||||
...obj.user,
|
||||
isMissingSeat: obj.user.plan === UserPlan.FREE,
|
||||
role: obj.role,
|
||||
accepted: obj.accepted,
|
||||
disableImpersonation: obj.disableImpersonation,
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// import { DeploymentType } from "@prisma/admin-client";
|
||||
import { User } from "@prisma/client";
|
||||
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { default as webPrisma } from "@calcom/prisma";
|
||||
|
||||
|
@ -17,7 +14,8 @@ export type TeamInfoType = {
|
|||
};
|
||||
|
||||
export type WebUserInfoType = UserInfo & {
|
||||
plan: User["plan"];
|
||||
/** All users are PRO now */
|
||||
plan?: "PRO";
|
||||
};
|
||||
|
||||
export type ConsoleUserInfoType = UserInfo & {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { faker } from "@faker-js/faker";
|
||||
import { Booking, BookingStatus, EventType, Prisma, UserPlan, Webhook } from "@prisma/client";
|
||||
import { Booking, BookingStatus, EventType, Prisma, Webhook } from "@prisma/client";
|
||||
|
||||
import { CalendarEvent, Person, VideoCallData } from "@calcom/types/Calendar";
|
||||
|
||||
|
@ -197,7 +197,6 @@ export const buildUser = <T extends Partial<UserPayload>>(user?: T): UserPayload
|
|||
locale: "en",
|
||||
metadata: null,
|
||||
password: null,
|
||||
plan: UserPlan.PRO,
|
||||
role: "USER",
|
||||
schedules: [],
|
||||
selectedCalendars: [],
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `plan` on the `users` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "users" DROP COLUMN "plan";
|
||||
|
||||
-- DropEnum
|
||||
DROP TYPE "UserPlan";
|
|
@ -103,12 +103,6 @@ model Credential {
|
|||
invalid Boolean? @default(false)
|
||||
}
|
||||
|
||||
enum UserPlan {
|
||||
FREE
|
||||
TRIAL
|
||||
PRO
|
||||
}
|
||||
|
||||
enum IdentityProvider {
|
||||
CAL
|
||||
GOOGLE
|
||||
|
@ -170,7 +164,6 @@ model User {
|
|||
identityProviderId String?
|
||||
availability Availability[]
|
||||
invitedTo Int?
|
||||
plan UserPlan @default(PRO)
|
||||
webhooks Webhook[]
|
||||
brandColor String @default("#292929")
|
||||
darkBrandColor String @default("#fafafa")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BookingStatus, MembershipRole, Prisma, UserPermissionRole, UserPlan } from "@prisma/client";
|
||||
import { BookingStatus, MembershipRole, Prisma, UserPermissionRole } from "@prisma/client";
|
||||
import { uuid } from "short-uuid";
|
||||
|
||||
import dailyMeta from "@calcom/app-store/dailyvideo/_metadata";
|
||||
|
@ -16,7 +16,6 @@ async function createUserAndEventType(opts: {
|
|||
email: string;
|
||||
password: string;
|
||||
username: string;
|
||||
plan: UserPlan;
|
||||
name: string;
|
||||
completedOnboarding?: boolean;
|
||||
timeZone?: string;
|
||||
|
@ -176,7 +175,6 @@ async function main() {
|
|||
password: "delete-me",
|
||||
username: "delete-me",
|
||||
name: "delete-me",
|
||||
plan: "FREE",
|
||||
},
|
||||
eventTypes: [],
|
||||
});
|
||||
|
@ -187,7 +185,6 @@ async function main() {
|
|||
password: "onboarding",
|
||||
username: "onboarding",
|
||||
name: "onboarding",
|
||||
plan: "TRIAL",
|
||||
completedOnboarding: false,
|
||||
},
|
||||
eventTypes: [],
|
||||
|
@ -199,7 +196,6 @@ async function main() {
|
|||
password: "free-first-hidden",
|
||||
username: "free-first-hidden",
|
||||
name: "Free First Hidden Example",
|
||||
plan: "FREE",
|
||||
},
|
||||
eventTypes: [
|
||||
{
|
||||
|
@ -221,7 +217,6 @@ async function main() {
|
|||
name: "Pro Example",
|
||||
password: "pro",
|
||||
username: "pro",
|
||||
plan: "PRO",
|
||||
},
|
||||
eventTypes: [
|
||||
{
|
||||
|
@ -445,7 +440,6 @@ async function main() {
|
|||
password: "trial",
|
||||
username: "trial",
|
||||
name: "Trial Example",
|
||||
plan: "TRIAL",
|
||||
},
|
||||
eventTypes: [
|
||||
{
|
||||
|
@ -467,7 +461,6 @@ async function main() {
|
|||
password: "free",
|
||||
username: "free",
|
||||
name: "Free Example",
|
||||
plan: "FREE",
|
||||
},
|
||||
eventTypes: [
|
||||
{
|
||||
|
@ -489,7 +482,6 @@ async function main() {
|
|||
password: "usa",
|
||||
username: "usa",
|
||||
name: "USA Timezone Example",
|
||||
plan: "FREE",
|
||||
timeZone: "America/Phoenix",
|
||||
},
|
||||
eventTypes: [
|
||||
|
@ -507,7 +499,6 @@ async function main() {
|
|||
password: "teamfree",
|
||||
username: "teamfree",
|
||||
name: "Team Free Example",
|
||||
plan: "FREE",
|
||||
},
|
||||
eventTypes: [],
|
||||
});
|
||||
|
@ -518,7 +509,6 @@ async function main() {
|
|||
password: "teampro",
|
||||
username: "teampro",
|
||||
name: "Team Pro Example",
|
||||
plan: "PRO",
|
||||
},
|
||||
eventTypes: [],
|
||||
});
|
||||
|
@ -530,7 +520,6 @@ async function main() {
|
|||
password: "ADMINadmin2022!",
|
||||
username: "admin",
|
||||
name: "Admin Example",
|
||||
plan: "PRO",
|
||||
role: "ADMIN",
|
||||
},
|
||||
eventTypes: [],
|
||||
|
@ -542,7 +531,6 @@ async function main() {
|
|||
password: "teampro2",
|
||||
username: "teampro2",
|
||||
name: "Team Pro Example 2",
|
||||
plan: "PRO",
|
||||
},
|
||||
eventTypes: [],
|
||||
});
|
||||
|
@ -553,7 +541,6 @@ async function main() {
|
|||
password: "teampro3",
|
||||
username: "teampro3",
|
||||
name: "Team Pro Example 3",
|
||||
plan: "PRO",
|
||||
},
|
||||
eventTypes: [],
|
||||
});
|
||||
|
@ -564,7 +551,6 @@ async function main() {
|
|||
password: "teampro4",
|
||||
username: "teampro4",
|
||||
name: "Team Pro Example 4",
|
||||
plan: "PRO",
|
||||
},
|
||||
eventTypes: [],
|
||||
});
|
||||
|
|
|
@ -97,7 +97,6 @@ export const availiblityPageEventTypeSelect = Prisma.validator<Prisma.EventTypeS
|
|||
name: true,
|
||||
username: true,
|
||||
hideBranding: true,
|
||||
plan: true,
|
||||
timeZone: true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -25,7 +25,6 @@ export const baseUserSelect = Prisma.validator<Prisma.UserSelect>()({
|
|||
name: true,
|
||||
destinationCalendar: true,
|
||||
locale: true,
|
||||
plan: true,
|
||||
hideBranding: true,
|
||||
theme: true,
|
||||
brandColor: true,
|
||||
|
@ -40,7 +39,6 @@ export const userSelect = Prisma.validator<Prisma.UserArgs>()({
|
|||
allowDynamicBooking: true,
|
||||
destinationCalendar: true,
|
||||
locale: true,
|
||||
plan: true,
|
||||
avatar: true,
|
||||
hideBranding: true,
|
||||
theme: true,
|
||||
|
|
|
@ -49,7 +49,6 @@ async function getUserFromSession({
|
|||
identityProvider: true,
|
||||
brandColor: true,
|
||||
darkBrandColor: true,
|
||||
plan: true,
|
||||
away: true,
|
||||
credentials: {
|
||||
select: {
|
||||
|
|
|
@ -167,7 +167,6 @@ const loggedInViewerRouter = router({
|
|||
identityProvider: user.identityProvider,
|
||||
brandColor: user.brandColor,
|
||||
darkBrandColor: user.darkBrandColor,
|
||||
plan: user.plan,
|
||||
away: user.away,
|
||||
bio: user.bio,
|
||||
weekStart: user.weekStart,
|
||||
|
@ -647,7 +646,6 @@ const loggedInViewerRouter = router({
|
|||
email: true,
|
||||
metadata: true,
|
||||
name: true,
|
||||
plan: true,
|
||||
createdDate: true,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { EventTypeCustomInput, MembershipRole, PeriodType, Prisma } from "@prisma/client";
|
||||
import { MembershipRole, PeriodType, Prisma } from "@prisma/client";
|
||||
import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
|
||||
// REVIEW: From lint error
|
||||
import _ from "lodash";
|
||||
|
@ -10,12 +10,12 @@ import { stripeDataSchema } from "@calcom/app-store/stripepayment/lib/server";
|
|||
import { validateBookingLimitOrder } from "@calcom/lib";
|
||||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { baseEventTypeSelect, baseUserSelect } from "@calcom/prisma";
|
||||
import { _DestinationCalendarModel, _EventTypeCustomInputModel, _EventTypeModel } from "@calcom/prisma/zod";
|
||||
import { _DestinationCalendarModel, _EventTypeModel } from "@calcom/prisma/zod";
|
||||
import {
|
||||
customInputSchema,
|
||||
CustomInputSchema,
|
||||
EventTypeMetaDataSchema,
|
||||
stringOrNumber,
|
||||
CustomInputSchema,
|
||||
} from "@calcom/prisma/zod-utils";
|
||||
import { createEventTypeInput } from "@calcom/prisma/zod/custom/eventtype";
|
||||
|
||||
|
@ -193,7 +193,6 @@ export const eventTypesRouter = router({
|
|||
startTime: true,
|
||||
endTime: true,
|
||||
bufferTime: true,
|
||||
plan: true,
|
||||
teams: {
|
||||
where: {
|
||||
accepted: true,
|
||||
|
@ -321,9 +320,6 @@ export const eventTypesRouter = router({
|
|||
}))
|
||||
);
|
||||
return {
|
||||
viewer: {
|
||||
plan: user.plan,
|
||||
},
|
||||
// don't display event teams without event types,
|
||||
eventTypeGroups: eventTypeGroups.filter((groupBy) => !!groupBy.eventTypes?.length),
|
||||
// so we can show a dropdown when the user has teams
|
||||
|
@ -425,7 +421,6 @@ export const eventTypesRouter = router({
|
|||
endTime: true,
|
||||
bufferTime: true,
|
||||
avatar: true,
|
||||
plan: true,
|
||||
},
|
||||
});
|
||||
if (!user) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { MembershipRole, Prisma, UserPlan } from "@prisma/client";
|
||||
import { MembershipRole, Prisma } from "@prisma/client";
|
||||
import { randomBytes } from "crypto";
|
||||
import { z } from "zod";
|
||||
|
||||
|
@ -45,10 +45,8 @@ export const viewerTeamsRouter = router({
|
|||
...team,
|
||||
membership: {
|
||||
role: membership?.role as MembershipRole,
|
||||
isMissingSeat: membership?.plan === UserPlan.FREE,
|
||||
accepted: membership?.accepted,
|
||||
},
|
||||
requiresUpgrade: HOSTED_CAL_FEATURES ? !!team.members.find((m) => m.plan !== UserPlan.PRO) : false,
|
||||
};
|
||||
}),
|
||||
// Returns teams I a member of
|
||||
|
|
|
@ -725,9 +725,6 @@ function DeploymentInfo() {
|
|||
className="mx-3 mt-1 mb-2 hidden opacity-50 lg:block">
|
||||
© {new Date().getFullYear()} {COMPANY_NAME} v.{pkg.version + "-"}
|
||||
{process.env.NEXT_PUBLIC_WEBSITE_URL === "https://cal.com" ? "h" : "sh"}
|
||||
<span className="lowercase" data-testid={`plan-${user?.plan.toLowerCase()}`}>
|
||||
-{user?.plan}
|
||||
</span>
|
||||
</small>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user