Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d2ec20f66 | ||
|
|
01fc501cb9 | ||
|
|
1be002c33c | ||
|
|
8a4b03833d | ||
|
|
8714dda047 | ||
|
|
5b89123307 | ||
|
|
3221379584 | ||
|
|
578f5dc16b | ||
|
|
3f042a1077 | ||
|
|
a44e7b2371 | ||
|
|
b06a94ab57 | ||
|
|
ec55454e43 | ||
|
|
9ec0217858 | ||
|
|
66d69f5a06 | ||
|
|
b7b58c2dc7 | ||
|
|
de1e19ee6d | ||
|
|
a366cb7c89 | ||
|
|
dac336894c | ||
|
|
373c17a46d | ||
|
|
4c00c1ac2b | ||
|
|
050a030ff0 | ||
|
|
dfb2232a59 | ||
|
|
984ccf7c80 | ||
|
|
e87168322c | ||
|
|
bf9e9b4ae1 | ||
|
|
6d4b05cf1d | ||
|
|
bd1af4027f | ||
|
|
3872175393 | ||
|
|
5ca063d4e8 | ||
|
|
112aa8201f | ||
|
|
17fcc2c213 | ||
|
|
d3f1dc1b32 | ||
|
|
25f3368fa1 | ||
|
|
9a271f397b | ||
|
|
6847781a7f | ||
|
|
2d9a3bd741 | ||
|
|
649faf4ff6 | ||
|
|
03346f04ed | ||
|
|
99260974f4 | ||
|
|
4a493c0a0e | ||
|
|
47435c36ff | ||
|
|
599744b31c | ||
|
|
d2c4c45137 | ||
|
|
43ba47a122 | ||
|
|
0048b2d92c | ||
|
|
9dc0570d38 | ||
|
|
1fbfca958a | ||
|
|
7a6c93795a | ||
|
|
4481b232cc | ||
|
|
84b265cd54 | ||
|
|
eb86064995 | ||
|
|
39fdf5a74e | ||
|
|
f28c605b50 | ||
|
|
63d26c4fba | ||
|
|
14bba343a4 | ||
|
|
e441f3308f | ||
|
|
b4aad453cd | ||
|
|
dc7a1c4680 | ||
|
|
fd651133c2 | ||
|
|
f0d2a1a051 | ||
|
|
62c7627775 | ||
|
|
be53a20429 | ||
|
|
5c6f52f1d4 | ||
|
|
0e9e3e5012 | ||
|
|
5d709cf63c | ||
|
|
0f67faeef3 | ||
|
|
1ff4f557f6 | ||
|
|
7e2c0bd29e | ||
|
|
5b59cf9d9c | ||
|
|
d5420eda00 | ||
|
|
c17ac67b3f | ||
|
|
b2763a6274 | ||
|
|
08b6f60407 | ||
|
|
466b3e4c08 |
@@ -388,6 +388,12 @@ BLACKLISTED_GUEST_EMAILS=
|
||||
NEXT_PUBLIC_VAPID_PUBLIC_KEY=
|
||||
VAPID_PRIVATE_KEY=
|
||||
|
||||
# Mintlify chat api
|
||||
# Power AI chat in for docs
|
||||
NEXT_PUBLIC_MINTLIFY_CHAT_API_KEY=
|
||||
NEXT_PUBLIC_CHAT_API_URL=
|
||||
NEXT_PUBLIC_DOCS_URL=
|
||||
|
||||
# Custom privacy policy / terms URLs (for self-hosters: change to your privacy policy / terms URLs)
|
||||
NEXT_PUBLIC_WEBSITE_PRIVACY_POLICY_URL=
|
||||
NEXT_PUBLIC_WEBSITE_TERMS_URL=
|
||||
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
undecided:
|
||||
- "@calcom/prisma"
|
||||
Vendored
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
undecided:
|
||||
- "@calcom/app-store-cli"
|
||||
- "@calcom/platform-constants"
|
||||
- "@calcom/platform-enums"
|
||||
- "@calcom/platform-types"
|
||||
- "@calcom/platform-utils"
|
||||
Vendored
Vendored
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
undecided:
|
||||
- calcom-monorepo
|
||||
- "@calcom/app-store-cli"
|
||||
- "@calcom/platform-constants"
|
||||
- "@calcom/platform-enums"
|
||||
- "@calcom/platform-types"
|
||||
- "@calcom/platform-utils"
|
||||
- "@calcom/prisma"
|
||||
@@ -2,7 +2,7 @@ import type { NextApiRequest } from "next";
|
||||
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import { defaultResponder } from "@calcom/lib/server";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { UserCreationService } from "@calcom/lib/server/service/userCreationService";
|
||||
import { CreationSource } from "@calcom/prisma/enums";
|
||||
|
||||
import { schemaUserCreateBodyParams } from "~/lib/validations/user";
|
||||
@@ -93,7 +93,9 @@ async function postHandler(req: NextApiRequest) {
|
||||
// If user is not ADMIN, return unauthorized.
|
||||
if (!isSystemWideAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" });
|
||||
const data = await schemaUserCreateBodyParams.parseAsync(req.body);
|
||||
const user = await prisma.user.create({ data: { ...data, creationSource: CreationSource.API_V1 } });
|
||||
const user = await UserCreationService.createUser({
|
||||
data: { ...data, creationSource: CreationSource.API_V1 },
|
||||
});
|
||||
req.statusCode = 201;
|
||||
return { user };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import prismock from "../../../../../../tests/libs/__mocks__/prisma";
|
||||
|
||||
import type { Request, Response } from "express";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import { createMocks } from "node-mocks-http";
|
||||
import { describe, test, expect, vi } from "vitest";
|
||||
|
||||
import handler from "../../../pages/api/users/_post";
|
||||
|
||||
type CustomNextApiRequest = NextApiRequest & Request;
|
||||
type CustomNextApiResponse = NextApiResponse & Response;
|
||||
|
||||
vi.mock("@calcom/lib/server/i18n", () => {
|
||||
return {
|
||||
getTranslation: (key: string) => {
|
||||
return () => key;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
vi.stubEnv("CALCOM_LICENSE_KEY", undefined);
|
||||
|
||||
describe("POST /api/users", () => {
|
||||
test("should throw 401 if not system-wide admin", async () => {
|
||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||
method: "POST",
|
||||
body: {
|
||||
email: "test@example.com",
|
||||
username: "test",
|
||||
},
|
||||
});
|
||||
req.isSystemWideAdmin = false;
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(401);
|
||||
});
|
||||
test("should throw a 400 if no email is provided", async () => {
|
||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||
method: "POST",
|
||||
body: {
|
||||
username: "test",
|
||||
},
|
||||
});
|
||||
req.isSystemWideAdmin = true;
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
test("should throw a 400 if no username is provided", async () => {
|
||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||
method: "POST",
|
||||
body: {
|
||||
email: "test@example.com",
|
||||
},
|
||||
});
|
||||
req.isSystemWideAdmin = true;
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
});
|
||||
test("should create user successfully", async () => {
|
||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||
method: "POST",
|
||||
body: {
|
||||
email: "test@example.com",
|
||||
username: "test",
|
||||
},
|
||||
prisma: prismock,
|
||||
});
|
||||
req.isSystemWideAdmin = true;
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
|
||||
const userQuery = await prismock.user.findFirst({
|
||||
where: {
|
||||
email: "test@example.com",
|
||||
},
|
||||
});
|
||||
|
||||
expect(userQuery).toEqual(
|
||||
expect.objectContaining({
|
||||
email: "test@example.com",
|
||||
username: "test",
|
||||
locked: false,
|
||||
organizationId: null,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("should auto lock user if email is in watchlist", async () => {
|
||||
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
|
||||
method: "POST",
|
||||
body: {
|
||||
email: "test@example.com",
|
||||
username: "test",
|
||||
},
|
||||
prisma: prismock,
|
||||
});
|
||||
req.isSystemWideAdmin = true;
|
||||
|
||||
await prismock.watchlist.create({
|
||||
data: {
|
||||
type: "EMAIL",
|
||||
value: "test@example.com",
|
||||
severity: "CRITICAL",
|
||||
createdById: 1,
|
||||
},
|
||||
});
|
||||
|
||||
await handler(req, res);
|
||||
|
||||
expect(res.statusCode).toBe(200);
|
||||
|
||||
const userQuery = await prismock.user.findFirst({
|
||||
where: {
|
||||
email: "test@example.com",
|
||||
},
|
||||
});
|
||||
|
||||
expect(userQuery).toEqual(
|
||||
expect.objectContaining({
|
||||
email: "test@example.com",
|
||||
username: "test",
|
||||
locked: true,
|
||||
organizationId: null,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -8,13 +8,13 @@ used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the Cal.com Subscription Terms available
|
||||
at https://cal.com/terms, or other agreements governing
|
||||
the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"),
|
||||
and otherwise have a valid Cal.com Enterprise Edition subscription ("Commercial Subscription")
|
||||
and otherwise have a valid Cal.com Commercial License ("Commercial License")
|
||||
for the correct number of hosts as defined in the "Commercial Terms ("Hosts"). Subject to the foregoing sentence,
|
||||
you are free to modify this Software and publish patches to the Software. You agree
|
||||
that Cal.com and/or its licensors (as applicable) retain all right, title and interest in
|
||||
and to all such modifications and/or patches, and all such modifications and/or
|
||||
patches may only be used, copied, modified, displayed, distributed, or otherwise
|
||||
exploited with a valid Commercial Subscription for the correct number of hosts.
|
||||
exploited with a valid Commercial License for the correct number of hosts.
|
||||
Notwithstanding the foregoing, you may copy and modify the Software for development
|
||||
and testing purposes, without requiring a subscription. You agree that Cal.com and/or
|
||||
its licensors (as applicable) retain all right, title and interest in and to all such
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
<img src="https://user-images.githubusercontent.com/8019099/133430653-24422d2a-3c8d-4052-9ad6-0580597151ee.png" alt="Logo">
|
||||
</a>
|
||||
|
||||
<a href="https://console.cal.com/">Get a License Key</a>
|
||||
<a href="https://go.cal.com/get-license">Get a License Key</a>
|
||||
</div>
|
||||
|
||||
# Enterprise Edition of API
|
||||
# Commercial License of API
|
||||
|
||||
Welcome to the Enterprise Edition ("/ee") of the Cal.com API.
|
||||
Welcome to the Commercial License of the Cal.com API.
|
||||
|
||||
Our philosophy is simple, all "Singleplayer APIs" are open-source under AGPLv3. All "Multiplayer APIs" are under a commercial license.
|
||||
|
||||
The [/ee](https://github.com/calcom/cal.com/tree/main/apps/api/v2/ee) subfolder is the place for all the **Enterprise Edition** features from our [hosted](https://cal.com/pricing) plan and enterprise-grade features for [Enterprise](https://cal.com/enterprise) such as SSO, SAML, OIDC, SCIM, SIEM and much more or [Platform](https://cal.com/platform) plan to build a marketplace.
|
||||
The [/ee](https://github.com/calcom/cal.com/tree/main/apps/api/v2/ee) subfolder is the place for all the **Commercial License** features from our [hosted](https://cal.com/pricing) plan.
|
||||
|
||||
> _❗ WARNING: This repository is copyrighted (unlike our [main repo](https://github.com/calcom/cal.com)). You are not allowed to use this code to host your own version of app.cal.com without obtaining a proper [license](https://console.cal.com/) first❗_
|
||||
> _❗ WARNING: This repository is copyrighted (unlike our [main repo](https://github.com/calcom/cal.com)). You are not allowed to use this code to host your own version of app.cal.com without obtaining a proper [license](https://go.cal.com/get-license) first❗_
|
||||
|
||||
@@ -167,6 +167,7 @@ describe("Bookings Endpoints 2024-08-13", () => {
|
||||
timeZone: "Europe/Rome",
|
||||
},
|
||||
},
|
||||
rating: 10,
|
||||
});
|
||||
|
||||
app = moduleRef.createNestApplication();
|
||||
@@ -552,6 +553,30 @@ describe("Bookings Endpoints 2024-08-13", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should should get a booking with rating", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/bookings/${bookingInThePast.uid}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_08_13)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: GetBookingOutput_2024_08_13 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseBody.data).toBeDefined();
|
||||
expect(responseDataIsBooking(responseBody.data)).toBe(true);
|
||||
|
||||
if (responseDataIsBooking(responseBody.data)) {
|
||||
const data: BookingOutput_2024_08_13 = responseBody.data;
|
||||
expect(data.id).toEqual(bookingInThePast.id);
|
||||
expect(data.uid).toEqual(bookingInThePast.uid);
|
||||
expect(data.rating).toEqual(bookingInThePast.rating);
|
||||
} else {
|
||||
throw new Error(
|
||||
"Invalid response data - expected booking but received array of possibily recurring bookings"
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("should should get 1 recurrence of a recurring booking", async () => {
|
||||
const recurrenceUid = createdRecurringBooking[0].uid;
|
||||
return request(app.getHttpServer())
|
||||
|
||||
@@ -133,6 +133,7 @@ export class OutputBookingsService_2024_08_13 {
|
||||
absentHost: !!databaseBooking.noShowHost,
|
||||
createdAt: databaseBooking.createdAt,
|
||||
updatedAt: databaseBooking.updatedAt,
|
||||
rating: databaseBooking.rating,
|
||||
};
|
||||
|
||||
const bookingTransformed = plainToClass(BookingOutput_2024_08_13, booking, { strategy: "excludeAll" });
|
||||
@@ -227,6 +228,7 @@ export class OutputBookingsService_2024_08_13 {
|
||||
bookingFieldsResponses: databaseBooking.responses,
|
||||
createdAt: databaseBooking.createdAt,
|
||||
updatedAt: databaseBooking.updatedAt,
|
||||
rating: databaseBooking.rating,
|
||||
};
|
||||
|
||||
const bookingTransformed = plainToClass(RecurringBookingOutput_2024_08_13, booking, {
|
||||
@@ -274,6 +276,7 @@ export class OutputBookingsService_2024_08_13 {
|
||||
absentHost: !!databaseBooking.noShowHost,
|
||||
createdAt: databaseBooking.createdAt,
|
||||
updatedAt: databaseBooking.updatedAt,
|
||||
rating: databaseBooking.rating,
|
||||
};
|
||||
|
||||
const parsed = plainToClass(GetSeatedBookingOutput_2024_08_13, booking, { strategy: "excludeAll" });
|
||||
@@ -283,7 +286,8 @@ export class OutputBookingsService_2024_08_13 {
|
||||
const { responses } = safeParse(
|
||||
seatedBookingDataSchema,
|
||||
attendee.bookingSeat?.data,
|
||||
defaultSeatedBookingData
|
||||
defaultSeatedBookingData,
|
||||
false
|
||||
);
|
||||
|
||||
const attendeeData = {
|
||||
@@ -300,7 +304,8 @@ export class OutputBookingsService_2024_08_13 {
|
||||
attendeeParsed.metadata = safeParse(
|
||||
seatedBookingMetadataSchema,
|
||||
attendee.bookingSeat?.metadata,
|
||||
defaultSeatedBookingMetadata
|
||||
defaultSeatedBookingMetadata,
|
||||
false
|
||||
);
|
||||
// note(Lauris): as of now email is not returned for privacy
|
||||
delete attendeeParsed.bookingFieldsResponses.email;
|
||||
@@ -380,6 +385,7 @@ export class OutputBookingsService_2024_08_13 {
|
||||
absentHost: !!databaseBooking.noShowHost,
|
||||
createdAt: databaseBooking.createdAt,
|
||||
updatedAt: databaseBooking.updatedAt,
|
||||
rating: databaseBooking.rating,
|
||||
};
|
||||
|
||||
const parsed = plainToClass(GetRecurringSeatedBookingOutput_2024_08_13, booking, {
|
||||
@@ -391,7 +397,8 @@ export class OutputBookingsService_2024_08_13 {
|
||||
const { responses } = safeParse(
|
||||
seatedBookingDataSchema,
|
||||
attendee.bookingSeat?.data,
|
||||
defaultSeatedBookingData
|
||||
defaultSeatedBookingData,
|
||||
false
|
||||
);
|
||||
|
||||
const attendeeData = {
|
||||
@@ -408,7 +415,8 @@ export class OutputBookingsService_2024_08_13 {
|
||||
attendeeParsed.metadata = safeParse(
|
||||
seatedBookingMetadataSchema,
|
||||
attendee.bookingSeat?.metadata,
|
||||
defaultSeatedBookingMetadata
|
||||
defaultSeatedBookingMetadata,
|
||||
false
|
||||
);
|
||||
// note(Lauris): as of now email is not returned for privacy
|
||||
delete attendeeParsed.bookingFieldsResponses.email;
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
Post,
|
||||
Body,
|
||||
} from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { ApiOperation, ApiParam, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { User } from "@prisma/client";
|
||||
import { plainToClass } from "class-transformer";
|
||||
import { Request } from "express";
|
||||
@@ -123,10 +123,15 @@ export class CalendarsController {
|
||||
};
|
||||
}
|
||||
|
||||
@ApiParam({
|
||||
enum: [OFFICE_365_CALENDAR, GOOGLE_CALENDAR],
|
||||
type: String,
|
||||
name: "calendar",
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@Get("/:calendar/connect")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: "Get connect URL" })
|
||||
@ApiOperation({ summary: "Get oAuth connect URL" })
|
||||
async redirect(
|
||||
@Req() req: Request,
|
||||
@Headers("Authorization") authorization: string,
|
||||
@@ -146,10 +151,15 @@ export class CalendarsController {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiParam({
|
||||
enum: [OFFICE_365_CALENDAR, GOOGLE_CALENDAR],
|
||||
type: String,
|
||||
name: "calendar",
|
||||
})
|
||||
@Get("/:calendar/save")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Redirect(undefined, 301)
|
||||
@ApiOperation({ summary: "Save a calendar" })
|
||||
@ApiOperation({ summary: "Save an oAuth calendar credentials" })
|
||||
async save(
|
||||
@Query("state") state: string,
|
||||
@Query("code") code: string,
|
||||
@@ -177,6 +187,11 @@ export class CalendarsController {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiParam({
|
||||
enum: [APPLE_CALENDAR],
|
||||
type: String,
|
||||
name: "calendar",
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@Post("/:calendar/credentials")
|
||||
@ApiOperation({ summary: "Sync credentials" })
|
||||
@@ -198,6 +213,11 @@ export class CalendarsController {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiParam({
|
||||
enum: [APPLE_CALENDAR, GOOGLE_CALENDAR, OFFICE_365_CALENDAR],
|
||||
type: String,
|
||||
name: "calendar",
|
||||
})
|
||||
@Get("/:calendar/check")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@UseGuards(ApiAuthGuard, PermissionsGuard)
|
||||
@@ -219,6 +239,11 @@ export class CalendarsController {
|
||||
}
|
||||
}
|
||||
|
||||
@ApiParam({
|
||||
enum: [APPLE_CALENDAR, GOOGLE_CALENDAR, OFFICE_365_CALENDAR],
|
||||
type: String,
|
||||
name: "calendar",
|
||||
})
|
||||
@UseGuards(ApiAuthGuard)
|
||||
@Post("/:calendar/disconnect")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
|
||||
@@ -3,20 +3,27 @@ import { ZodSchema } from "zod";
|
||||
|
||||
const logger = new Logger("safeParse");
|
||||
|
||||
export function safeParse<T>(schema: ZodSchema<T>, value: unknown, defaultValue: T): T {
|
||||
export function safeParse<T>(
|
||||
schema: ZodSchema<T>,
|
||||
value: unknown,
|
||||
defaultValue: T,
|
||||
logError = true
|
||||
): T {
|
||||
const result = schema.safeParse(value);
|
||||
if (result.success) {
|
||||
return result.data;
|
||||
} else {
|
||||
const errorStack = new Error().stack;
|
||||
|
||||
logger.error(
|
||||
`Zod parsing failed.\n` +
|
||||
`1. Schema: ${schema.description || "UnnamedSchema"}\n` +
|
||||
`2. Input: ${JSON.stringify(value, null, 2)}\n` +
|
||||
`3. Zod Error: ${result.error}\n` +
|
||||
`4. Call Stack: ${errorStack}`
|
||||
);
|
||||
if (logError) {
|
||||
logger.error(
|
||||
`Zod parsing failed.\n` +
|
||||
`1. Schema: ${schema.description || "UnnamedSchema"}\n` +
|
||||
`2. Input: ${JSON.stringify(value, null, 2)}\n` +
|
||||
`3. Zod Error: ${result.error}\n` +
|
||||
`4. Call Stack: ${errorStack}`
|
||||
);
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,11 @@ export class RouterController {
|
||||
const pathNameParams = routingUrl.pathname.split("/");
|
||||
const eventTypeSlug = pathNameParams[pathNameParams.length - 1];
|
||||
const teamId = Number(routingSearchParams.get("cal.teamId"));
|
||||
const eventTypeData = this.teamsEventTypesRepository.getTeamEventTypeBySlug(teamId, eventTypeSlug, 3);
|
||||
const eventTypeData = await this.teamsEventTypesRepository.getTeamEventTypeBySlug(
|
||||
teamId,
|
||||
eventTypeSlug,
|
||||
3
|
||||
);
|
||||
|
||||
// get the salesforce record owner email for the email given as a form response.
|
||||
const {
|
||||
|
||||
@@ -4063,7 +4063,7 @@
|
||||
"/v2/calendars/{calendar}/connect": {
|
||||
"get": {
|
||||
"operationId": "CalendarsController_redirect",
|
||||
"summary": "Get connect URL",
|
||||
"summary": "Get oAuth connect URL",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Authorization",
|
||||
@@ -4078,6 +4078,10 @@
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"enum": [
|
||||
"office365",
|
||||
"google"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -4102,7 +4106,7 @@
|
||||
"/v2/calendars/{calendar}/save": {
|
||||
"get": {
|
||||
"operationId": "CalendarsController_save",
|
||||
"summary": "Save a calendar",
|
||||
"summary": "Save an oAuth calendar credentials",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "state",
|
||||
@@ -4125,6 +4129,10 @@
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"enum": [
|
||||
"office365",
|
||||
"google"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -4149,6 +4157,9 @@
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"enum": [
|
||||
"apple"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -4173,6 +4184,11 @@
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"enum": [
|
||||
"apple",
|
||||
"google",
|
||||
"office365"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -4204,6 +4220,11 @@
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"enum": [
|
||||
"apple",
|
||||
"google",
|
||||
"office365"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
@@ -12698,8 +12719,7 @@
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"callId",
|
||||
"agentId"
|
||||
"callId"
|
||||
]
|
||||
},
|
||||
"CreatePhoneCallOutput": {
|
||||
@@ -15376,6 +15396,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -15524,6 +15548,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -15775,6 +15803,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"seatUid": {
|
||||
"type": "string",
|
||||
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
|
||||
@@ -15910,6 +15942,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"seatUid": {
|
||||
"type": "string",
|
||||
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
|
||||
@@ -16090,6 +16126,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -16220,6 +16260,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -230,7 +230,7 @@
|
||||
--cal-text-info: hsla(228, 56%, 33%, 1);
|
||||
--cal-text-success: hsla(133, 34%, 24%, 1);
|
||||
--cal-text-attention: hsla(16, 62%, 28%, 1);
|
||||
--cal-text-error: hsla(2, 55%, 30%, 1);
|
||||
--cal-text-error: hsla(0, 63%, 31%, 1);
|
||||
|
||||
/* Brand shinanigans
|
||||
-> These will be computed for the users theme at runtime.
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -1,36 +0,0 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
@@ -1,485 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
/**
|
||||
* Add css variables here as well for light mode in addition to tailwind.config to avoid FOUC
|
||||
*/
|
||||
:root {
|
||||
/* background */
|
||||
|
||||
--cal-bg-emphasis: hsla(220,13%,91%,1);
|
||||
--cal-bg: hsla(0,0%,100%,1);
|
||||
--cal-bg-subtle: hsla(220, 14%, 96%,1);
|
||||
--cal-bg-muted: hsla(210,20%,98%,1);
|
||||
--cal-bg-inverted: hsla(0,0%,6%,1);
|
||||
|
||||
/* background -> components*/
|
||||
--cal-bg-info: hsla(218,83%,98%,1);
|
||||
--cal-bg-success: hsla(134,76%,94%,1);
|
||||
--cal-bg-attention: hsla(37, 86%, 92%, 1);
|
||||
--cal-bg-error: hsla(3,66%,93%,1);
|
||||
--cal-bg-dark-error: hsla(2, 55%, 30%, 1);
|
||||
|
||||
/* Borders */
|
||||
--cal-border-emphasis: hsla(218, 11%, 65%, 1);
|
||||
--cal-border: hsla(216, 12%, 84%, 1);
|
||||
--cal-border-subtle: hsla(220, 13%, 91%, 1);
|
||||
--cal-border-booker: #e5e7eb;
|
||||
--cal-border-muted: hsla(220, 14%, 96%, 1);
|
||||
--cal-border-error: hsla(4, 63%, 41%, 1);
|
||||
--cal-border-focus: hsla(0, 0%, 10%, 1);
|
||||
|
||||
/* Content/Text */
|
||||
--cal-text-emphasis: hsla(217, 19%, 27%, 1);
|
||||
--cal-text: hsla(217, 19%, 27%, 1);
|
||||
--cal-text-subtle: hsla(220, 9%, 46%, 1);
|
||||
--cal-text-muted: hsla(218, 11%, 65%, 1);
|
||||
--cal-text-inverted: hsla(0, 0%, 100%, 1);
|
||||
|
||||
/* Content/Text -> components */
|
||||
--cal-text-info: hsla(228, 56%, 33%, 1);
|
||||
--cal-text-success: hsla(133, 34%, 24%, 1);
|
||||
--cal-text-attention: hsla(16, 62%, 28%, 1);
|
||||
--cal-text-error: hsla(2, 55%, 30%, 1);
|
||||
|
||||
/* Brand shinanigans
|
||||
-> These will be computed for the users theme at runtime.
|
||||
*/
|
||||
--cal-brand: hsla(221, 39%, 11%, 1);
|
||||
--cal-brand-emphasis: hsla(0, 0%, 6%, 1);
|
||||
--cal-brand-text: hsla(0, 0%, 100%, 1);
|
||||
}
|
||||
.dark {
|
||||
/* background */
|
||||
|
||||
--cal-bg-emphasis: hsla(0, 0%, 25%, 1);
|
||||
--cal-bg: hsla(0, 0%, 10%, 1);
|
||||
--cal-bg-subtle: hsla(0, 0%, 18%, 1);
|
||||
--cal-bg-muted: hsla(0, 0%, 12%, 1);
|
||||
--cal-bg-inverted: hsla(220, 14%, 96%, 1);
|
||||
|
||||
/* background -> components*/
|
||||
--cal-bg-info: hsla(228, 56%, 33%, 1);
|
||||
--cal-bg-success: hsla(133, 34%, 24%, 1);
|
||||
--cal-bg-attention: hsla(16, 62%, 28%, 1);
|
||||
--cal-bg-error: hsla(2, 55%, 30%, 1);
|
||||
--cal-bg-dark-error: hsla(2, 55%, 30%, 1);
|
||||
|
||||
/* Borders */
|
||||
--cal-border-emphasis: hsla(0, 0%, 46%, 1);
|
||||
--cal-border: hsla(0, 0%, 34%, 1);
|
||||
--cal-border-subtle: hsla(0, 0%, 22%, 1);
|
||||
--cal-border-booker: hsla(0, 0%, 22%, 1);
|
||||
--cal-border-muted: hsla(0, 0%, 18%, 1);
|
||||
--cal-border-error: hsla(4, 63%, 41%, 1);
|
||||
--cal-border-focus: hsla(0, 0%, 100%, 1);
|
||||
|
||||
/* Content/Text */
|
||||
--cal-text-emphasis: hsla(240, 20%, 99%, 1);
|
||||
--cal-text: hsla(0, 0%, 84%, 1);
|
||||
--cal-text-subtle: hsla(0, 0%, 65%, 1);
|
||||
--cal-text-muted: hsla(0, 0%, 34%, 1);
|
||||
--cal-text-inverted: hsla(0, 0%, 10%, 1);
|
||||
|
||||
/* Content/Text -> components */
|
||||
--cal-text-info: hsla(218, 83%, 93%, 1);
|
||||
--cal-text-success: hsla(134, 76%, 94%, 1);
|
||||
--cal-text-attention: hsla(37, 86%, 92%, 1);
|
||||
--cal-text-error: hsla(3, 66%, 93%, 1);
|
||||
|
||||
/* Brand shenanigans
|
||||
-> These will be computed for the users theme at runtime.
|
||||
*/
|
||||
--cal-brand: hsla(0, 0%, 100%, 1);
|
||||
--cal-brand-emphasis: hsla(218, 11%, 65%, 1);
|
||||
--cal-brand-text: hsla(0, 0%, 0%,1);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-default
|
||||
}
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
color: var(--cal-brand-text);
|
||||
background: var(--cal-brand);
|
||||
}
|
||||
|
||||
::selection {
|
||||
color: var(--cal-brand-text);
|
||||
background: var(--cal-brand);
|
||||
}
|
||||
|
||||
body {
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/*
|
||||
Desktop App specific CSS
|
||||
https://docs.todesktop.com/
|
||||
*/
|
||||
|
||||
html.todesktop-platform-win32 .todesktop\:\!bg-transparent{
|
||||
background: inherit !important;
|
||||
}
|
||||
|
||||
/* disable user selection on buttons, links and images on desktop app */
|
||||
html.todesktop button,
|
||||
html.todesktop a,
|
||||
html.todesktop img,
|
||||
html.todesktop header {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
html.todesktop,
|
||||
html.todesktop div {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
/* make header draggable on desktop app */
|
||||
html.todesktop header {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
html.todesktop header button,
|
||||
html.todesktop header a {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
html.todesktop-platform-darwin body, html.todesktop-platform-darwin aside {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
html.todesktop-platform-darwin.dark main.bg-default {
|
||||
background: rgba(0, 0, 0, 0.6) !important;
|
||||
}
|
||||
|
||||
html.todesktop-platform-darwin.light main.bg-default {
|
||||
background: rgba(255, 255, 255, 0.8) !important;
|
||||
}
|
||||
|
||||
html.todesktop.light {
|
||||
--cal-bg-emphasis: hsla(0, 0%, 11%, 0.1);
|
||||
}
|
||||
|
||||
html.todesktop.dark {
|
||||
--cal-bg-emphasis: hsla(220, 2%, 26%, 0.3);
|
||||
}
|
||||
|
||||
/*
|
||||
Adds Utility to hide scrollbar to tailwind
|
||||
https://github.com/tailwindlabs/tailwindcss/discussions/2394
|
||||
https://github.com/tailwindlabs/tailwindcss/pull/5732
|
||||
*/
|
||||
@layer utilities {
|
||||
/* Chrome, Safari and Opera */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Override the default tailwindcss-forms styling (default is: 'colors.blue.600')
|
||||
* @see: https://github.com/tailwindlabs/tailwindcss-forms/issues/14#issuecomment-1005376006
|
||||
*/
|
||||
[type="text"]:focus,
|
||||
[type="email"]:focus,
|
||||
[type="url"]:focus,
|
||||
[type="password"]:focus,
|
||||
[type="number"]:focus,
|
||||
[type="date"]:focus,
|
||||
[type="datetime-local"]:focus,
|
||||
[type="month"]:focus,
|
||||
[type="search"]:focus,
|
||||
[type="tel"]:focus,
|
||||
[type="checkbox"]:focus,
|
||||
[type="radio"]:focus,
|
||||
[type="time"]:focus,
|
||||
[type="week"]:focus,
|
||||
[multiple]:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
--tw-ring-color: var(--brand-color);
|
||||
border-color: var(--brand-color);
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.scroll-bar {
|
||||
@apply scrollbar-thin scrollbar-thumb-rounded-md dark:scrollbar-thumb-darkgray-300 scrollbar-thumb-gray-300 scrollbar-track-transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: avoid global specific css */
|
||||
/* button[role="switch"][data-state="checked"] span {
|
||||
transform: translateX(16px);
|
||||
} */
|
||||
|
||||
@layer components {
|
||||
/* slider */
|
||||
.slider {
|
||||
@apply relative flex h-4 w-40 select-none items-center;
|
||||
}
|
||||
|
||||
.slider > .slider-track {
|
||||
@apply relative h-1 flex-grow rounded-md bg-gray-400;
|
||||
}
|
||||
|
||||
.slider .slider-range {
|
||||
@apply absolute h-full rounded-full bg-gray-700;
|
||||
}
|
||||
|
||||
.slider .slider-thumb {
|
||||
@apply block h-3 w-3 cursor-pointer rounded-full bg-gray-700 transition-all;
|
||||
}
|
||||
|
||||
.slider .slider-thumb:hover {
|
||||
@apply bg-gray-600;
|
||||
}
|
||||
|
||||
.slider .slider-thumb:focus {
|
||||
box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
/* hide chat bubble on mobile */
|
||||
@media only screen and (max-width: 768px) {
|
||||
/* Intercom FAB*/
|
||||
#launcher {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Zendesk FAB*/
|
||||
div[role="presentation"] > iframe {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Helpscout FAB*/
|
||||
.BeaconFabButtonFrame {
|
||||
margin-left: -30px;
|
||||
left: 50%;
|
||||
bottom: 28px !important;
|
||||
z-index: 1058 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: implement styling for react-multi-email */
|
||||
|
||||
/* !important to override react-dates */
|
||||
.DateRangePickerInput__withBorder {
|
||||
border: 0 !important;
|
||||
}
|
||||
.DateInput_input {
|
||||
border: 1px solid #d1d5db !important;
|
||||
border-radius: 2px !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
color: #000;
|
||||
padding: 11px 11px 9px !important;
|
||||
line-height: 16px !important;
|
||||
}
|
||||
|
||||
.DateInput_input__focused {
|
||||
border: 2px solid #000 !important;
|
||||
border-radius: 2px !important;
|
||||
box-shadow: none !important;
|
||||
padding: 10px 10px 9px !important;
|
||||
}
|
||||
|
||||
.DateRangePickerInput_arrow {
|
||||
padding: 0px 10px;
|
||||
}
|
||||
|
||||
.loader {
|
||||
display: block;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin: 60px auto;
|
||||
position: relative;
|
||||
border-width: 4px;
|
||||
border-style: solid;
|
||||
animation: loader 2s infinite ease;
|
||||
}
|
||||
|
||||
.loader-inner {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
animation: loader-inner 2s infinite ease-in;
|
||||
}
|
||||
|
||||
.no-ring-inset {
|
||||
--tw-ring-inset: unset;
|
||||
}
|
||||
|
||||
@keyframes loader {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes loader-inner {
|
||||
0% {
|
||||
height: 0%;
|
||||
}
|
||||
|
||||
25% {
|
||||
height: 0%;
|
||||
}
|
||||
|
||||
50% {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
75% {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
height: 0%;
|
||||
}
|
||||
}
|
||||
|
||||
.text-inverted-important {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.transition-max-width {
|
||||
-webkit-transition-property: max-width;
|
||||
transition-property: max-width;
|
||||
}
|
||||
}
|
||||
|
||||
#timeZone input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* react-date-picker forces a border upon us, cast it away */
|
||||
.react-date-picker__wrapper {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.react-date-picker__inputGroup__input {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* animations */
|
||||
.slideInBottom {
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: both;
|
||||
animation-name: slideInBottom;
|
||||
}
|
||||
|
||||
@keyframes slideInBottom {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30%);
|
||||
pointer-events: none;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* animations */
|
||||
.slideInTop {
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: both;
|
||||
animation-name: slideInTop;
|
||||
}
|
||||
|
||||
@keyframes slideInTop {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20%);
|
||||
pointer-events: none;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
transform: translateY(0%);
|
||||
}
|
||||
}
|
||||
|
||||
.fadeIn {
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: both;
|
||||
animation-name: fadeIn;
|
||||
animation-timing-function: ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure h-screen works on mobile Safari. By default h-screen
|
||||
* does not take into account the height of the address bar, causing
|
||||
* weird behaviour when scrolling — sometimes the height will be correct
|
||||
* and sometimes it won't, depending on whether the address bar is
|
||||
* in 'collapsed' state or not.
|
||||
* @see: https://benborgers.com/posts/tailwind-h-screen
|
||||
*/
|
||||
@supports (-webkit-touch-callout: none) {
|
||||
.h-screen {
|
||||
height: -webkit-fill-available;
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.react-tel-input .country-list .country:hover,
|
||||
.react-tel-input .country-list .country.highlight {
|
||||
@apply !bg-emphasis;
|
||||
}
|
||||
|
||||
.react-tel-input .flag-dropdown .selected-flag,
|
||||
.react-tel-input .flag-dropdown.open .selected-flag {
|
||||
@apply !bg-default;
|
||||
}
|
||||
|
||||
.react-tel-input .flag-dropdown {
|
||||
@apply !border-r-default left-0.5 !border-y-0 !border-l-0;
|
||||
}
|
||||
|
||||
.intercom-lightweight-app {
|
||||
@apply z-40 !important;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
// import AvatarDemo from "./_components/AvatarDemo";
|
||||
|
||||
export default function Home() {
|
||||
return <div className="p-4 font-[family-name:var(--font-geist-sans)]">{/* <AvatarDemo /> */}</div>;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { dirname } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { FlatCompat } from "@eslint/eslintrc";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
});
|
||||
|
||||
const eslintConfig = [
|
||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||
];
|
||||
|
||||
export default eslintConfig;
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"name": "ui-playground",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack --port=1337",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@calcom/config": "*",
|
||||
"@calcom/lib": "*",
|
||||
"@calcom/ui": "*",
|
||||
"next": "15.1.6",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "15.1.6",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,8 +0,0 @@
|
||||
import base from "@calcom/config/tailwind-preset";
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
...base,
|
||||
content: [...base.content],
|
||||
plugins: [...base.plugins, require("tailwindcss-animate")],
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { getBucket } from "abTest/utils";
|
||||
import type { NextMiddleware, NextRequest } from "next/server";
|
||||
import { NextResponse, URLPattern } from "next/server";
|
||||
|
||||
import { FUTURE_ROUTES_ENABLED_COOKIE_NAME, FUTURE_ROUTES_OVERRIDE_COOKIE_NAME } from "@calcom/lib/constants";
|
||||
|
||||
const ROUTES: [URLPattern, boolean][] = [
|
||||
["/apps/:slug/setup", process.env.APP_ROUTER_APPS_SLUG_SETUP_ENABLED === "1"] as const,
|
||||
["/team", process.env.APP_ROUTER_TEAM_ENABLED === "1"] as const,
|
||||
].map(([pathname, enabled]) => [
|
||||
new URLPattern({
|
||||
pathname,
|
||||
}),
|
||||
enabled,
|
||||
]);
|
||||
|
||||
export const abTestMiddlewareFactory =
|
||||
(next: (req: NextRequest) => Promise<NextResponse<unknown>>): NextMiddleware =>
|
||||
async (req: NextRequest) => {
|
||||
const response = await next(req);
|
||||
|
||||
const { pathname } = req.nextUrl;
|
||||
|
||||
const override = req.cookies.has(FUTURE_ROUTES_OVERRIDE_COOKIE_NAME);
|
||||
|
||||
const route = ROUTES.find(([regExp]) => regExp.test(req.url)) ?? null;
|
||||
const enabled = route !== null ? route[1] || override : false;
|
||||
|
||||
if (pathname.includes("future") || !enabled) {
|
||||
return response;
|
||||
}
|
||||
|
||||
const bucketValue = override ? "future" : req.cookies.get(FUTURE_ROUTES_ENABLED_COOKIE_NAME)?.value;
|
||||
|
||||
if (!bucketValue || !["future", "legacy"].includes(bucketValue)) {
|
||||
// cookie does not exist or it has incorrect value
|
||||
const bucket = getBucket();
|
||||
|
||||
response.cookies.set(FUTURE_ROUTES_ENABLED_COOKIE_NAME, bucket, {
|
||||
expires: Date.now() + 1000 * 60 * 30,
|
||||
httpOnly: true,
|
||||
}); // 30 min in ms
|
||||
|
||||
if (bucket === "legacy") {
|
||||
return response;
|
||||
}
|
||||
|
||||
const url = req.nextUrl.clone();
|
||||
url.pathname = `future${pathname}/`;
|
||||
|
||||
return NextResponse.rewrite(url, response);
|
||||
}
|
||||
|
||||
if (bucketValue === "legacy") {
|
||||
return response;
|
||||
}
|
||||
|
||||
const url = req.nextUrl.clone();
|
||||
url.pathname = `future${pathname}/`;
|
||||
|
||||
return NextResponse.rewrite(url, response);
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import { AB_TEST_BUCKET_PROBABILITY } from "@calcom/lib/constants";
|
||||
|
||||
const cryptoRandom = () => {
|
||||
return crypto.getRandomValues(new Uint8Array(1))[0] / 0xff;
|
||||
};
|
||||
|
||||
export const getBucket = () => {
|
||||
return cryptoRandom() * 100 < AB_TEST_BUCKET_PROBABILITY ? "future" : "legacy";
|
||||
};
|
||||
@@ -5,7 +5,7 @@ import { headers, cookies } from "next/headers";
|
||||
|
||||
import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
import { buildLegacyCtx, decodeParams } from "@lib/buildLegacyCtx";
|
||||
|
||||
import { getServerSideProps } from "@server/lib/[user]/[type]/getServerSideProps";
|
||||
|
||||
@@ -31,12 +31,14 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
|
||||
})),
|
||||
],
|
||||
};
|
||||
const decodedParams = decodeParams(params);
|
||||
const metadata = await generateMeetingMetadata(
|
||||
meeting,
|
||||
(t) => `${rescheduleUid && !!booking ? t("reschedule") : ""} ${title} | ${profileName}`,
|
||||
(t) => `${rescheduleUid ? t("reschedule") : ""} ${title}`,
|
||||
isBrandingHidden,
|
||||
getOrgFullOrigin(eventData?.entity.orgSlug ?? null)
|
||||
getOrgFullOrigin(eventData?.entity.orgSlug ?? null),
|
||||
`/${decodedParams.user}/${decodedParams.type}`
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { headers, cookies } from "next/headers";
|
||||
|
||||
import { getOrgFullOrigin } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
import { buildLegacyCtx, decodeParams } from "@lib/buildLegacyCtx";
|
||||
|
||||
import { getServerSideProps } from "@server/lib/[user]/getServerSideProps";
|
||||
|
||||
@@ -30,7 +30,8 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
|
||||
() => profile.name,
|
||||
() => markdownStrippedBio,
|
||||
false,
|
||||
getOrgFullOrigin(entity.orgSlug ?? null)
|
||||
getOrgFullOrigin(entity.orgSlug ?? null),
|
||||
`/${decodeParams(params).user}`
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -32,4 +32,4 @@ const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
|
||||
return <SetupView {...props} />;
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
export default ServerPage;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||
import type { PageProps as ServerPageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import type { routingServerSidePropsConfig } from "@calcom/app-store/routing-forms/pages/app-routing.config";
|
||||
import LayoutHandler from "@calcom/app-store/routing-forms/pages/layout-handler/[...appPages]";
|
||||
import Shell from "@calcom/features/shell/Shell";
|
||||
|
||||
import { getServerSideProps } from "@lib/apps/routing-forms/[...pages]/getServerSideProps";
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
const normalizePages = (pages: string[] | string | undefined) => {
|
||||
const normalizedPages = Array.isArray(pages) ? pages : pages?.split("/") ?? [];
|
||||
return {
|
||||
mainPage: normalizedPages[0],
|
||||
subPages: normalizedPages.slice(1),
|
||||
};
|
||||
};
|
||||
|
||||
export const generateMetadata = async ({ params }: { params: { pages: string[] } }) => {
|
||||
const { mainPage } = normalizePages(params.pages);
|
||||
return await _generateMetadata(
|
||||
// TODO: Need to show the actual form name instead of "Form"
|
||||
(t) => (mainPage === "routing-link" ? `Form | Cal.com Forms` : `${t("routing_forms")} | Cal.com Forms`),
|
||||
() => ""
|
||||
);
|
||||
};
|
||||
|
||||
type GetServerSidePropsResult =
|
||||
(typeof routingServerSidePropsConfig)[keyof typeof routingServerSidePropsConfig];
|
||||
const getData = withAppDirSsr<GetServerSidePropsResult>(getServerSideProps);
|
||||
|
||||
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
|
||||
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
|
||||
const props = await getData(context);
|
||||
const { mainPage, subPages } = normalizePages(params.pages);
|
||||
|
||||
const componentProps = {
|
||||
...props,
|
||||
pages: subPages,
|
||||
};
|
||||
|
||||
if (mainPage === "routing-link") {
|
||||
return <LayoutHandler {...componentProps} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Shell withoutMain withoutSeo>
|
||||
<LayoutHandler {...componentProps} />
|
||||
</Shell>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
@@ -0,0 +1,7 @@
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
const ServerPage = async () => {
|
||||
redirect("/apps/routing-forms/forms");
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
@@ -1,5 +1,7 @@
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
|
||||
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
|
||||
|
||||
import LegacyPage from "~/connect-and-join/connect-and-join-view";
|
||||
|
||||
export const generateMetadata = async () => {
|
||||
@@ -9,4 +11,11 @@ export const generateMetadata = async () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default LegacyPage;
|
||||
const ServerPage = async () => {
|
||||
return (
|
||||
<LicenseRequired>
|
||||
<LegacyPage />
|
||||
</LicenseRequired>
|
||||
);
|
||||
};
|
||||
export default ServerPage;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
import { UpgradeTip } from "@calcom/features/tips";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Icon, Button, ButtonGroup } from "@calcom/ui";
|
||||
|
||||
export default function UpgradeTipWrapper({ children }: { children: React.ReactNode }) {
|
||||
const { t } = useLocale();
|
||||
const session = useSession();
|
||||
const features = [
|
||||
{
|
||||
icon: <Icon name="users" className="h-5 w-5" />,
|
||||
title: t("view_bookings_across"),
|
||||
description: t("view_bookings_across_description"),
|
||||
},
|
||||
{
|
||||
icon: <Icon name="refresh-ccw" className="h-5 w-5" />,
|
||||
title: t("identify_booking_trends"),
|
||||
description: t("identify_booking_trends_description"),
|
||||
},
|
||||
{
|
||||
icon: <Icon name="user-plus" className="h-5 w-5" />,
|
||||
title: t("spot_popular_event_types"),
|
||||
description: t("spot_popular_event_types_description"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<UpgradeTip
|
||||
plan="team"
|
||||
title={t("make_informed_decisions")}
|
||||
description={t("make_informed_decisions_description")}
|
||||
features={features}
|
||||
background="/tips/insights"
|
||||
buttons={
|
||||
<div className="space-y-2 rtl:space-x-reverse sm:space-x-2">
|
||||
<ButtonGroup>
|
||||
<Button color="primary" href={`${WEBAPP_URL}/settings/teams/new`}>
|
||||
{t("create_team")}
|
||||
</Button>
|
||||
<Button color="minimal" href="https://go.cal.com/insights" target="_blank">
|
||||
{t("learn_more")}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
}>
|
||||
{!session.data?.user ? null : children}
|
||||
</UpgradeTip>
|
||||
);
|
||||
}
|
||||
@@ -1,65 +1,15 @@
|
||||
"use client";
|
||||
|
||||
import { useSession } from "next-auth/react";
|
||||
import { getTranslate } from "app/_utils";
|
||||
|
||||
import Shell from "@calcom/features/shell/Shell";
|
||||
import { UpgradeTip } from "@calcom/features/tips";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { Button, ButtonGroup } from "@calcom/ui";
|
||||
import { Icon } from "@calcom/ui";
|
||||
|
||||
export default function InsightsLayout({ children }: { children: React.ReactNode }) {
|
||||
const { t } = useLocale();
|
||||
const session = useSession();
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: <Icon name="users" className="h-5 w-5" />,
|
||||
title: t("view_bookings_across"),
|
||||
description: t("view_bookings_across_description"),
|
||||
},
|
||||
{
|
||||
icon: <Icon name="refresh-ccw" className="h-5 w-5" />,
|
||||
title: t("identify_booking_trends"),
|
||||
description: t("identify_booking_trends_description"),
|
||||
},
|
||||
{
|
||||
icon: <Icon name="user-plus" className="h-5 w-5" />,
|
||||
title: t("spot_popular_event_types"),
|
||||
description: t("spot_popular_event_types_description"),
|
||||
},
|
||||
];
|
||||
import UpgradeTipWrapper from "./UpgradeTipWrapper";
|
||||
|
||||
export default async function InsightsLayout({ children }: { children: React.ReactNode }) {
|
||||
const t = await getTranslate();
|
||||
return (
|
||||
<div>
|
||||
<Shell
|
||||
withoutMain={false}
|
||||
withoutSeo={true}
|
||||
heading={t("insights")}
|
||||
subtitle={t("insights_subtitle")}
|
||||
title={t("insights")}
|
||||
description={t("insights_subtitle")}>
|
||||
<UpgradeTip
|
||||
plan="team"
|
||||
title={t("make_informed_decisions")}
|
||||
description={t("make_informed_decisions_description")}
|
||||
features={features}
|
||||
background="/tips/insights"
|
||||
buttons={
|
||||
<div className="space-y-2 rtl:space-x-reverse sm:space-x-2">
|
||||
<ButtonGroup>
|
||||
<Button color="primary" href={`${WEBAPP_URL}/settings/teams/new`}>
|
||||
{t("create_team")}
|
||||
</Button>
|
||||
<Button color="minimal" href="https://go.cal.com/insights" target="_blank">
|
||||
{t("learn_more")}
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
}>
|
||||
{!session.data?.user ? null : children}
|
||||
</UpgradeTip>
|
||||
<Shell withoutMain={false} withoutSeo={true} heading={t("insights")} subtitle={t("insights_subtitle")}>
|
||||
<UpgradeTipWrapper>{children}</UpgradeTipWrapper>
|
||||
</Shell>
|
||||
</div>
|
||||
);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ export const generateMetadata = async () =>
|
||||
);
|
||||
|
||||
const Page = () => {
|
||||
redirect("/[category]");
|
||||
redirect("/settings/admin/apps/calendar");
|
||||
};
|
||||
|
||||
export default Page;
|
||||
+1
-3
@@ -6,7 +6,7 @@ import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
|
||||
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
|
||||
|
||||
import SettingsLayoutAppDir from "../(settings-layout)/SettingsLayoutAppDir";
|
||||
import SettingsLayoutAppDir from "../(settings-layout)/layout";
|
||||
import type { AdminLayoutProps } from "./AdminLayoutAppDirClient";
|
||||
|
||||
const AdminLayoutAppDirClient = dynamic(() => import("./AdminLayoutAppDirClient"), {
|
||||
@@ -21,5 +21,3 @@ export default async function AdminLayoutAppDir(props: AdminLayoutAppDirProps) {
|
||||
|
||||
return await SettingsLayoutAppDir({ children: <AdminLayoutAppDirClient {...props} userRole={userRole} /> });
|
||||
}
|
||||
|
||||
export const getLayout = async (page: React.ReactElement) => await AdminLayoutAppDir({ children: page });
|
||||
+3
-4
@@ -13,10 +13,11 @@ const SettingsLayoutAppDirClient = dynamic(() => import("./SettingsLayoutAppDirC
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
type SettingsLayoutAppDir = Omit<SettingsLayoutProps, "currentOrg" | "otherTeams">;
|
||||
type SettingsLayoutAppDirProps = Omit<SettingsLayoutProps, "currentOrg" | "otherTeams">;
|
||||
|
||||
export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDir) {
|
||||
export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDirProps) {
|
||||
const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) });
|
||||
|
||||
const userId = session?.user?.id ?? -1;
|
||||
const orgId = session?.user?.org?.id ?? -1;
|
||||
let currentOrg = null;
|
||||
@@ -35,5 +36,3 @@ export default async function SettingsLayoutAppDir(props: SettingsLayoutAppDir)
|
||||
|
||||
return <SettingsLayoutAppDirClient {...props} currentOrg={currentOrg} otherTeams={otherTeams} />;
|
||||
}
|
||||
|
||||
export const getLayout = async (page: React.ReactElement) => await SettingsLayoutAppDir({ children: page });
|
||||
+1
-1
@@ -18,7 +18,7 @@ const Page = async () => {
|
||||
<SettingsHeader
|
||||
title={t("out_of_office")}
|
||||
description={t("out_of_office_description")}
|
||||
CTA={<CreateNewOutOfOfficeEntryButton />}>
|
||||
CTA={<CreateNewOutOfOfficeEntryButton data-testid="add_entry_ooo" />}>
|
||||
<OutOfOfficeEntriesList />
|
||||
</SettingsHeader>
|
||||
);
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import BillingPage, { generateMetadata } from "../../billing/page";
|
||||
|
||||
export { generateMetadata };
|
||||
|
||||
export default BillingPage;
|
||||
@@ -0,0 +1,4 @@
|
||||
import BillingPage, { generateMetadata } from "../../../billing/page";
|
||||
|
||||
export { generateMetadata };
|
||||
export default BillingPage;
|
||||
+15
-6
@@ -1,9 +1,11 @@
|
||||
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||
import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import type { inferSSRProps } from "@calcom/types/inferSSRProps";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
import { getServerSideProps } from "@lib/settings/license-key/new/getServerSideProps";
|
||||
|
||||
import CreateANewLicenseKeyForm, { LayoutWrapper } from "~/settings/license-key/new/new-view";
|
||||
@@ -14,8 +16,15 @@ export const generateMetadata = async () =>
|
||||
(t) => t("organizations_description")
|
||||
);
|
||||
|
||||
export default WithLayout({
|
||||
Page: CreateANewLicenseKeyForm,
|
||||
getLayout: LayoutWrapper,
|
||||
getData: withAppDirSsr<inferSSRProps<typeof getServerSideProps>>(getServerSideProps),
|
||||
});
|
||||
const getData = withAppDirSsr<inferSSRProps<typeof getServerSideProps>>(getServerSideProps);
|
||||
|
||||
const ServerPage = async ({ params, searchParams }: PageProps) => {
|
||||
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
|
||||
return (
|
||||
<LayoutWrapper>
|
||||
<CreateANewLicenseKeyForm />
|
||||
</LayoutWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
+14
-6
@@ -1,9 +1,12 @@
|
||||
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||
import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/about-view";
|
||||
|
||||
export const generateMetadata = async () =>
|
||||
@@ -14,8 +17,13 @@ export const generateMetadata = async () =>
|
||||
|
||||
const getData = withAppDirSsr(getServerSideProps);
|
||||
|
||||
export default WithLayout({
|
||||
Page: LegacyPage,
|
||||
getLayout: LayoutWrapper,
|
||||
getData,
|
||||
});
|
||||
const ServerPage = async ({ params, searchParams }: PageProps) => {
|
||||
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
|
||||
return (
|
||||
<LayoutWrapper>
|
||||
<LegacyPage />
|
||||
</LayoutWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
+14
-6
@@ -1,9 +1,12 @@
|
||||
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||
import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/add-teams-view";
|
||||
|
||||
export const generateMetadata = async () =>
|
||||
@@ -14,8 +17,13 @@ export const generateMetadata = async () =>
|
||||
|
||||
const getData = withAppDirSsr(getServerSideProps);
|
||||
|
||||
export default WithLayout({
|
||||
Page: LegacyPage,
|
||||
getLayout: LayoutWrapper,
|
||||
getData,
|
||||
});
|
||||
const ServerPage = async ({ params, searchParams }: PageProps) => {
|
||||
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
|
||||
return (
|
||||
<LayoutWrapper>
|
||||
<LegacyPage />
|
||||
</LayoutWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
+5
-4
@@ -1,5 +1,4 @@
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
|
||||
import MembersPage from "~/members/members-view";
|
||||
|
||||
@@ -9,6 +8,8 @@ export const generateMetadata = async () =>
|
||||
(t) => t("organization_description")
|
||||
);
|
||||
|
||||
export default WithLayout({
|
||||
Page: MembersPage,
|
||||
});
|
||||
const ServerPageWrapper = () => {
|
||||
return <MembersPage />;
|
||||
};
|
||||
|
||||
export default ServerPageWrapper;
|
||||
+14
-6
@@ -1,9 +1,12 @@
|
||||
import { withAppDirSsr } from "app/WithAppDirSsr";
|
||||
import type { PageProps } from "app/_types";
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
import { cookies, headers } from "next/headers";
|
||||
|
||||
import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
|
||||
|
||||
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
|
||||
|
||||
import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/onboard-members-view";
|
||||
|
||||
export const generateMetadata = async () =>
|
||||
@@ -14,8 +17,13 @@ export const generateMetadata = async () =>
|
||||
|
||||
const getData = withAppDirSsr(getServerSideProps);
|
||||
|
||||
export default WithLayout({
|
||||
Page: LegacyPage,
|
||||
getLayout: LayoutWrapper,
|
||||
getData,
|
||||
});
|
||||
const ServerPage = async ({ params, searchParams }: PageProps) => {
|
||||
await getData(buildLegacyCtx(headers(), cookies(), params, searchParams));
|
||||
return (
|
||||
<LayoutWrapper>
|
||||
<LegacyPage />
|
||||
</LayoutWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServerPage;
|
||||
+5
-2
@@ -1,5 +1,4 @@
|
||||
import { _generateMetadata } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
|
||||
import Page from "@calcom/features/ee/organizations/pages/settings/appearance";
|
||||
|
||||
@@ -9,4 +8,8 @@ export const generateMetadata = async () =>
|
||||
(t) => t("appearance_org_description")
|
||||
);
|
||||
|
||||
export default WithLayout({ Page });
|
||||
const ServerPageWrapper = () => {
|
||||
return <Page />;
|
||||
};
|
||||
|
||||
export default ServerPageWrapper;
|
||||
+4
-8
@@ -1,11 +1,9 @@
|
||||
import SettingsLayoutAppDir from "app/(use-page-wrapper)/settings/(settings-layout)/layout";
|
||||
import { _generateMetadata, getTranslate } from "app/_utils";
|
||||
import { WithLayout } from "app/layoutHOC";
|
||||
|
||||
import LegacyPage from "@calcom/features/ee/organizations/pages/members";
|
||||
import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
|
||||
|
||||
import SettingsLayoutAppDir from "../../(settings-layout)/SettingsLayoutAppDir";
|
||||
|
||||
export const generateMetadata = async () =>
|
||||
await _generateMetadata(
|
||||
(t) => t("organization_members"),
|
||||
@@ -15,14 +13,12 @@ export const generateMetadata = async () =>
|
||||
const Page = async () => {
|
||||
const t = await getTranslate();
|
||||
|
||||
return (
|
||||
const children = (
|
||||
<SettingsHeader title={t("organization_members")} description={t("organization_description")}>
|
||||
<LegacyPage />
|
||||
</SettingsHeader>
|
||||
);
|
||||
return await SettingsLayoutAppDir({ children, containerClassName: "lg:max-w-screen-2xl" });
|
||||
};
|
||||
|
||||
const getLayout = async (page: React.ReactElement) =>
|
||||
await SettingsLayoutAppDir({ children: page, containerClassName: "lg:max-w-screen-2xl" });
|
||||
|
||||
export default WithLayout({ ServerPage: Page, getServerLayout: getLayout })<"P">;
|
||||
export default Page;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user