refactor: v2 schedules (#15403)
* refactor: platform-types schedule types * refactor: lib add bidirectional schedule transformers api <-> atom * refactor: trpc handlers use renamed lib transformers * refactor: platform-libraries export new bi-directional transformers * chore: v2 update platform-libraries * chore: enable also old platform-libraries * fix: platform-types support previous types * refactor: versioning date * chore: version old schedules as schedules_2024_04_15 module * chore: version old schedules as schedules_2024_04_15 module * feat: new 2024_06_11 schedules module * feat: atoms use refactored schedule api * refactor: remove ?for=atom in schedules hooks * fix: unit test
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
"dependencies": {
|
||||
"@calcom/platform-constants": "*",
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2",
|
||||
"@calcom/platform-libraries-0.0.4": "npm:@calcom/platform-libraries@0.0.4",
|
||||
"@calcom/platform-types": "*",
|
||||
"@calcom/platform-utils": "*",
|
||||
"@calcom/prisma": "*",
|
||||
|
||||
@@ -30,7 +30,9 @@ export const bootstrap = (app: NestExpressApplication): NestExpressApplication =
|
||||
type: VersioningType.CUSTOM,
|
||||
extractor: (request: unknown) => {
|
||||
const headerVersion = (request as Request)?.headers[CAL_API_VERSION_HEADER] as string | undefined;
|
||||
console.log("asap header headerVersion", headerVersion);
|
||||
if (headerVersion && API_VERSIONS.includes(headerVersion as API_VERSIONS_ENUM)) {
|
||||
console.log("asap return header headerVersion", headerVersion);
|
||||
return headerVersion;
|
||||
}
|
||||
return VERSION_2024_04_15;
|
||||
|
||||
@@ -2,11 +2,10 @@ import { bootstrap } from "@/app";
|
||||
import { AppModule } from "@/app.module";
|
||||
import { GetBookingOutput } from "@/ee/bookings/outputs/get-booking.output";
|
||||
import { GetBookingsOutput } from "@/ee/bookings/outputs/get-bookings.output";
|
||||
import { CreateScheduleInput } from "@/ee/schedules/inputs/create-schedule.input";
|
||||
import { SchedulesModule } from "@/ee/schedules/schedules.module";
|
||||
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
|
||||
import { CreateScheduleInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-schedule.input";
|
||||
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
|
||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||
import { AvailabilitiesModule } from "@/modules/availabilities/availabilities.module";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
import { INestApplication } from "@nestjs/common";
|
||||
@@ -29,7 +28,7 @@ describe("Bookings Endpoints", () => {
|
||||
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let bookingsRepositoryFixture: BookingsRepositoryFixture;
|
||||
let schedulesService: SchedulesService;
|
||||
let schedulesService: SchedulesService_2024_04_15;
|
||||
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
|
||||
|
||||
const userEmail = "bookings-controller-e2e@api.com";
|
||||
@@ -43,7 +42,7 @@ describe("Bookings Endpoints", () => {
|
||||
const moduleRef = await withAccessTokenAuth(
|
||||
userEmail,
|
||||
Test.createTestingModule({
|
||||
imports: [AppModule, PrismaModule, AvailabilitiesModule, UsersModule, SchedulesModule],
|
||||
imports: [AppModule, PrismaModule, UsersModule, SchedulesModule_2024_04_15],
|
||||
})
|
||||
)
|
||||
.overrideGuard(PermissionsGuard)
|
||||
@@ -55,13 +54,13 @@ describe("Bookings Endpoints", () => {
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
bookingsRepositoryFixture = new BookingsRepositoryFixture(moduleRef);
|
||||
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
|
||||
schedulesService = moduleRef.get<SchedulesService>(SchedulesService);
|
||||
schedulesService = moduleRef.get<SchedulesService_2024_04_15>(SchedulesService_2024_04_15);
|
||||
|
||||
user = await userRepositoryFixture.create({
|
||||
email: userEmail,
|
||||
});
|
||||
|
||||
const userSchedule: CreateScheduleInput = {
|
||||
const userSchedule: CreateScheduleInput_2024_04_15 = {
|
||||
name: "working time",
|
||||
timeZone: "Europe/Rome",
|
||||
isDefault: true,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { bootstrap } from "@/app";
|
||||
import { AppModule } from "@/app.module";
|
||||
import { SchedulesModule } from "@/ee/schedules/schedules.module";
|
||||
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
|
||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||
import { AvailabilitiesModule } from "@/modules/availabilities/availabilities.module";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input";
|
||||
@@ -34,14 +33,7 @@ describe("Me Endpoints", () => {
|
||||
const moduleRef = await withAccessTokenAuth(
|
||||
userEmail,
|
||||
Test.createTestingModule({
|
||||
imports: [
|
||||
AppModule,
|
||||
PrismaModule,
|
||||
AvailabilitiesModule,
|
||||
UsersModule,
|
||||
TokensModule,
|
||||
SchedulesModule,
|
||||
],
|
||||
imports: [AppModule, PrismaModule, UsersModule, TokensModule, SchedulesModule_2024_04_15],
|
||||
})
|
||||
)
|
||||
.overrideGuard(PermissionsGuard)
|
||||
@@ -118,13 +110,13 @@ describe("Me Endpoints", () => {
|
||||
});
|
||||
|
||||
it("should not update user associated with access token given invalid time format", async () => {
|
||||
const bodyWithIncorrectTimeFormat: UpdateManagedUserInput = { timeFormat: 100 };
|
||||
const bodyWithIncorrectTimeFormat: UpdateManagedUserInput = { timeFormat: 100 as any };
|
||||
|
||||
return request(app.getHttpServer()).patch("/v2/me").send(bodyWithIncorrectTimeFormat).expect(400);
|
||||
});
|
||||
|
||||
it("should not update user associated with access token given invalid week start", async () => {
|
||||
const bodyWithIncorrectWeekStart: UpdateManagedUserInput = { weekStart: "waba luba dub dub" };
|
||||
const bodyWithIncorrectWeekStart: UpdateManagedUserInput = { weekStart: "waba luba dub dub" as any };
|
||||
|
||||
return request(app.getHttpServer()).patch("/v2/me").send(bodyWithIncorrectWeekStart).expect(400);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GetMeOutput } from "@/ee/me/outputs/get-me.output";
|
||||
import { UpdateMeOutput } from "@/ee/me/outputs/update-me.output";
|
||||
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
|
||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
@@ -23,7 +23,7 @@ import { userSchemaResponse } from "@calcom/platform-types";
|
||||
export class MeController {
|
||||
constructor(
|
||||
private readonly usersRepository: UsersRepository,
|
||||
private readonly schedulesRepository: SchedulesService
|
||||
private readonly schedulesRepository: SchedulesService_2024_04_15
|
||||
) {}
|
||||
|
||||
@Get("/")
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { MeController } from "@/ee/me/me.controller";
|
||||
import { SchedulesModule } from "@/ee/schedules/schedules.module";
|
||||
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [UsersModule, SchedulesModule, TokensModule],
|
||||
imports: [UsersModule, SchedulesModule_2024_04_15, TokensModule],
|
||||
controllers: [MeController],
|
||||
})
|
||||
export class MeModule {}
|
||||
|
||||
@@ -4,7 +4,8 @@ import { EventTypesModule } from "@/ee/event-types/event-types.module";
|
||||
import { GcalModule } from "@/ee/gcal/gcal.module";
|
||||
import { MeModule } from "@/ee/me/me.module";
|
||||
import { ProviderModule } from "@/ee/provider/provider.module";
|
||||
import { SchedulesModule } from "@/ee/schedules/schedules.module";
|
||||
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
|
||||
import { SchedulesModule_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.module";
|
||||
import { SlotsModule } from "@/modules/slots/slots.module";
|
||||
import type { MiddlewareConsumer, NestModule } from "@nestjs/common";
|
||||
import { Module } from "@nestjs/common";
|
||||
@@ -13,7 +14,8 @@ import { Module } from "@nestjs/common";
|
||||
imports: [
|
||||
GcalModule,
|
||||
ProviderModule,
|
||||
SchedulesModule,
|
||||
SchedulesModule_2024_04_15,
|
||||
SchedulesModule_2024_06_11,
|
||||
MeModule,
|
||||
EventTypesModule,
|
||||
CalendarsModule,
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { SchedulesController } from "@/ee/schedules/controllers/schedules.controller";
|
||||
import { SchedulesRepository } from "@/ee/schedules/schedules.repository";
|
||||
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
|
||||
import { AvailabilitiesModule } from "@/modules/availabilities/availabilities.module";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, AvailabilitiesModule, UsersModule, TokensModule],
|
||||
providers: [SchedulesRepository, SchedulesService],
|
||||
controllers: [SchedulesController],
|
||||
exports: [SchedulesService, SchedulesRepository],
|
||||
})
|
||||
export class SchedulesModule {}
|
||||
+17
-23
@@ -1,12 +1,11 @@
|
||||
import { bootstrap } from "@/app";
|
||||
import { AppModule } from "@/app.module";
|
||||
import { CreateScheduleInput } from "@/ee/schedules/inputs/create-schedule.input";
|
||||
import { CreateScheduleOutput } from "@/ee/schedules/outputs/create-schedule.output";
|
||||
import { GetSchedulesOutput } from "@/ee/schedules/outputs/get-schedules.output";
|
||||
import { UpdateScheduleOutput } from "@/ee/schedules/outputs/update-schedule.output";
|
||||
import { SchedulesModule } from "@/ee/schedules/schedules.module";
|
||||
import { CreateScheduleInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-schedule.input";
|
||||
import { CreateScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/create-schedule.output";
|
||||
import { GetSchedulesOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/get-schedules.output";
|
||||
import { UpdateScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/update-schedule.output";
|
||||
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
|
||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||
import { AvailabilitiesModule } from "@/modules/availabilities/availabilities.module";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
@@ -19,8 +18,8 @@ import { SchedulesRepositoryFixture } from "test/fixtures/repository/schedules.r
|
||||
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
|
||||
import { withAccessTokenAuth } from "test/utils/withAccessTokenAuth";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { UpdateScheduleInput } from "@calcom/platform-types";
|
||||
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_04_15 } from "@calcom/platform-constants";
|
||||
import { UpdateScheduleInput_2024_04_15 } from "@calcom/platform-types";
|
||||
|
||||
describe("Schedules Endpoints", () => {
|
||||
describe("User Authentication", () => {
|
||||
@@ -32,7 +31,7 @@ describe("Schedules Endpoints", () => {
|
||||
const userEmail = "schedules-controller-e2e@api.com";
|
||||
let user: User;
|
||||
|
||||
let createdSchedule: CreateScheduleOutput["data"];
|
||||
let createdSchedule: CreateScheduleOutput_2024_04_15["data"];
|
||||
const defaultAvailabilityDays = [1, 2, 3, 4, 5];
|
||||
const defaultAvailabilityStartTime = "1970-01-01T09:00:00.000Z";
|
||||
const defaultAvailabilityEndTime = "1970-01-01T17:00:00.000Z";
|
||||
@@ -41,14 +40,7 @@ describe("Schedules Endpoints", () => {
|
||||
const moduleRef = await withAccessTokenAuth(
|
||||
userEmail,
|
||||
Test.createTestingModule({
|
||||
imports: [
|
||||
AppModule,
|
||||
PrismaModule,
|
||||
AvailabilitiesModule,
|
||||
UsersModule,
|
||||
TokensModule,
|
||||
SchedulesModule,
|
||||
],
|
||||
imports: [AppModule, PrismaModule, UsersModule, TokensModule, SchedulesModule_2024_04_15],
|
||||
})
|
||||
)
|
||||
.overrideGuard(PermissionsGuard)
|
||||
@@ -79,7 +71,7 @@ describe("Schedules Endpoints", () => {
|
||||
const scheduleTimeZone = "Europe/Rome";
|
||||
const isDefault = true;
|
||||
|
||||
const body: CreateScheduleInput = {
|
||||
const body: CreateScheduleInput_2024_04_15 = {
|
||||
name: scheduleName,
|
||||
timeZone: scheduleTimeZone,
|
||||
isDefault,
|
||||
@@ -87,10 +79,11 @@ describe("Schedules Endpoints", () => {
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.post("/api/v2/schedules")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_04_15)
|
||||
.send(body)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
const responseData: CreateScheduleOutput = response.body;
|
||||
const responseData: CreateScheduleOutput_2024_04_15 = response.body;
|
||||
expect(responseData.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseData.data).toBeDefined();
|
||||
expect(responseData.data.isDefault).toEqual(isDefault);
|
||||
@@ -117,7 +110,7 @@ describe("Schedules Endpoints", () => {
|
||||
.get("/api/v2/schedules/default")
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseData: CreateScheduleOutput = response.body;
|
||||
const responseData: CreateScheduleOutput_2024_04_15 = response.body;
|
||||
expect(responseData.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseData.data).toBeDefined();
|
||||
expect(responseData.data.id).toEqual(createdSchedule.id);
|
||||
@@ -137,7 +130,7 @@ describe("Schedules Endpoints", () => {
|
||||
.get(`/api/v2/schedules`)
|
||||
.expect(200)
|
||||
.then((response) => {
|
||||
const responseData: GetSchedulesOutput = response.body;
|
||||
const responseData: GetSchedulesOutput_2024_04_15 = response.body;
|
||||
expect(responseData.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseData.data).toBeDefined();
|
||||
expect(responseData.data?.[0].id).toEqual(createdSchedule.id);
|
||||
@@ -155,16 +148,17 @@ describe("Schedules Endpoints", () => {
|
||||
it("should update schedule name", async () => {
|
||||
const newScheduleName = "new-schedule-name";
|
||||
|
||||
const body: UpdateScheduleInput = {
|
||||
const body: UpdateScheduleInput_2024_04_15 = {
|
||||
name: newScheduleName,
|
||||
};
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/schedules/${createdSchedule.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_04_15)
|
||||
.send(body)
|
||||
.expect(200)
|
||||
.then((response: any) => {
|
||||
const responseData: UpdateScheduleOutput = response.body;
|
||||
const responseData: UpdateScheduleOutput_2024_04_15 = response.body;
|
||||
expect(responseData.status).toEqual(SUCCESS_STATUS);
|
||||
expect(responseData.data).toBeDefined();
|
||||
expect(responseData.data.schedule.name).toEqual(newScheduleName);
|
||||
+28
-22
@@ -1,11 +1,11 @@
|
||||
import { CreateScheduleOutput } from "@/ee/schedules/outputs/create-schedule.output";
|
||||
import { DeleteScheduleOutput } from "@/ee/schedules/outputs/delete-schedule.output";
|
||||
import { GetDefaultScheduleOutput } from "@/ee/schedules/outputs/get-default-schedule.output";
|
||||
import { GetScheduleOutput } from "@/ee/schedules/outputs/get-schedule.output";
|
||||
import { GetSchedulesOutput } from "@/ee/schedules/outputs/get-schedules.output";
|
||||
import { UpdateScheduleOutput } from "@/ee/schedules/outputs/update-schedule.output";
|
||||
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { CreateScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/create-schedule.output";
|
||||
import { DeleteScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/delete-schedule.output";
|
||||
import { GetDefaultScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/get-default-schedule.output";
|
||||
import { GetScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/get-schedule.output";
|
||||
import { GetSchedulesOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/get-schedules.output";
|
||||
import { UpdateScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/update-schedule.output";
|
||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||
import { VERSION_2024_04_15_VALUE } from "@/lib/api-versions";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
|
||||
@@ -27,25 +27,25 @@ import { ApiResponse, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { Throttle } from "@nestjs/throttler";
|
||||
|
||||
import { SCHEDULE_READ, SCHEDULE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { UpdateScheduleInput } from "@calcom/platform-types";
|
||||
import { UpdateScheduleInput_2024_04_15 } from "@calcom/platform-types";
|
||||
|
||||
import { CreateScheduleInput } from "../inputs/create-schedule.input";
|
||||
import { CreateScheduleInput_2024_04_15 } from "../inputs/create-schedule.input";
|
||||
|
||||
@Controller({
|
||||
path: "/v2/schedules",
|
||||
version: API_VERSIONS_VALUES,
|
||||
version: VERSION_2024_04_15_VALUE,
|
||||
})
|
||||
@UseGuards(AccessTokenGuard, PermissionsGuard)
|
||||
@DocsTags("Schedules")
|
||||
export class SchedulesController {
|
||||
constructor(private readonly schedulesService: SchedulesService) {}
|
||||
export class SchedulesController_2024_04_15 {
|
||||
constructor(private readonly schedulesService: SchedulesService_2024_04_15) {}
|
||||
|
||||
@Post("/")
|
||||
@Permissions([SCHEDULE_WRITE])
|
||||
async createSchedule(
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Body() bodySchedule: CreateScheduleInput
|
||||
): Promise<CreateScheduleOutput> {
|
||||
@Body() bodySchedule: CreateScheduleInput_2024_04_15
|
||||
): Promise<CreateScheduleOutput_2024_04_15> {
|
||||
const schedule = await this.schedulesService.createUserSchedule(user.id, bodySchedule);
|
||||
const scheduleFormatted = await this.schedulesService.formatScheduleForAtom(user, schedule);
|
||||
|
||||
@@ -57,8 +57,14 @@ export class SchedulesController {
|
||||
|
||||
@Get("/default")
|
||||
@Permissions([SCHEDULE_READ])
|
||||
@ApiResponse({ status: 200, description: "Returns the default schedule", type: GetDefaultScheduleOutput })
|
||||
async getDefaultSchedule(@GetUser() user: UserWithProfile): Promise<GetDefaultScheduleOutput | null> {
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: "Returns the default schedule",
|
||||
type: GetDefaultScheduleOutput_2024_04_15,
|
||||
})
|
||||
async getDefaultSchedule(
|
||||
@GetUser() user: UserWithProfile
|
||||
): Promise<GetDefaultScheduleOutput_2024_04_15 | null> {
|
||||
const schedule = await this.schedulesService.getUserScheduleDefault(user.id);
|
||||
const scheduleFormatted = schedule
|
||||
? await this.schedulesService.formatScheduleForAtom(user, schedule)
|
||||
@@ -76,7 +82,7 @@ export class SchedulesController {
|
||||
async getSchedule(
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Param("scheduleId") scheduleId: number
|
||||
): Promise<GetScheduleOutput> {
|
||||
): Promise<GetScheduleOutput_2024_04_15> {
|
||||
const schedule = await this.schedulesService.getUserSchedule(user.id, scheduleId);
|
||||
const scheduleFormatted = await this.schedulesService.formatScheduleForAtom(user, schedule);
|
||||
|
||||
@@ -88,7 +94,7 @@ export class SchedulesController {
|
||||
|
||||
@Get("/")
|
||||
@Permissions([SCHEDULE_READ])
|
||||
async getSchedules(@GetUser() user: UserWithProfile): Promise<GetSchedulesOutput> {
|
||||
async getSchedules(@GetUser() user: UserWithProfile): Promise<GetSchedulesOutput_2024_04_15> {
|
||||
const schedules = await this.schedulesService.getUserSchedules(user.id);
|
||||
const schedulesFormatted = await this.schedulesService.formatSchedulesForAtom(user, schedules);
|
||||
|
||||
@@ -103,9 +109,9 @@ export class SchedulesController {
|
||||
@Permissions([SCHEDULE_WRITE])
|
||||
async updateSchedule(
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Body() bodySchedule: UpdateScheduleInput,
|
||||
@Body() bodySchedule: UpdateScheduleInput_2024_04_15,
|
||||
@Param("scheduleId") scheduleId: string
|
||||
): Promise<UpdateScheduleOutput> {
|
||||
): Promise<UpdateScheduleOutput_2024_04_15> {
|
||||
const updatedSchedule = await this.schedulesService.updateUserSchedule(
|
||||
user,
|
||||
Number(scheduleId),
|
||||
@@ -124,7 +130,7 @@ export class SchedulesController {
|
||||
async deleteSchedule(
|
||||
@GetUser("id") userId: number,
|
||||
@Param("scheduleId") scheduleId: number
|
||||
): Promise<DeleteScheduleOutput> {
|
||||
): Promise<DeleteScheduleOutput_2024_04_15> {
|
||||
await this.schedulesService.deleteUserSchedule(userId, scheduleId);
|
||||
|
||||
return {
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Transform, TransformFnParams } from "class-transformer";
|
||||
import { IsArray, IsDate, IsNumber } from "class-validator";
|
||||
|
||||
export class CreateAvailabilityInput {
|
||||
export class CreateAvailabilityInput_2024_04_15 {
|
||||
@IsArray()
|
||||
@IsNumber({}, { each: true })
|
||||
@ApiProperty({ example: [1, 2] })
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
import { CreateAvailabilityInput } from "@/modules/availabilities/inputs/create-availability.input";
|
||||
import { CreateAvailabilityInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-availability.input";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsArray, IsBoolean, IsTimeZone, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||
|
||||
export class CreateScheduleInput {
|
||||
export class CreateScheduleInput_2024_04_15 {
|
||||
@IsString()
|
||||
name!: string;
|
||||
|
||||
@@ -11,9 +11,9 @@ export class CreateScheduleInput {
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateAvailabilityInput)
|
||||
@Type(() => CreateAvailabilityInput_2024_04_15)
|
||||
@IsOptional()
|
||||
availabilities?: CreateAvailabilityInput[];
|
||||
availabilities?: CreateAvailabilityInput_2024_04_15[];
|
||||
|
||||
@IsBoolean()
|
||||
isDefault!: boolean;
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { ScheduleOutput } from "@/ee/schedules/outputs/schedule.output";
|
||||
import { ScheduleOutput } from "@/ee/schedules/schedules_2024_04_15/outputs/schedule.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class CreateScheduleOutput {
|
||||
export class CreateScheduleOutput_2024_04_15 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { IsEnum } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class DeleteScheduleOutput {
|
||||
export class DeleteScheduleOutput_2024_04_15 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { ScheduleOutput } from "@/ee/schedules/outputs/schedule.output";
|
||||
import { ScheduleOutput } from "@/ee/schedules/schedules_2024_04_15/outputs/schedule.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class GetDefaultScheduleOutput {
|
||||
export class GetDefaultScheduleOutput_2024_04_15 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { ScheduleOutput } from "@/ee/schedules/outputs/schedule.output";
|
||||
import { ScheduleOutput } from "@/ee/schedules/schedules_2024_04_15/outputs/schedule.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class GetScheduleOutput {
|
||||
export class GetScheduleOutput_2024_04_15 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import { ScheduleOutput } from "@/ee/schedules/outputs/schedule.output";
|
||||
import { ScheduleOutput } from "@/ee/schedules/schedules_2024_04_15/outputs/schedule.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsArray, IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class GetSchedulesOutput {
|
||||
export class GetSchedulesOutput_2024_04_15 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
+10
-10
@@ -1,7 +1,7 @@
|
||||
import { Type } from "class-transformer";
|
||||
import { IsBoolean, IsInt, IsOptional, IsString, ValidateNested, IsArray } from "class-validator";
|
||||
|
||||
class EventTypeModel {
|
||||
class EventTypeModel_2024_04_15 {
|
||||
@IsInt()
|
||||
id!: number;
|
||||
|
||||
@@ -10,7 +10,7 @@ class EventTypeModel {
|
||||
eventName?: string | null;
|
||||
}
|
||||
|
||||
class AvailabilityModel {
|
||||
class AvailabilityModel_2024_04_15 {
|
||||
@IsInt()
|
||||
id!: number;
|
||||
|
||||
@@ -46,7 +46,7 @@ class AvailabilityModel {
|
||||
date?: Date | null;
|
||||
}
|
||||
|
||||
class ScheduleModel {
|
||||
class ScheduleModel_2024_04_15 {
|
||||
@IsInt()
|
||||
id!: number;
|
||||
|
||||
@@ -62,21 +62,21 @@ class ScheduleModel {
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => EventTypeModel)
|
||||
@Type(() => EventTypeModel_2024_04_15)
|
||||
@IsArray()
|
||||
eventType?: EventTypeModel[];
|
||||
eventType?: EventTypeModel_2024_04_15[];
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => AvailabilityModel)
|
||||
@Type(() => AvailabilityModel_2024_04_15)
|
||||
@IsArray()
|
||||
availability?: AvailabilityModel[];
|
||||
availability?: AvailabilityModel_2024_04_15[];
|
||||
}
|
||||
|
||||
export class UpdatedScheduleOutput {
|
||||
export class UpdatedScheduleOutput_2024_04_15 {
|
||||
@ValidateNested()
|
||||
@Type(() => ScheduleModel)
|
||||
schedule!: ScheduleModel;
|
||||
@Type(() => ScheduleModel_2024_04_15)
|
||||
schedule!: ScheduleModel_2024_04_15;
|
||||
|
||||
@IsBoolean()
|
||||
isDefault!: boolean;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { UpdatedScheduleOutput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/outputs/schedule-updated.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class UpdateScheduleOutput_2024_04_15 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({
|
||||
type: UpdatedScheduleOutput_2024_04_15,
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => UpdatedScheduleOutput_2024_04_15)
|
||||
data!: UpdatedScheduleOutput_2024_04_15;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { SchedulesController_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/controllers/schedules.controller";
|
||||
import { SchedulesRepository_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.repository";
|
||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, UsersModule, TokensModule],
|
||||
providers: [SchedulesRepository_2024_04_15, SchedulesService_2024_04_15],
|
||||
controllers: [SchedulesController_2024_04_15],
|
||||
exports: [SchedulesService_2024_04_15, SchedulesRepository_2024_04_15],
|
||||
})
|
||||
export class SchedulesModule_2024_04_15 {}
|
||||
+5
-5
@@ -1,18 +1,18 @@
|
||||
import { CreateScheduleInput } from "@/ee/schedules/inputs/create-schedule.input";
|
||||
import { CreateAvailabilityInput } from "@/modules/availabilities/inputs/create-availability.input";
|
||||
import { CreateAvailabilityInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-availability.input";
|
||||
import { CreateScheduleInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-schedule.input";
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class SchedulesRepository {
|
||||
export class SchedulesRepository_2024_04_15 {
|
||||
constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {}
|
||||
|
||||
async createScheduleWithAvailabilities(
|
||||
userId: number,
|
||||
schedule: CreateScheduleInput,
|
||||
availabilities: CreateAvailabilityInput[]
|
||||
schedule: CreateScheduleInput_2024_04_15,
|
||||
availabilities: CreateAvailabilityInput_2024_04_15[]
|
||||
) {
|
||||
const createScheduleData: Prisma.ScheduleCreateInput = {
|
||||
user: {
|
||||
+25
-11
@@ -1,7 +1,7 @@
|
||||
import { CreateScheduleInput } from "@/ee/schedules/inputs/create-schedule.input";
|
||||
import { ScheduleOutput } from "@/ee/schedules/outputs/schedule.output";
|
||||
import { SchedulesRepository } from "@/ee/schedules/schedules.repository";
|
||||
import { AvailabilitiesService } from "@/modules/availabilities/availabilities.service";
|
||||
import { CreateAvailabilityInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-availability.input";
|
||||
import { CreateScheduleInput_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/inputs/create-schedule.input";
|
||||
import { ScheduleOutput } from "@/ee/schedules/schedules_2024_04_15/outputs/schedule.output";
|
||||
import { SchedulesRepository_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.repository";
|
||||
import { UserWithProfile, UsersRepository } from "@/modules/users/users.repository";
|
||||
import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Schedule } from "@prisma/client";
|
||||
@@ -14,13 +14,12 @@ import {
|
||||
transformAvailabilityForClient,
|
||||
transformDateOverridesForClient,
|
||||
} from "@calcom/platform-libraries-0.0.2";
|
||||
import { UpdateScheduleInput } from "@calcom/platform-types";
|
||||
import { UpdateScheduleInput_2024_04_15 } from "@calcom/platform-types";
|
||||
|
||||
@Injectable()
|
||||
export class SchedulesService {
|
||||
export class SchedulesService_2024_04_15 {
|
||||
constructor(
|
||||
private readonly schedulesRepository: SchedulesRepository,
|
||||
private readonly availabilitiesService: AvailabilitiesService,
|
||||
private readonly schedulesRepository: SchedulesRepository_2024_04_15,
|
||||
private readonly usersRepository: UsersRepository
|
||||
) {}
|
||||
|
||||
@@ -34,10 +33,10 @@ export class SchedulesService {
|
||||
return this.createUserSchedule(userId, schedule);
|
||||
}
|
||||
|
||||
async createUserSchedule(userId: number, schedule: CreateScheduleInput) {
|
||||
async createUserSchedule(userId: number, schedule: CreateScheduleInput_2024_04_15) {
|
||||
const availabilities = schedule.availabilities?.length
|
||||
? schedule.availabilities
|
||||
: [this.availabilitiesService.getDefaultAvailabilityInput()];
|
||||
: [this.getDefaultAvailabilityInput()];
|
||||
|
||||
const createdSchedule = await this.schedulesRepository.createScheduleWithAvailabilities(
|
||||
userId,
|
||||
@@ -76,7 +75,11 @@ export class SchedulesService {
|
||||
return this.schedulesRepository.getSchedulesByUserId(userId);
|
||||
}
|
||||
|
||||
async updateUserSchedule(user: UserWithProfile, scheduleId: number, bodySchedule: UpdateScheduleInput) {
|
||||
async updateUserSchedule(
|
||||
user: UserWithProfile,
|
||||
scheduleId: number,
|
||||
bodySchedule: UpdateScheduleInput_2024_04_15
|
||||
) {
|
||||
const existingSchedule = await this.schedulesRepository.getScheduleById(scheduleId);
|
||||
|
||||
if (!existingSchedule) {
|
||||
@@ -158,4 +161,15 @@ export class SchedulesService {
|
||||
throw new ForbiddenException(`User with ID=${userId} does not own schedule with ID=${schedule.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
getDefaultAvailabilityInput(): CreateAvailabilityInput_2024_04_15 {
|
||||
const startTime = new Date(new Date().setUTCHours(9, 0, 0, 0));
|
||||
const endTime = new Date(new Date().setUTCHours(17, 0, 0, 0));
|
||||
|
||||
return {
|
||||
days: [1, 2, 3, 4, 5],
|
||||
startTime,
|
||||
endTime,
|
||||
};
|
||||
}
|
||||
}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
import { bootstrap } from "@/app";
|
||||
import { AppModule } from "@/app.module";
|
||||
import { SchedulesModule_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.module";
|
||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
import { INestApplication } from "@nestjs/common";
|
||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { Test } from "@nestjs/testing";
|
||||
import { User } from "@prisma/client";
|
||||
import * as request from "supertest";
|
||||
import { SchedulesRepositoryFixture } from "test/fixtures/repository/schedules.repository.fixture";
|
||||
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
|
||||
import { withAccessTokenAuth } from "test/utils/withAccessTokenAuth";
|
||||
|
||||
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_06_11 } from "@calcom/platform-constants";
|
||||
import {
|
||||
CreateScheduleInput_2024_06_11,
|
||||
CreateScheduleOutput_2024_06_11,
|
||||
GetScheduleOutput_2024_06_11,
|
||||
GetSchedulesOutput_2024_06_11,
|
||||
ScheduleOutput_2024_06_11,
|
||||
UpdateScheduleOutput_2024_06_11,
|
||||
} from "@calcom/platform-types";
|
||||
import { UpdateScheduleInput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
describe("Schedules Endpoints", () => {
|
||||
describe("User Authentication", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let scheduleRepositoryFixture: SchedulesRepositoryFixture;
|
||||
|
||||
const userEmail = "schedules-controller-e2e@api.com";
|
||||
let user: User;
|
||||
|
||||
const createScheduleInput: CreateScheduleInput_2024_06_11 = {
|
||||
name: "work",
|
||||
timeZone: "Europe/Rome",
|
||||
isDefault: true,
|
||||
};
|
||||
|
||||
const defaultAvailability: CreateScheduleInput_2024_06_11["availability"] = [
|
||||
{
|
||||
days: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
startTime: "09:00",
|
||||
endTime: "17:00",
|
||||
},
|
||||
];
|
||||
|
||||
let createdSchedule: CreateScheduleOutput_2024_06_11["data"];
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await withAccessTokenAuth(
|
||||
userEmail,
|
||||
Test.createTestingModule({
|
||||
imports: [AppModule, PrismaModule, UsersModule, TokensModule, SchedulesModule_2024_06_11],
|
||||
})
|
||||
)
|
||||
.overrideGuard(PermissionsGuard)
|
||||
.useValue({
|
||||
canActivate: () => true,
|
||||
})
|
||||
.compile();
|
||||
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
scheduleRepositoryFixture = new SchedulesRepositoryFixture(moduleRef);
|
||||
user = await userRepositoryFixture.create({
|
||||
email: userEmail,
|
||||
});
|
||||
|
||||
app = moduleRef.createNestApplication();
|
||||
bootstrap(app as NestExpressApplication);
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(userRepositoryFixture).toBeDefined();
|
||||
expect(user).toBeDefined();
|
||||
});
|
||||
|
||||
it("should create a default schedule", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.post("/api/v2/schedules")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_11)
|
||||
.send(createScheduleInput)
|
||||
.expect(201)
|
||||
.then(async (response) => {
|
||||
const responseBody: CreateScheduleOutput_2024_06_11 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
createdSchedule = response.body.data;
|
||||
|
||||
const expectedSchedule = {
|
||||
...createScheduleInput,
|
||||
availability: defaultAvailability,
|
||||
overrides: [],
|
||||
};
|
||||
outputScheduleMatchesExpected(createdSchedule, expectedSchedule, 1);
|
||||
|
||||
const scheduleOwner = createdSchedule.ownerId
|
||||
? await userRepositoryFixture.get(createdSchedule.ownerId)
|
||||
: null;
|
||||
expect(scheduleOwner?.defaultScheduleId).toEqual(createdSchedule.id);
|
||||
});
|
||||
});
|
||||
|
||||
function outputScheduleMatchesExpected(
|
||||
outputSchedule: ScheduleOutput_2024_06_11 | null,
|
||||
expected: CreateScheduleInput_2024_06_11 & {
|
||||
availability: CreateScheduleInput_2024_06_11["availability"];
|
||||
} & {
|
||||
overrides: CreateScheduleInput_2024_06_11["overrides"];
|
||||
},
|
||||
expectedAvailabilityLength: number
|
||||
) {
|
||||
expect(outputSchedule).toBeTruthy();
|
||||
expect(outputSchedule?.name).toEqual(expected.name);
|
||||
expect(outputSchedule?.timeZone).toEqual(expected.timeZone);
|
||||
expect(outputSchedule?.isDefault).toEqual(expected.isDefault);
|
||||
expect(outputSchedule?.availability.length).toEqual(expectedAvailabilityLength);
|
||||
|
||||
const outputScheduleAvailability = outputSchedule?.availability[0];
|
||||
expect(outputScheduleAvailability).toBeDefined();
|
||||
expect(outputScheduleAvailability?.days).toEqual(expected.availability?.[0].days);
|
||||
expect(outputScheduleAvailability?.startTime).toEqual(expected.availability?.[0].startTime);
|
||||
expect(outputScheduleAvailability?.endTime).toEqual(expected.availability?.[0].endTime);
|
||||
|
||||
expect(JSON.stringify(outputSchedule?.overrides)).toEqual(JSON.stringify(expected.overrides));
|
||||
}
|
||||
|
||||
it("should get default schedule", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get("/api/v2/schedules/default")
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_11)
|
||||
.expect(200)
|
||||
.then(async (response) => {
|
||||
const responseBody: GetScheduleOutput_2024_06_11 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
const outputSchedule = responseBody.data;
|
||||
|
||||
const expectedSchedule = {
|
||||
...createScheduleInput,
|
||||
availability: defaultAvailability,
|
||||
overrides: [],
|
||||
};
|
||||
outputScheduleMatchesExpected(outputSchedule, expectedSchedule, 1);
|
||||
});
|
||||
});
|
||||
|
||||
it("should get schedules", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/api/v2/schedules`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_11)
|
||||
.expect(200)
|
||||
.then((response) => {
|
||||
const responseBody: GetSchedulesOutput_2024_06_11 = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
const outputSchedule = responseBody.data[0];
|
||||
|
||||
const expectedSchedule = {
|
||||
...createScheduleInput,
|
||||
availability: defaultAvailability,
|
||||
overrides: [],
|
||||
};
|
||||
outputScheduleMatchesExpected(outputSchedule, expectedSchedule, 1);
|
||||
});
|
||||
});
|
||||
|
||||
it("should update schedule name", async () => {
|
||||
const newScheduleName = "updated-schedule-name";
|
||||
|
||||
const body: UpdateScheduleInput_2024_06_11 = {
|
||||
name: newScheduleName,
|
||||
};
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/schedules/${createdSchedule.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_11)
|
||||
.send(body)
|
||||
.expect(200)
|
||||
.then((response: any) => {
|
||||
const responseData: UpdateScheduleOutput_2024_06_11 = response.body;
|
||||
expect(responseData.status).toEqual(SUCCESS_STATUS);
|
||||
const responseSchedule = responseData.data;
|
||||
|
||||
const expectedSchedule = { ...createdSchedule, name: newScheduleName };
|
||||
outputScheduleMatchesExpected(responseSchedule, expectedSchedule, 1);
|
||||
|
||||
createdSchedule = responseSchedule;
|
||||
});
|
||||
});
|
||||
|
||||
it("should add overrides", async () => {
|
||||
const overrides = [
|
||||
{
|
||||
date: "2026-05-05",
|
||||
startTime: "10:00",
|
||||
endTime: "12:00",
|
||||
},
|
||||
];
|
||||
|
||||
const body: UpdateScheduleInput_2024_06_11 = {
|
||||
overrides,
|
||||
};
|
||||
|
||||
return request(app.getHttpServer())
|
||||
.patch(`/api/v2/schedules/${createdSchedule.id}`)
|
||||
.set(CAL_API_VERSION_HEADER, VERSION_2024_06_11)
|
||||
.send(body)
|
||||
.expect(200)
|
||||
.then((response: any) => {
|
||||
const responseData: UpdateScheduleOutput_2024_06_11 = response.body;
|
||||
expect(responseData.status).toEqual(SUCCESS_STATUS);
|
||||
const responseSchedule = responseData.data;
|
||||
|
||||
const expectedSchedule = { ...createdSchedule, overrides };
|
||||
outputScheduleMatchesExpected(responseSchedule, expectedSchedule, 1);
|
||||
|
||||
createdSchedule = responseSchedule;
|
||||
});
|
||||
});
|
||||
|
||||
it("should delete schedule", async () => {
|
||||
return request(app.getHttpServer()).delete(`/api/v2/schedules/${createdSchedule.id}`).expect(200);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await userRepositoryFixture.deleteByEmail(user.email);
|
||||
try {
|
||||
await scheduleRepositoryFixture.deleteById(createdSchedule.id);
|
||||
} catch (e) {}
|
||||
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service";
|
||||
import { VERSION_2024_06_11_VALUE } from "@/lib/api-versions";
|
||||
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
|
||||
import { Permissions } from "@/modules/auth/decorators/permissions/permissions.decorator";
|
||||
import { AccessTokenGuard } from "@/modules/auth/guards/access-token/access-token.guard";
|
||||
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
|
||||
import { UserWithProfile } from "@/modules/users/users.repository";
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Post,
|
||||
Patch,
|
||||
UseGuards,
|
||||
} from "@nestjs/common";
|
||||
import { ApiResponse, ApiTags as DocsTags } from "@nestjs/swagger";
|
||||
import { Throttle } from "@nestjs/throttler";
|
||||
|
||||
import { SCHEDULE_READ, SCHEDULE_WRITE, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import {
|
||||
CreateScheduleOutput_2024_06_11,
|
||||
CreateScheduleInput_2024_06_11,
|
||||
UpdateScheduleInput_2024_06_11,
|
||||
GetScheduleOutput_2024_06_11,
|
||||
UpdateScheduleOutput_2024_06_11,
|
||||
GetDefaultScheduleOutput_2024_06_11,
|
||||
DeleteScheduleOutput_2024_06_11,
|
||||
GetSchedulesOutput_2024_06_11,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
@Controller({
|
||||
path: "/v2/schedules",
|
||||
version: VERSION_2024_06_11_VALUE,
|
||||
})
|
||||
@UseGuards(AccessTokenGuard, PermissionsGuard)
|
||||
@DocsTags("Schedules")
|
||||
export class SchedulesController_2024_06_11 {
|
||||
constructor(private readonly schedulesService: SchedulesService_2024_06_11) {}
|
||||
|
||||
@Post("/")
|
||||
@Permissions([SCHEDULE_WRITE])
|
||||
async createSchedule(
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Body() bodySchedule: CreateScheduleInput_2024_06_11
|
||||
): Promise<CreateScheduleOutput_2024_06_11> {
|
||||
const schedule = await this.schedulesService.createUserSchedule(user.id, bodySchedule);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: schedule,
|
||||
};
|
||||
}
|
||||
|
||||
@Get("/default")
|
||||
@Permissions([SCHEDULE_READ])
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: "Returns the default schedule",
|
||||
type: GetDefaultScheduleOutput_2024_06_11,
|
||||
})
|
||||
async getDefaultSchedule(@GetUser() user: UserWithProfile): Promise<GetScheduleOutput_2024_06_11> {
|
||||
const schedule = await this.schedulesService.getUserScheduleDefault(user.id);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: schedule,
|
||||
};
|
||||
}
|
||||
|
||||
@Get("/:scheduleId")
|
||||
@Permissions([SCHEDULE_READ])
|
||||
@Throttle({ default: { limit: 10, ttl: 60000 } }) // allow 10 requests per minute (for :scheduleId)
|
||||
async getSchedule(
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Param("scheduleId") scheduleId: number
|
||||
): Promise<GetScheduleOutput_2024_06_11> {
|
||||
const schedule = await this.schedulesService.getUserSchedule(user.id, scheduleId);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: schedule,
|
||||
};
|
||||
}
|
||||
|
||||
@Get("/")
|
||||
@Permissions([SCHEDULE_READ])
|
||||
async getSchedules(@GetUser() user: UserWithProfile): Promise<GetSchedulesOutput_2024_06_11> {
|
||||
const schedules = await this.schedulesService.getUserSchedules(user.id);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: schedules,
|
||||
};
|
||||
}
|
||||
|
||||
@Patch("/:scheduleId")
|
||||
@Permissions([SCHEDULE_WRITE])
|
||||
async updateSchedule(
|
||||
@GetUser() user: UserWithProfile,
|
||||
@Body() bodySchedule: UpdateScheduleInput_2024_06_11,
|
||||
@Param("scheduleId") scheduleId: string
|
||||
): Promise<UpdateScheduleOutput_2024_06_11> {
|
||||
const updatedSchedule = await this.schedulesService.updateUserSchedule(
|
||||
user.id,
|
||||
Number(scheduleId),
|
||||
bodySchedule
|
||||
);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: updatedSchedule,
|
||||
};
|
||||
}
|
||||
|
||||
@Delete("/:scheduleId")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Permissions([SCHEDULE_WRITE])
|
||||
async deleteSchedule(
|
||||
@GetUser("id") userId: number,
|
||||
@Param("scheduleId") scheduleId: number
|
||||
): Promise<DeleteScheduleOutput_2024_06_11> {
|
||||
await this.schedulesService.deleteUserSchedule(userId, scheduleId);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { SchedulesController_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/controllers/schedules.controller";
|
||||
import { SchedulesRepository_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.repository";
|
||||
import { InputSchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/input-schedules.service";
|
||||
import { OutputSchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/output-schedules.service";
|
||||
import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, UsersModule, TokensModule],
|
||||
providers: [
|
||||
SchedulesRepository_2024_06_11,
|
||||
SchedulesService_2024_06_11,
|
||||
InputSchedulesService_2024_06_11,
|
||||
OutputSchedulesService_2024_06_11,
|
||||
],
|
||||
controllers: [SchedulesController_2024_06_11],
|
||||
exports: [SchedulesService_2024_06_11, SchedulesRepository_2024_06_11],
|
||||
})
|
||||
export class SchedulesModule_2024_06_11 {}
|
||||
@@ -0,0 +1,208 @@
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import type { CreateScheduleInput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
type InputScheduleAvailabilityTransformed = {
|
||||
days: number[];
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
};
|
||||
|
||||
type InputScheduleOverrideTransformed = {
|
||||
date: Date;
|
||||
startTime: Date;
|
||||
endTime: Date;
|
||||
};
|
||||
|
||||
type InputScheduleTransformed = Omit<CreateScheduleInput_2024_06_11, "availability" | "overrides"> & {
|
||||
availability: InputScheduleAvailabilityTransformed[];
|
||||
overrides: InputScheduleOverrideTransformed[];
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class SchedulesRepository_2024_06_11 {
|
||||
constructor(private readonly dbRead: PrismaReadService, private readonly dbWrite: PrismaWriteService) {}
|
||||
|
||||
async createSchedule(userId: number, schedule: Omit<InputScheduleTransformed, "isDefault">) {
|
||||
const { availability, overrides } = schedule;
|
||||
|
||||
const createScheduleData: Prisma.ScheduleCreateInput = {
|
||||
user: {
|
||||
connect: {
|
||||
id: userId,
|
||||
},
|
||||
},
|
||||
name: schedule.name,
|
||||
timeZone: schedule.timeZone,
|
||||
};
|
||||
|
||||
const availabilitiesAndOverrides: Prisma.AvailabilityCreateManyInput[] = [];
|
||||
|
||||
if (availability && availability.length > 0) {
|
||||
availability.forEach((availability) => {
|
||||
availabilitiesAndOverrides.push({
|
||||
days: availability.days,
|
||||
startTime: availability.startTime,
|
||||
endTime: availability.endTime,
|
||||
userId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (overrides && overrides.length > 0) {
|
||||
overrides.forEach((override) => {
|
||||
availabilitiesAndOverrides.push({
|
||||
date: override.date,
|
||||
startTime: override.startTime,
|
||||
endTime: override.endTime,
|
||||
userId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (availabilitiesAndOverrides.length > 0) {
|
||||
createScheduleData.availability = {
|
||||
createMany: {
|
||||
data: availabilitiesAndOverrides,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const createdSchedule = await this.dbWrite.prisma.schedule.create({
|
||||
data: {
|
||||
...createScheduleData,
|
||||
},
|
||||
include: {
|
||||
availability: true,
|
||||
},
|
||||
});
|
||||
|
||||
return createdSchedule;
|
||||
}
|
||||
|
||||
async getScheduleById(scheduleId: number) {
|
||||
const schedule = await this.dbRead.prisma.schedule.findUnique({
|
||||
where: {
|
||||
id: scheduleId,
|
||||
},
|
||||
include: {
|
||||
availability: true,
|
||||
},
|
||||
});
|
||||
|
||||
return schedule;
|
||||
}
|
||||
|
||||
async updateSchedule(
|
||||
userId: number,
|
||||
scheduleId: number,
|
||||
schedule: Partial<Omit<InputScheduleTransformed, "isDefault">>
|
||||
) {
|
||||
const { availability, overrides } = schedule;
|
||||
|
||||
const updateScheduleData: Prisma.ScheduleUpdateInput = {
|
||||
name: schedule.name,
|
||||
timeZone: schedule.timeZone,
|
||||
};
|
||||
|
||||
const availabilitiesAndOverrides: Prisma.AvailabilityCreateManyInput[] = [];
|
||||
|
||||
const deleteConditions = [];
|
||||
if (availability) {
|
||||
// note(Lauris): availabilities and overrides are stored in the same "Availability" table,
|
||||
// but availabilities have "date" field as null, while overrides have it as not null, so delete
|
||||
// condition below results in deleting only rows from Availability table that are availabilities.
|
||||
deleteConditions.push({
|
||||
scheduleId: { equals: scheduleId },
|
||||
date: null,
|
||||
});
|
||||
}
|
||||
|
||||
if (overrides) {
|
||||
// note(Lauris): availabilities and overrides are stored in the same "Availability" table,
|
||||
// but overrides have "date" field as not-null, while availabilities have it as null, so delete
|
||||
// condition below results in deleting only rows from Availability table that are overrides.
|
||||
deleteConditions.push({
|
||||
scheduleId: { equals: scheduleId },
|
||||
NOT: { date: null },
|
||||
});
|
||||
}
|
||||
|
||||
if (availability && availability.length > 0) {
|
||||
availability.forEach((availability) => {
|
||||
availabilitiesAndOverrides.push({
|
||||
days: availability.days,
|
||||
startTime: availability.startTime,
|
||||
endTime: availability.endTime,
|
||||
userId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (overrides && overrides.length > 0) {
|
||||
overrides.forEach((override) => {
|
||||
availabilitiesAndOverrides.push({
|
||||
date: override.date,
|
||||
startTime: override.startTime,
|
||||
endTime: override.endTime,
|
||||
userId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (availabilitiesAndOverrides.length > 0) {
|
||||
updateScheduleData.availability = {
|
||||
deleteMany: deleteConditions,
|
||||
createMany: {
|
||||
data: availabilitiesAndOverrides,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const updatedSchedule = await this.dbWrite.prisma.schedule.update({
|
||||
where: {
|
||||
id: scheduleId,
|
||||
},
|
||||
data: {
|
||||
...updateScheduleData,
|
||||
},
|
||||
include: {
|
||||
availability: true,
|
||||
},
|
||||
});
|
||||
|
||||
return updatedSchedule;
|
||||
}
|
||||
|
||||
async getSchedulesByUserId(userId: number) {
|
||||
const schedules = await this.dbRead.prisma.schedule.findMany({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
include: {
|
||||
availability: true,
|
||||
},
|
||||
});
|
||||
|
||||
return schedules;
|
||||
}
|
||||
|
||||
async deleteScheduleById(scheduleId: number) {
|
||||
return this.dbWrite.prisma.schedule.delete({
|
||||
where: {
|
||||
id: scheduleId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getUserSchedulesCount(userId: number) {
|
||||
return this.dbRead.prisma.schedule.count({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import {
|
||||
transformApiScheduleOverrides,
|
||||
transformApiScheduleAvailability,
|
||||
} from "@calcom/platform-libraries-0.0.4";
|
||||
import { CreateScheduleInput_2024_06_11, ScheduleAvailabilityInput_2024_06_11 } from "@calcom/platform-types";
|
||||
import { ScheduleOverrideInput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
@Injectable()
|
||||
export class InputSchedulesService_2024_06_11 {
|
||||
transformInputCreateSchedule(inputSchedule: CreateScheduleInput_2024_06_11) {
|
||||
const defaultAvailability: ScheduleAvailabilityInput_2024_06_11[] = [
|
||||
{
|
||||
days: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
startTime: "09:00",
|
||||
endTime: "17:00",
|
||||
},
|
||||
];
|
||||
const defaultOverrides: ScheduleOverrideInput_2024_06_11[] = [];
|
||||
|
||||
const availability = this.transformInputScheduleAvailability(
|
||||
inputSchedule.availability || defaultAvailability
|
||||
);
|
||||
const overrides = this.transformInputOverrides(inputSchedule.overrides || defaultOverrides);
|
||||
|
||||
const internalCreateSchedule = {
|
||||
...inputSchedule,
|
||||
availability,
|
||||
overrides,
|
||||
};
|
||||
|
||||
return internalCreateSchedule;
|
||||
}
|
||||
|
||||
transformInputScheduleAvailability(inputAvailability: ScheduleAvailabilityInput_2024_06_11[]) {
|
||||
return transformApiScheduleAvailability(inputAvailability);
|
||||
}
|
||||
|
||||
transformInputOverrides(inputOverrides: ScheduleOverrideInput_2024_06_11[]) {
|
||||
return transformApiScheduleOverrides(inputOverrides);
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
import { UsersRepository } from "@/modules/users/users.repository";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import type { Availability, Schedule } from "@prisma/client";
|
||||
|
||||
import { WeekDay } from "@calcom/platform-types";
|
||||
|
||||
@Injectable()
|
||||
export class OutputSchedulesService_2024_06_11 {
|
||||
constructor(private readonly usersRepository: UsersRepository) {}
|
||||
|
||||
async getResponseSchedule(databaseSchedule: Schedule & { availability: Availability[] }) {
|
||||
if (!databaseSchedule.timeZone) {
|
||||
throw new Error("Failed to create schedule because its timezone is not set.");
|
||||
}
|
||||
|
||||
const ownerDefaultScheduleId = await this.usersRepository.getUserScheduleDefaultId(
|
||||
databaseSchedule.userId
|
||||
);
|
||||
|
||||
const createdScheduleAvailabilities = databaseSchedule.availability.filter(
|
||||
(availability) => !!availability.days.length
|
||||
);
|
||||
const createdScheduleOverrides = databaseSchedule.availability.filter((override) => !!override.date);
|
||||
|
||||
return {
|
||||
id: databaseSchedule.id,
|
||||
ownerId: databaseSchedule.userId,
|
||||
name: databaseSchedule.name,
|
||||
timeZone: databaseSchedule.timeZone,
|
||||
availability: createdScheduleAvailabilities.map((availability) => ({
|
||||
days: availability.days.map(transformNumberToDay),
|
||||
startTime: this.padHoursMinutesWithZeros(
|
||||
availability.startTime.getUTCHours() + ":" + availability.startTime.getUTCMinutes()
|
||||
),
|
||||
endTime: this.padHoursMinutesWithZeros(
|
||||
availability.endTime.getUTCHours() + ":" + availability.endTime.getUTCMinutes()
|
||||
),
|
||||
})),
|
||||
isDefault: databaseSchedule.id === ownerDefaultScheduleId,
|
||||
overrides: createdScheduleOverrides.map((override) => ({
|
||||
date:
|
||||
override.date?.getUTCFullYear() +
|
||||
"-" +
|
||||
(override.date ? override.date.getUTCMonth() + 1 : "").toString().padStart(2, "0") +
|
||||
"-" +
|
||||
override.date?.getUTCDate().toString().padStart(2, "0"),
|
||||
startTime: this.padHoursMinutesWithZeros(
|
||||
override.startTime.getUTCHours() + ":" + override.startTime.getUTCMinutes()
|
||||
),
|
||||
endTime: this.padHoursMinutesWithZeros(
|
||||
override.endTime.getUTCHours() + ":" + override.endTime.getUTCMinutes()
|
||||
),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
padHoursMinutesWithZeros(hhMM: string) {
|
||||
const [hours, minutes] = hhMM.split(":");
|
||||
|
||||
const formattedHours = hours.padStart(2, "0");
|
||||
const formattedMinutes = minutes.padStart(2, "0");
|
||||
|
||||
return `${formattedHours}:${formattedMinutes}`;
|
||||
}
|
||||
}
|
||||
|
||||
function transformNumberToDay(day: number): WeekDay {
|
||||
const weekMap: { [key: number]: WeekDay } = {
|
||||
0: "Sunday",
|
||||
1: "Monday",
|
||||
2: "Tuesday",
|
||||
3: "Wednesday",
|
||||
4: "Thursday",
|
||||
5: "Friday",
|
||||
6: "Saturday",
|
||||
};
|
||||
return weekMap[day];
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
import { SchedulesRepository_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.repository";
|
||||
import { InputSchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/input-schedules.service";
|
||||
import { OutputSchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/output-schedules.service";
|
||||
import { UsersRepository } from "@/modules/users/users.repository";
|
||||
import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { Schedule } from "@prisma/client";
|
||||
|
||||
import { CreateScheduleInput_2024_06_11, ScheduleOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
import { UpdateScheduleInput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
@Injectable()
|
||||
export class SchedulesService_2024_06_11 {
|
||||
constructor(
|
||||
private readonly schedulesRepository: SchedulesRepository_2024_06_11,
|
||||
private readonly inputSchedulesService: InputSchedulesService_2024_06_11,
|
||||
private readonly outputSchedulesService: OutputSchedulesService_2024_06_11,
|
||||
private readonly usersRepository: UsersRepository
|
||||
) {}
|
||||
|
||||
async createUserDefaultSchedule(userId: number, timeZone: string) {
|
||||
const defaultSchedule = {
|
||||
isDefault: true,
|
||||
name: "Default schedule",
|
||||
timeZone,
|
||||
};
|
||||
|
||||
return this.createUserSchedule(userId, defaultSchedule);
|
||||
}
|
||||
|
||||
async createUserSchedule(
|
||||
userId: number,
|
||||
scheduleInput: CreateScheduleInput_2024_06_11
|
||||
): Promise<ScheduleOutput_2024_06_11> {
|
||||
const schedule = this.inputSchedulesService.transformInputCreateSchedule(scheduleInput);
|
||||
|
||||
const createdSchedule = await this.schedulesRepository.createSchedule(userId, schedule);
|
||||
|
||||
if (schedule.isDefault) {
|
||||
await this.usersRepository.setDefaultSchedule(userId, createdSchedule.id);
|
||||
}
|
||||
|
||||
return this.outputSchedulesService.getResponseSchedule(createdSchedule);
|
||||
}
|
||||
|
||||
async getUserScheduleDefault(userId: number) {
|
||||
const user = await this.usersRepository.findById(userId);
|
||||
|
||||
if (!user?.defaultScheduleId) return null;
|
||||
|
||||
const defaultSchedule = await this.schedulesRepository.getScheduleById(user.defaultScheduleId);
|
||||
|
||||
if (!defaultSchedule) return null;
|
||||
return this.outputSchedulesService.getResponseSchedule(defaultSchedule);
|
||||
}
|
||||
|
||||
async getUserSchedule(userId: number, scheduleId: number) {
|
||||
const existingSchedule = await this.schedulesRepository.getScheduleById(scheduleId);
|
||||
|
||||
if (!existingSchedule) {
|
||||
throw new NotFoundException(`Schedule with ID=${scheduleId} does not exist.`);
|
||||
}
|
||||
|
||||
this.checkUserOwnsSchedule(userId, existingSchedule);
|
||||
|
||||
return this.outputSchedulesService.getResponseSchedule(existingSchedule);
|
||||
}
|
||||
|
||||
async getUserSchedules(userId: number) {
|
||||
const schedules = await this.schedulesRepository.getSchedulesByUserId(userId);
|
||||
return Promise.all(
|
||||
schedules.map(async (schedule) => {
|
||||
return this.outputSchedulesService.getResponseSchedule(schedule);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async updateUserSchedule(userId: number, scheduleId: number, bodySchedule: UpdateScheduleInput_2024_06_11) {
|
||||
const existingSchedule = await this.schedulesRepository.getScheduleById(scheduleId);
|
||||
|
||||
if (!existingSchedule) {
|
||||
throw new NotFoundException(`Schedule with ID=${scheduleId} does not exist.`);
|
||||
}
|
||||
|
||||
this.checkUserOwnsSchedule(userId, existingSchedule);
|
||||
|
||||
const availability = bodySchedule.availability
|
||||
? this.inputSchedulesService.transformInputScheduleAvailability(bodySchedule.availability)
|
||||
: undefined;
|
||||
const overrides = bodySchedule.overrides
|
||||
? this.inputSchedulesService.transformInputOverrides(bodySchedule.overrides)
|
||||
: undefined;
|
||||
|
||||
if (bodySchedule.isDefault) {
|
||||
await this.usersRepository.setDefaultSchedule(userId, scheduleId);
|
||||
}
|
||||
|
||||
const updatedSchedule = await this.schedulesRepository.updateSchedule(userId, scheduleId, {
|
||||
...bodySchedule,
|
||||
availability,
|
||||
overrides,
|
||||
});
|
||||
|
||||
return this.outputSchedulesService.getResponseSchedule(updatedSchedule);
|
||||
}
|
||||
|
||||
async deleteUserSchedule(userId: number, scheduleId: number) {
|
||||
const existingSchedule = await this.schedulesRepository.getScheduleById(scheduleId);
|
||||
|
||||
if (!existingSchedule) {
|
||||
throw new BadRequestException(`Schedule with ID=${scheduleId} does not exist.`);
|
||||
}
|
||||
|
||||
this.checkUserOwnsSchedule(userId, existingSchedule);
|
||||
|
||||
return this.schedulesRepository.deleteScheduleById(scheduleId);
|
||||
}
|
||||
|
||||
checkUserOwnsSchedule(userId: number, schedule: Pick<Schedule, "id" | "userId">) {
|
||||
if (userId !== schedule.userId) {
|
||||
throw new ForbiddenException(`User with ID=${userId} does not own schedule with ID=${schedule.id}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
import { VersionValue } from "@nestjs/common/interfaces";
|
||||
|
||||
import { API_VERSIONS, VERSION_2024_04_15, VERSION_2024_05_21 } from "@calcom/platform-constants";
|
||||
import {
|
||||
API_VERSIONS,
|
||||
VERSION_2024_04_15,
|
||||
VERSION_2024_05_21,
|
||||
VERSION_2024_06_11,
|
||||
} from "@calcom/platform-constants";
|
||||
|
||||
export const API_VERSIONS_VALUES: VersionValue = API_VERSIONS as unknown as VersionValue;
|
||||
export const VERSION_2024_06_11_VALUE: VersionValue = VERSION_2024_06_11 as unknown as VersionValue;
|
||||
export const VERSION_2024_05_21_VALUE: VersionValue = VERSION_2024_05_21 as unknown as VersionValue;
|
||||
export const VERSION_2024_04_15_VALUE: VersionValue = VERSION_2024_04_15 as unknown as VersionValue;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { AvailabilitiesService } from "@/modules/availabilities/availabilities.service";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
providers: [AvailabilitiesService],
|
||||
exports: [AvailabilitiesService],
|
||||
})
|
||||
export class AvailabilitiesModule {}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { CreateAvailabilityInput } from "@/modules/availabilities/inputs/create-availability.input";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class AvailabilitiesService {
|
||||
getDefaultAvailabilityInput(): CreateAvailabilityInput {
|
||||
const startTime = new Date(new Date().setUTCHours(9, 0, 0, 0));
|
||||
const endTime = new Date(new Date().setUTCHours(17, 0, 0, 0));
|
||||
|
||||
return {
|
||||
days: [1, 2, 3, 4, 5],
|
||||
startTime,
|
||||
endTime,
|
||||
};
|
||||
}
|
||||
}
|
||||
-1
@@ -22,7 +22,6 @@ import {
|
||||
HttpStatus,
|
||||
Param,
|
||||
Patch,
|
||||
BadRequestException,
|
||||
Delete,
|
||||
Query,
|
||||
NotFoundException,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EventTypesModule } from "@/ee/event-types/event-types.module";
|
||||
import { SchedulesModule } from "@/ee/schedules/schedules.module";
|
||||
import { SchedulesModule_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/schedules.module";
|
||||
import { AuthModule } from "@/modules/auth/auth.module";
|
||||
import { BillingModule } from "@/modules/billing/billing.module";
|
||||
import { MembershipsModule } from "@/modules/memberships/memberships.module";
|
||||
@@ -32,7 +32,7 @@ import { Global, Module } from "@nestjs/common";
|
||||
OrganizationsModule,
|
||||
StripeModule,
|
||||
BillingModule,
|
||||
SchedulesModule,
|
||||
SchedulesModule_2024_04_15,
|
||||
],
|
||||
providers: [
|
||||
OAuthClientRepository,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EventTypesService } from "@/ee/event-types/services/event-types.service";
|
||||
import { SchedulesService } from "@/ee/schedules/services/schedules.service";
|
||||
import { SchedulesService_2024_04_15 } from "@/ee/schedules/schedules_2024_04_15/services/schedules.service";
|
||||
import { TokensRepository } from "@/modules/tokens/tokens.repository";
|
||||
import { CreateManagedUserInput } from "@/modules/users/inputs/create-managed-user.input";
|
||||
import { UpdateManagedUserInput } from "@/modules/users/inputs/update-managed-user.input";
|
||||
@@ -15,7 +15,7 @@ export class OAuthClientUsersService {
|
||||
private readonly userRepository: UsersRepository,
|
||||
private readonly tokensRepository: TokensRepository,
|
||||
private readonly eventTypesService: EventTypesService,
|
||||
private readonly schedulesService: SchedulesService
|
||||
private readonly schedulesService: SchedulesService_2024_04_15
|
||||
) {}
|
||||
|
||||
async createOauthClientUser(
|
||||
|
||||
@@ -173,6 +173,14 @@ export class UsersRepository {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getUserScheduleDefaultId(userId: number) {
|
||||
const user = await this.findById(userId);
|
||||
|
||||
if (!user?.defaultScheduleId) return null;
|
||||
|
||||
return user?.defaultScheduleId;
|
||||
}
|
||||
}
|
||||
|
||||
function capitalizeTimezone(timezone: string) {
|
||||
|
||||
@@ -808,14 +808,14 @@
|
||||
},
|
||||
"/v2/schedules": {
|
||||
"post": {
|
||||
"operationId": "SchedulesController_createSchedule",
|
||||
"operationId": "SchedulesController_2024_06_11_createSchedule",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateScheduleInput"
|
||||
"$ref": "#/components/schemas/CreateScheduleInput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -826,7 +826,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateScheduleOutput"
|
||||
"$ref": "#/components/schemas/CreateScheduleOutput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -837,7 +837,7 @@
|
||||
]
|
||||
},
|
||||
"get": {
|
||||
"operationId": "SchedulesController_getSchedules",
|
||||
"operationId": "SchedulesController_2024_06_11_getSchedules",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -845,7 +845,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetSchedulesOutput"
|
||||
"$ref": "#/components/schemas/GetSchedulesOutput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -858,7 +858,7 @@
|
||||
},
|
||||
"/v2/schedules/default": {
|
||||
"get": {
|
||||
"operationId": "SchedulesController_getDefaultSchedule",
|
||||
"operationId": "SchedulesController_2024_06_11_getDefaultSchedule",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -866,7 +866,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetDefaultScheduleOutput"
|
||||
"$ref": "#/components/schemas/GetDefaultScheduleOutput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -879,7 +879,7 @@
|
||||
},
|
||||
"/v2/schedules/{scheduleId}": {
|
||||
"get": {
|
||||
"operationId": "SchedulesController_getSchedule",
|
||||
"operationId": "SchedulesController_2024_06_11_getSchedule",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "scheduleId",
|
||||
@@ -896,7 +896,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetScheduleOutput"
|
||||
"$ref": "#/components/schemas/GetScheduleOutput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -907,7 +907,7 @@
|
||||
]
|
||||
},
|
||||
"patch": {
|
||||
"operationId": "SchedulesController_updateSchedule",
|
||||
"operationId": "SchedulesController_2024_06_11_updateSchedule",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "scheduleId",
|
||||
@@ -923,7 +923,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UpdateScheduleInput"
|
||||
"$ref": "#/components/schemas/UpdateScheduleInput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -934,7 +934,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/UpdateScheduleOutput"
|
||||
"$ref": "#/components/schemas/UpdateScheduleOutput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -945,7 +945,7 @@
|
||||
]
|
||||
},
|
||||
"delete": {
|
||||
"operationId": "SchedulesController_deleteSchedule",
|
||||
"operationId": "SchedulesController_2024_06_11_deleteSchedule",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "scheduleId",
|
||||
@@ -962,7 +962,7 @@
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DeleteScheduleOutput"
|
||||
"$ref": "#/components/schemas/DeleteScheduleOutput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3002,7 +3002,7 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"CreateAvailabilityInput": {
|
||||
"CreateAvailabilityInput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"days": {
|
||||
@@ -3030,7 +3030,7 @@
|
||||
"endTime"
|
||||
]
|
||||
},
|
||||
"CreateScheduleInput": {
|
||||
"CreateScheduleInput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
@@ -3042,7 +3042,7 @@
|
||||
"availabilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/CreateAvailabilityInput"
|
||||
"$ref": "#/components/schemas/CreateAvailabilityInput_2024_04_15"
|
||||
}
|
||||
},
|
||||
"isDefault": {
|
||||
@@ -3214,7 +3214,7 @@
|
||||
"readOnly"
|
||||
]
|
||||
},
|
||||
"CreateScheduleOutput": {
|
||||
"CreateScheduleOutput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -3234,7 +3234,7 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"GetDefaultScheduleOutput": {
|
||||
"GetDefaultScheduleOutput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -3259,7 +3259,7 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"GetScheduleOutput": {
|
||||
"GetScheduleOutput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -3279,7 +3279,7 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"GetSchedulesOutput": {
|
||||
"GetSchedulesOutput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -3299,7 +3299,7 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"UpdateScheduleInput": {
|
||||
"UpdateScheduleInput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timeZone": {
|
||||
@@ -3359,7 +3359,7 @@
|
||||
"schedule"
|
||||
]
|
||||
},
|
||||
"EventTypeModel": {
|
||||
"EventTypeModel_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -3374,7 +3374,50 @@
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"ScheduleModel": {
|
||||
"AvailabilityModel_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number"
|
||||
},
|
||||
"userId": {
|
||||
"type": "number",
|
||||
"nullable": true
|
||||
},
|
||||
"scheduleId": {
|
||||
"type": "number",
|
||||
"nullable": true
|
||||
},
|
||||
"eventTypeId": {
|
||||
"type": "number",
|
||||
"nullable": true
|
||||
},
|
||||
"days": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"startTime": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"endTime": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
},
|
||||
"date": {
|
||||
"format": "date-time",
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"days"
|
||||
]
|
||||
},
|
||||
"ScheduleModel_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -3393,13 +3436,13 @@
|
||||
"eventType": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/EventTypeModel"
|
||||
"$ref": "#/components/schemas/EventTypeModel_2024_04_15"
|
||||
}
|
||||
},
|
||||
"availability": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/AvailabilityModel"
|
||||
"$ref": "#/components/schemas/AvailabilityModel_2024_04_15"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -3409,11 +3452,11 @@
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"UpdatedScheduleOutput": {
|
||||
"UpdatedScheduleOutput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"schedule": {
|
||||
"$ref": "#/components/schemas/ScheduleModel"
|
||||
"$ref": "#/components/schemas/ScheduleModel_2024_04_15"
|
||||
},
|
||||
"isDefault": {
|
||||
"type": "boolean"
|
||||
@@ -3435,7 +3478,7 @@
|
||||
"isDefault"
|
||||
]
|
||||
},
|
||||
"UpdateScheduleOutput": {
|
||||
"UpdateScheduleOutput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -3447,7 +3490,7 @@
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/UpdatedScheduleOutput"
|
||||
"$ref": "#/components/schemas/UpdatedScheduleOutput_2024_04_15"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -3455,7 +3498,7 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"DeleteScheduleOutput": {
|
||||
"DeleteScheduleOutput_2024_04_15": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -3561,6 +3604,349 @@
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"ScheduleAvailabilityInput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"days": {
|
||||
"example": [
|
||||
"Monday",
|
||||
"Tuesday"
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"startTime": {
|
||||
"type": "string",
|
||||
"example": "09:00"
|
||||
},
|
||||
"endTime": {
|
||||
"type": "string",
|
||||
"example": "10:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"days",
|
||||
"startTime",
|
||||
"endTime"
|
||||
]
|
||||
},
|
||||
"ScheduleOverrideInput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"date": {
|
||||
"type": "string",
|
||||
"example": "2024-05-20"
|
||||
},
|
||||
"startTime": {
|
||||
"type": "string",
|
||||
"example": "12:00"
|
||||
},
|
||||
"endTime": {
|
||||
"type": "string",
|
||||
"example": "13:00"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"date",
|
||||
"startTime",
|
||||
"endTime"
|
||||
]
|
||||
},
|
||||
"CreateScheduleInput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "One-on-one coaching"
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "string",
|
||||
"example": "Europe/Rome"
|
||||
},
|
||||
"availability": {
|
||||
"example": [
|
||||
{
|
||||
"days": [
|
||||
"Monday",
|
||||
"Tuesday"
|
||||
],
|
||||
"startTime": "09:00",
|
||||
"endTime": "10:00"
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ScheduleAvailabilityInput_2024_06_11"
|
||||
}
|
||||
},
|
||||
"isDefault": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"overrides": {
|
||||
"example": [
|
||||
{
|
||||
"date": "2024-05-20",
|
||||
"startTime": "12:00",
|
||||
"endTime": "14:00"
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ScheduleOverrideInput_2024_06_11"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"timeZone",
|
||||
"isDefault"
|
||||
]
|
||||
},
|
||||
"ScheduleOutput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"example": 254
|
||||
},
|
||||
"ownerId": {
|
||||
"type": "number",
|
||||
"example": 478
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "One-on-one coaching"
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "string",
|
||||
"example": "Europe/Rome"
|
||||
},
|
||||
"availability": {
|
||||
"example": [
|
||||
{
|
||||
"days": [
|
||||
"Monday",
|
||||
"Tuesday"
|
||||
],
|
||||
"startTime": "09:00",
|
||||
"endTime": "10:00"
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ScheduleAvailabilityInput_2024_06_11"
|
||||
}
|
||||
},
|
||||
"isDefault": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"overrides": {
|
||||
"example": [
|
||||
{
|
||||
"date": "2024-05-20",
|
||||
"startTime": "12:00",
|
||||
"endTime": "13:00"
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ScheduleOverrideInput_2024_06_11"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"ownerId",
|
||||
"name",
|
||||
"timeZone",
|
||||
"availability",
|
||||
"isDefault",
|
||||
"overrides"
|
||||
]
|
||||
},
|
||||
"CreateScheduleOutput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": [
|
||||
"success",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/ScheduleOutput_2024_06_11"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"GetDefaultScheduleOutput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": [
|
||||
"success",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/ScheduleOutput_2024_06_11"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"GetScheduleOutput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": [
|
||||
"success",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"nullable": true,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ScheduleOutput_2024_06_11"
|
||||
}
|
||||
]
|
||||
},
|
||||
"error": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"GetSchedulesOutput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": [
|
||||
"success",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ScheduleOutput_2024_06_11"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"UpdateScheduleInput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "One-on-one coaching"
|
||||
},
|
||||
"timeZone": {
|
||||
"type": "string",
|
||||
"example": "Europe/Rome"
|
||||
},
|
||||
"availability": {
|
||||
"example": [
|
||||
{
|
||||
"days": [
|
||||
"Monday",
|
||||
"Tuesday"
|
||||
],
|
||||
"startTime": "09:00",
|
||||
"endTime": "10:00"
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ScheduleAvailabilityInput_2024_06_11"
|
||||
}
|
||||
},
|
||||
"isDefault": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"overrides": {
|
||||
"example": [
|
||||
{
|
||||
"date": "2024-05-20",
|
||||
"startTime": "12:00",
|
||||
"endTime": "14:00"
|
||||
}
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ScheduleOverrideInput_2024_06_11"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UpdateScheduleOutput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": [
|
||||
"success",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/ScheduleOutput_2024_06_11"
|
||||
},
|
||||
"error": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"DeleteScheduleOutput_2024_06_11": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": [
|
||||
"success",
|
||||
"error"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status"
|
||||
]
|
||||
},
|
||||
"MeOutput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -128,10 +128,10 @@ export function getWorkingHours(
|
||||
}
|
||||
|
||||
export function availabilityAsString(
|
||||
availability: Availability,
|
||||
availability: Pick<Availability, "days" | "startTime" | "endTime">,
|
||||
{ locale, hour12 }: { locale?: string; hour12?: boolean }
|
||||
) {
|
||||
const weekSpan = (availability: Availability) => {
|
||||
const weekSpan = (availability: Pick<Availability, "days" | "startTime" | "endTime">) => {
|
||||
const days = availability.days.slice(1).reduce(
|
||||
(days, day) => {
|
||||
if (days[days.length - 1].length === 1 && days[days.length - 1][0] === day - 1) {
|
||||
@@ -153,7 +153,7 @@ export function availabilityAsString(
|
||||
.join(", ");
|
||||
};
|
||||
|
||||
const timeSpan = (availability: Availability) => {
|
||||
const timeSpan = (availability: Pick<Availability, "days" | "startTime" | "endTime">) => {
|
||||
return `${new Intl.DateTimeFormat(locale, { hour: "numeric", minute: "numeric", hour12 }).format(
|
||||
new Date(availability.startTime.toISOString().slice(0, -1))
|
||||
)} - ${new Intl.DateTimeFormat(locale, { hour: "numeric", minute: "numeric", hour12 }).format(
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from "./client/transformers";
|
||||
export * from "./transformers";
|
||||
|
||||
+14
-21
@@ -1,33 +1,25 @@
|
||||
import type { Availability as AvailabilityModel, Schedule as ScheduleModel } from "@prisma/client";
|
||||
import type { Availability } from "@prisma/client";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { getWorkingHours } from "@calcom/lib/availability";
|
||||
import { yyyymmdd } from "@calcom/lib/date-fns";
|
||||
import type { Schedule, TimeRange } from "@calcom/types/schedule";
|
||||
|
||||
export type ScheduleWithAvailabilities = ScheduleModel & { availability: AvailabilityModel[] };
|
||||
type ScheduleAvailability = Pick<Availability, "days" | "startTime" | "endTime">[];
|
||||
type ScheduleOverride = Pick<Availability, "date" | "startTime" | "endTime">[];
|
||||
|
||||
export type ScheduleWithAvailabilitiesForWeb = Pick<ScheduleModel, "id" | "name"> & {
|
||||
isManaged: boolean;
|
||||
workingHours: ReturnType<typeof transformWorkingHoursForClient>;
|
||||
schedule: AvailabilityModel[];
|
||||
availability: ReturnType<typeof transformAvailabilityForClient>;
|
||||
timeZone: string;
|
||||
dateOverrides: ReturnType<typeof transformDateOverridesForClient>;
|
||||
isDefault: boolean;
|
||||
isLastSchedule: boolean;
|
||||
readOnly: boolean;
|
||||
};
|
||||
|
||||
export function transformWorkingHoursForClient(schedule: ScheduleWithAvailabilities) {
|
||||
export function transformWorkingHoursForAtom(schedule: {
|
||||
timeZone: string | null;
|
||||
availability: ScheduleAvailability;
|
||||
}) {
|
||||
return getWorkingHours(
|
||||
{ timeZone: schedule.timeZone || undefined, utcOffset: 0 },
|
||||
schedule.availability || []
|
||||
);
|
||||
}
|
||||
|
||||
export function transformAvailabilityForClient(schedule: ScheduleWithAvailabilities) {
|
||||
return transformScheduleToAvailabilityForClient(schedule).map((a) =>
|
||||
export function transformAvailabilityForAtom(schedule: { availability: ScheduleAvailability }) {
|
||||
return transformScheduleToAvailabilityForAtom(schedule).map((a) =>
|
||||
a.map((startAndEnd) => ({
|
||||
...startAndEnd,
|
||||
end: new Date(startAndEnd.end.toISOString().replace("23:59:00.000Z", "23:59:59.999Z")),
|
||||
@@ -35,7 +27,10 @@ export function transformAvailabilityForClient(schedule: ScheduleWithAvailabilit
|
||||
);
|
||||
}
|
||||
|
||||
export function transformDateOverridesForClient(schedule: ScheduleWithAvailabilities, timeZone: string) {
|
||||
export function transformDateOverridesForAtom(
|
||||
schedule: { availability: ScheduleOverride },
|
||||
timeZone: string
|
||||
) {
|
||||
return schedule.availability.reduce((acc, override) => {
|
||||
// only if future date override
|
||||
const currentUtcOffset = dayjs().tz(timeZone).utcOffset();
|
||||
@@ -70,9 +65,7 @@ export function transformDateOverridesForClient(schedule: ScheduleWithAvailabili
|
||||
}, [] as { ranges: TimeRange[] }[]);
|
||||
}
|
||||
|
||||
export const transformScheduleToAvailabilityForClient = (
|
||||
schedule: Partial<ScheduleModel> & { availability: AvailabilityModel[] }
|
||||
) => {
|
||||
export const transformScheduleToAvailabilityForAtom = (schedule: { availability: ScheduleAvailability }) => {
|
||||
return schedule.availability.reduce(
|
||||
(schedule: Schedule, availability) => {
|
||||
availability.days.forEach((day) => {
|
||||
@@ -0,0 +1,54 @@
|
||||
import type { ScheduleAvailabilityInput_2024_06_11 } from "@calcom/platform-types/schedules/schedules-2024-06-11";
|
||||
import type { ScheduleOverrideInput_2024_06_11 } from "@calcom/platform-types/schedules/schedules-2024-06-11";
|
||||
import type { WeekDay } from "@calcom/platform-types/schedules/schedules-2024-06-11";
|
||||
|
||||
export function transformApiScheduleAvailability(inputAvailability: ScheduleAvailabilityInput_2024_06_11[]) {
|
||||
return inputAvailability.map((availability) => ({
|
||||
days: availability.days.map(transformDayToNumber),
|
||||
startTime: createDateFromHoursMinutes(availability.startTime),
|
||||
endTime: createDateFromHoursMinutes(availability.endTime),
|
||||
}));
|
||||
}
|
||||
|
||||
export function transformApiScheduleOverrides(inputOverrides: ScheduleOverrideInput_2024_06_11[]) {
|
||||
return inputOverrides.map((override) => ({
|
||||
date: new Date(override.date),
|
||||
startTime: createDateFromHoursMinutes(override.startTime),
|
||||
endTime: createDateFromHoursMinutes(override.endTime),
|
||||
}));
|
||||
}
|
||||
|
||||
function createDateFromHoursMinutes(hoursMinutes: string): Date {
|
||||
const parts = hoursMinutes.split(":");
|
||||
|
||||
if (parts.length < 2) {
|
||||
throw new Error("Invalid time format. Please use 'hh:mm'.");
|
||||
}
|
||||
|
||||
const hours = parseInt(parts[0], 10);
|
||||
const minutes = parseInt(parts[1], 10);
|
||||
|
||||
if (isNaN(hours) || hours < 0 || hours > 23) {
|
||||
throw new Error("Hours must be a number between 0 and 23.");
|
||||
}
|
||||
if (isNaN(minutes) || minutes < 0 || minutes > 59) {
|
||||
throw new Error("Minutes must be a number between 0 and 59.");
|
||||
}
|
||||
|
||||
const utcDate = new Date(Date.UTC(1970, 0, 1, hours, minutes));
|
||||
|
||||
return utcDate;
|
||||
}
|
||||
|
||||
function transformDayToNumber(day: WeekDay): number {
|
||||
const weekMap: { [key in WeekDay]: number } = {
|
||||
Sunday: 0,
|
||||
Monday: 1,
|
||||
Tuesday: 2,
|
||||
Wednesday: 3,
|
||||
Thursday: 4,
|
||||
Friday: 5,
|
||||
Saturday: 6,
|
||||
};
|
||||
return weekMap[day];
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./for-atom";
|
||||
export * from "./from-api";
|
||||
@@ -62,6 +62,8 @@ export type CustomClassNames = {
|
||||
};
|
||||
};
|
||||
|
||||
export type Availability = Pick<Schedule, "days" | "startTime" | "endTime">;
|
||||
|
||||
type AvailabilitySettingsProps = {
|
||||
skeletonLabel?: string;
|
||||
schedule: {
|
||||
@@ -73,7 +75,7 @@ type AvailabilitySettingsProps = {
|
||||
workingHours: WorkingHours[];
|
||||
dateOverrides: { ranges: TimeRange[] }[];
|
||||
timeZone: string;
|
||||
schedule: Schedule[];
|
||||
schedule: Availability[];
|
||||
};
|
||||
travelSchedules?: RouterOutputs["viewer"]["getTravelSchedules"];
|
||||
handleDelete: () => void;
|
||||
@@ -289,7 +291,9 @@ export function AvailabilitySettings({
|
||||
schedule.schedule
|
||||
.filter((availability) => !!availability.days.length)
|
||||
.map((availability) => (
|
||||
<span key={availability.id} className={cn(customClassNames?.subtitlesClassName)}>
|
||||
<span
|
||||
key={availability.startTime.valueOf().toString()}
|
||||
className={cn(customClassNames?.subtitlesClassName)}>
|
||||
{availabilityAsString(availability, { locale: i18n.language, hour12: timeFormat === 12 })}
|
||||
<br />
|
||||
</span>
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
import type { ScheduleOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
import type { User } from "@calcom/prisma/client";
|
||||
|
||||
import { transformApiScheduleForAtom } from "./transformApiScheduleForAtom";
|
||||
|
||||
const SCHEDULE_OWNER_ID = 256;
|
||||
|
||||
describe("transformScheduleForAtom", () => {
|
||||
const user: Pick<User, "id" | "defaultScheduleId" | "timeZone"> = {
|
||||
id: SCHEDULE_OWNER_ID,
|
||||
defaultScheduleId: 139,
|
||||
timeZone: "America/New_York",
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should return null if user is not provided", () => {
|
||||
const schedule: ScheduleOutput_2024_06_11 | null = {
|
||||
id: 139,
|
||||
ownerId: SCHEDULE_OWNER_ID,
|
||||
name: "Default",
|
||||
timeZone: "America/Cancun",
|
||||
availability: [
|
||||
{
|
||||
days: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
startTime: "09:00",
|
||||
endTime: "17:00",
|
||||
},
|
||||
],
|
||||
isDefault: true,
|
||||
overrides: [],
|
||||
};
|
||||
|
||||
expect(transformApiScheduleForAtom(undefined, schedule, 1)).toBeNull();
|
||||
});
|
||||
|
||||
it("should return null if schedule is not provided", () => {
|
||||
expect(transformApiScheduleForAtom(user, null, 1)).toBeNull();
|
||||
});
|
||||
|
||||
it("should transform schedule correctly", () => {
|
||||
const schedule: ScheduleOutput_2024_06_11 = {
|
||||
id: 139,
|
||||
ownerId: SCHEDULE_OWNER_ID,
|
||||
name: "Default",
|
||||
timeZone: "America/Cancun",
|
||||
availability: [
|
||||
{
|
||||
days: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||||
startTime: "09:00",
|
||||
endTime: "17:00",
|
||||
},
|
||||
],
|
||||
isDefault: true,
|
||||
overrides: [],
|
||||
};
|
||||
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
|
||||
const expectedResult = {
|
||||
id: 139,
|
||||
name: "Default",
|
||||
isManaged: false,
|
||||
workingHours: [
|
||||
{
|
||||
days: [1, 2, 3, 4, 5],
|
||||
startTime: 540,
|
||||
endTime: 1020,
|
||||
userId: 256,
|
||||
},
|
||||
],
|
||||
schedule: [
|
||||
{
|
||||
userId: 256,
|
||||
scheduleId: 139,
|
||||
days: [1, 2, 3, 4, 5],
|
||||
startTime: new Date(Date.UTC(1970, 0, 1, 9, 0)),
|
||||
endTime: new Date(Date.UTC(1970, 0, 1, 17, 0)),
|
||||
date: null,
|
||||
},
|
||||
],
|
||||
availability: [
|
||||
[],
|
||||
[
|
||||
{
|
||||
start: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T09:00:00.000Z`
|
||||
),
|
||||
end: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T17:00:00.000Z`
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T09:00:00.000Z`
|
||||
),
|
||||
end: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T17:00:00.000Z`
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T09:00:00.000Z`
|
||||
),
|
||||
end: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T17:00:00.000Z`
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T09:00:00.000Z`
|
||||
),
|
||||
end: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T17:00:00.000Z`
|
||||
),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T09:00:00.000Z`
|
||||
),
|
||||
end: new Date(
|
||||
`${year}-${month.toString().padStart(2, "0")}-${day.toString().padStart(2, "0")}T17:00:00.000Z`
|
||||
),
|
||||
},
|
||||
],
|
||||
[],
|
||||
],
|
||||
timeZone: "America/Cancun",
|
||||
dateOverrides: [],
|
||||
isDefault: true,
|
||||
isLastSchedule: true,
|
||||
readOnly: false,
|
||||
};
|
||||
|
||||
const result = transformApiScheduleForAtom(user, schedule, 1);
|
||||
|
||||
expect(result).toEqual(expectedResult);
|
||||
});
|
||||
});
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
transformAvailabilityForAtom,
|
||||
transformDateOverridesForAtom,
|
||||
transformApiScheduleAvailability,
|
||||
transformApiScheduleOverrides,
|
||||
transformWorkingHoursForAtom,
|
||||
} from "@calcom/lib/schedules/transformers";
|
||||
import type { ScheduleOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
import type { User } from "@calcom/prisma/client";
|
||||
|
||||
export function transformApiScheduleForAtom(
|
||||
user: Pick<User, "id" | "defaultScheduleId" | "timeZone"> | undefined,
|
||||
schedule: ScheduleOutput_2024_06_11 | null | undefined,
|
||||
userSchedulesCount: number
|
||||
) {
|
||||
if (!user || !schedule) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const transformedSchedule = {
|
||||
...schedule,
|
||||
availability: transformApiScheduleAvailability(schedule.availability),
|
||||
overrides: transformApiScheduleOverrides(schedule.overrides),
|
||||
};
|
||||
|
||||
const combined = [...transformedSchedule.availability, ...transformedSchedule.overrides];
|
||||
const availability = combined.map((entry) => {
|
||||
return {
|
||||
...entry,
|
||||
userId: schedule.ownerId,
|
||||
scheduleId: schedule.id,
|
||||
days: "days" in entry ? entry.days : [],
|
||||
date: "date" in entry ? entry.date : null,
|
||||
};
|
||||
});
|
||||
|
||||
const atomSchedule = {
|
||||
...schedule,
|
||||
availability,
|
||||
userId: schedule.ownerId,
|
||||
};
|
||||
|
||||
const timeZone = schedule.timeZone || user.timeZone;
|
||||
const defaultScheduleId = user.defaultScheduleId;
|
||||
|
||||
return {
|
||||
id: schedule.id,
|
||||
name: schedule.name,
|
||||
isManaged: schedule.ownerId !== user.id,
|
||||
workingHours: transformWorkingHoursForAtom(atomSchedule),
|
||||
schedule: availability,
|
||||
availability: transformAvailabilityForAtom(atomSchedule),
|
||||
timeZone,
|
||||
dateOverrides: transformDateOverridesForAtom(atomSchedule, timeZone),
|
||||
isDefault: defaultScheduleId === schedule.id,
|
||||
isLastSchedule: userSchedulesCount <= 1,
|
||||
readOnly: schedule.ownerId !== user.id,
|
||||
};
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
import type { UpdateScheduleInput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
import type { AvailabilityFormValues } from "../types";
|
||||
import { transformAtomScheduleForApi } from "./transformAtomScheduleForApi";
|
||||
|
||||
describe("transformAtomScheduleForApi", () => {
|
||||
it("should transform atom schedule correctly to API format", () => {
|
||||
const input: AvailabilityFormValues = {
|
||||
name: "Default",
|
||||
schedule: [
|
||||
[],
|
||||
[
|
||||
{
|
||||
start: new Date("2024-05-14T09:00:00.000Z"),
|
||||
end: new Date("2024-05-14T17:00:00.000Z"),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date("2024-05-14T09:00:00.000Z"),
|
||||
end: new Date("2024-05-14T17:00:00.000Z"),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date("2024-05-14T09:00:00.000Z"),
|
||||
end: new Date("2024-05-14T17:00:00.000Z"),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date("2024-05-14T09:00:00.000Z"),
|
||||
end: new Date("2024-05-14T17:00:00.000Z"),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
start: new Date("2024-05-14T11:00:00.000Z"),
|
||||
end: new Date("2024-05-14T12:00:00.000Z"),
|
||||
},
|
||||
],
|
||||
[],
|
||||
],
|
||||
dateOverrides: [],
|
||||
timeZone: "America/Cancun",
|
||||
isDefault: true,
|
||||
};
|
||||
|
||||
const expectedOutput: UpdateScheduleInput_2024_06_11 = {
|
||||
name: "Default",
|
||||
timeZone: "America/Cancun",
|
||||
isDefault: true,
|
||||
availability: [
|
||||
{
|
||||
days: ["Monday", "Tuesday", "Wednesday", "Thursday"],
|
||||
startTime: "09:00",
|
||||
endTime: "17:00",
|
||||
},
|
||||
{
|
||||
days: ["Friday"],
|
||||
startTime: "11:00",
|
||||
endTime: "12:00",
|
||||
},
|
||||
],
|
||||
overrides: [],
|
||||
};
|
||||
|
||||
const result = transformAtomScheduleForApi(input);
|
||||
|
||||
expect(result).toEqual(expectedOutput);
|
||||
});
|
||||
});
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import type {
|
||||
ScheduleAvailabilityInput_2024_06_11,
|
||||
UpdateScheduleInput_2024_06_11,
|
||||
WeekDay,
|
||||
} from "@calcom/platform-types";
|
||||
|
||||
import type { AvailabilityFormValues } from "../types";
|
||||
|
||||
export function transformAtomScheduleForApi(body: AvailabilityFormValues): UpdateScheduleInput_2024_06_11 {
|
||||
const { name, schedule, dateOverrides, timeZone, isDefault } = body;
|
||||
|
||||
const overrides =
|
||||
dateOverrides.flatMap(
|
||||
(dateOverridesRanges) =>
|
||||
dateOverridesRanges?.ranges?.map((range) => ({
|
||||
date: `${range.start.getUTCFullYear}-${range.start.getUTCMonth}-${range.start.getUTCDate}`,
|
||||
startTime: `${range.start.getUTCHours}-${range.start.getUTCMinutes}`,
|
||||
endTime: `${range.end.getUTCHours}-${range.end.getUTCMinutes}`,
|
||||
})) ?? []
|
||||
) ?? [];
|
||||
|
||||
const availability = formatScheduleTime(schedule);
|
||||
|
||||
return { name, timeZone, isDefault, availability, overrides };
|
||||
}
|
||||
|
||||
function formatScheduleTime(
|
||||
weekSchedule: AvailabilityFormValues["schedule"]
|
||||
): UpdateScheduleInput_2024_06_11["availability"] {
|
||||
const daysOfWeek: WeekDay[] = [
|
||||
"Sunday",
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
];
|
||||
|
||||
const formattedSchedule = weekSchedule.map((daySchedule, index) =>
|
||||
daySchedule.map((event) => ({
|
||||
startTime: convertToHHMM(event.start.toISOString()),
|
||||
endTime: convertToHHMM(event.end.toISOString()),
|
||||
days: [daysOfWeek[index]],
|
||||
}))
|
||||
);
|
||||
|
||||
const timeMap: { [key: string]: ScheduleAvailabilityInput_2024_06_11 } = {};
|
||||
|
||||
formattedSchedule.flat().forEach((event) => {
|
||||
const timeKey = `${event.startTime}-${event.endTime}`;
|
||||
if (!timeMap[timeKey]) {
|
||||
timeMap[timeKey] = { startTime: event.startTime, endTime: event.endTime, days: [] };
|
||||
}
|
||||
timeMap[timeKey].days.push(...event.days);
|
||||
});
|
||||
|
||||
return Object.values(timeMap);
|
||||
}
|
||||
|
||||
function convertToHHMM(isoDate: string): string {
|
||||
const date = new Date(isoDate);
|
||||
const hours = date.getUTCHours().toString().padStart(2, "0");
|
||||
const minutes = date.getUTCMinutes().toString().padStart(2, "0");
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
+29
-32
@@ -1,16 +1,18 @@
|
||||
import type { ScheduleLabelsType } from "@calcom/features/schedules/components/Schedule";
|
||||
import type { ScheduleWithAvailabilitiesForWeb, UpdateScheduleOutputType } from "@calcom/platform-libraries";
|
||||
import type { ApiErrorResponse, ApiResponse, ApiSuccessResponse } from "@calcom/platform-types";
|
||||
import type { ApiErrorResponse, ApiResponse, ScheduleOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
import useClientSchedule from "../../hooks/useClientSchedule";
|
||||
import useDeleteSchedule from "../../hooks/useDeleteSchedule";
|
||||
import useDeleteSchedule from "../../hooks/schedules/useDeleteSchedule";
|
||||
import { useSchedule } from "../../hooks/schedules/useSchedule";
|
||||
import { useSchedules } from "../../hooks/schedules/useSchedules";
|
||||
import useUpdateSchedule from "../../hooks/schedules/useUpdateSchedule";
|
||||
import { useMe } from "../../hooks/useMe";
|
||||
import useUpdateSchedule from "../../hooks/useUpdateSchedule";
|
||||
import { AtomsWrapper } from "../../src/components/atoms-wrapper";
|
||||
import { useToast } from "../../src/components/ui/use-toast";
|
||||
import type { Schedule } from "../AvailabilitySettings";
|
||||
import type { Availability } from "../AvailabilitySettings";
|
||||
import type { CustomClassNames } from "../AvailabilitySettings";
|
||||
import { AvailabilitySettings } from "../AvailabilitySettings";
|
||||
import { transformApiScheduleForAtom } from "../atom-api-transformers/transformApiScheduleForAtom";
|
||||
import { transformAtomScheduleForApi } from "../atom-api-transformers/transformAtomScheduleForApi";
|
||||
import type { AvailabilityFormValues } from "../types";
|
||||
|
||||
type AvailabilitySettingsPlatformWrapperProps = {
|
||||
@@ -19,7 +21,7 @@ type AvailabilitySettingsPlatformWrapperProps = {
|
||||
tooltips: Partial<ScheduleLabelsType>;
|
||||
};
|
||||
customClassNames?: Partial<CustomClassNames>;
|
||||
onUpdateSuccess?: (res: ApiResponse<UpdateScheduleOutputType>) => void;
|
||||
onUpdateSuccess?: (res: ApiResponse<ScheduleOutput_2024_06_11>) => void;
|
||||
onUpdateError?: (err: ApiErrorResponse) => void;
|
||||
onDeleteSuccess?: (res: ApiResponse) => void;
|
||||
onDeleteError?: (err: ApiErrorResponse) => void;
|
||||
@@ -35,10 +37,10 @@ export const AvailabilitySettingsPlatformWrapper = ({
|
||||
onUpdateSuccess,
|
||||
disableEditableHeading = false,
|
||||
}: AvailabilitySettingsPlatformWrapperProps) => {
|
||||
const { isLoading, data: schedule } = useClientSchedule(id);
|
||||
const mySchedule = schedule as ApiSuccessResponse<ScheduleWithAvailabilitiesForWeb>;
|
||||
const { isLoading, data: schedule } = useSchedule(id);
|
||||
const { data: schedules } = useSchedules();
|
||||
const { data: me } = useMe();
|
||||
const userSchedule = mySchedule?.data;
|
||||
const atomSchedule = transformApiScheduleForAtom(me?.data, schedule, schedules?.length || 0);
|
||||
const { timeFormat } = me?.data || { timeFormat: null };
|
||||
const { toast } = useToast();
|
||||
|
||||
@@ -77,48 +79,43 @@ export const AvailabilitySettingsPlatformWrapper = ({
|
||||
};
|
||||
|
||||
const handleUpdate = async (id: number, body: AvailabilityFormValues) => {
|
||||
const transformedDateOverrides =
|
||||
body.dateOverrides.flatMap(
|
||||
(dateOverridesRanges) =>
|
||||
dateOverridesRanges?.ranges?.map((range) => ({ start: range.start, end: range.end })) ?? []
|
||||
) ?? [];
|
||||
|
||||
await updateSchedule({ ...body, scheduleId: id, dateOverrides: transformedDateOverrides });
|
||||
const updateBody = transformAtomScheduleForApi(body);
|
||||
updateSchedule({ id, ...updateBody });
|
||||
};
|
||||
|
||||
if (isLoading) return <div className="px-10 py-4 text-xl">Loading...</div>;
|
||||
|
||||
if (!userSchedule) return <div className="px-10 py-4 text-xl">No user schedule present</div>;
|
||||
if (!atomSchedule) return <div className="px-10 py-4 text-xl">No user schedule present</div>;
|
||||
|
||||
return (
|
||||
<AtomsWrapper>
|
||||
<AvailabilitySettings
|
||||
disableEditableHeading={disableEditableHeading}
|
||||
handleDelete={() => {
|
||||
userSchedule.id && handleDelete(userSchedule.id);
|
||||
atomSchedule.id && handleDelete(atomSchedule.id);
|
||||
}}
|
||||
handleSubmit={async (data) => {
|
||||
userSchedule.id && handleUpdate(userSchedule.id, data);
|
||||
atomSchedule.id && handleUpdate(atomSchedule.id, data);
|
||||
}}
|
||||
weekStart="Sunday"
|
||||
timeFormat={timeFormat}
|
||||
isLoading={isLoading}
|
||||
schedule={{
|
||||
name: userSchedule.name,
|
||||
id: userSchedule.id,
|
||||
isLastSchedule: userSchedule.isLastSchedule,
|
||||
isDefault: userSchedule.isDefault,
|
||||
workingHours: userSchedule.workingHours,
|
||||
dateOverrides: userSchedule.dateOverrides,
|
||||
timeZone: userSchedule.timeZone,
|
||||
availability: userSchedule.availability,
|
||||
name: atomSchedule.name,
|
||||
id: atomSchedule.id,
|
||||
isLastSchedule: atomSchedule.isLastSchedule,
|
||||
isDefault: atomSchedule.isDefault,
|
||||
workingHours: atomSchedule.workingHours,
|
||||
dateOverrides: atomSchedule.dateOverrides,
|
||||
timeZone: atomSchedule.timeZone,
|
||||
availability: atomSchedule.availability,
|
||||
schedule:
|
||||
userSchedule.schedule.reduce(
|
||||
(acc: Schedule[], avail: Schedule) => [
|
||||
atomSchedule.schedule.reduce(
|
||||
(acc: Availability[], avail: Availability) => [
|
||||
...acc,
|
||||
{ ...avail, startTime: new Date(avail.startTime), endTime: new Date(avail.endTime) },
|
||||
{ days: avail.days, startTime: new Date(avail.startTime), endTime: new Date(avail.endTime) },
|
||||
],
|
||||
[] as Schedule[]
|
||||
[]
|
||||
) || [],
|
||||
}}
|
||||
isDeleting={isDeletionInProgress}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { useEffect, type ReactNode } from "react";
|
||||
|
||||
import type { API_VERSIONS_ENUM } from "@calcom/platform-constants";
|
||||
import { VERSION_2024_04_15 } from "@calcom/platform-constants";
|
||||
import { VERSION_2024_06_11 } from "@calcom/platform-constants";
|
||||
|
||||
import http from "../lib/http";
|
||||
import { BaseCalProvider } from "./BaseCalProvider";
|
||||
@@ -40,7 +40,7 @@ export function CalProvider({
|
||||
children,
|
||||
autoUpdateTimezone = true,
|
||||
onTimezoneChange,
|
||||
version = VERSION_2024_04_15,
|
||||
version = VERSION_2024_06_11,
|
||||
}: CalProviderProps) {
|
||||
useEffect(() => {
|
||||
http.setVersionHeader(version);
|
||||
|
||||
+3
-3
@@ -4,8 +4,8 @@ import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { V2_ENDPOINTS } from "@calcom/platform-constants";
|
||||
import type { ApiResponse, ApiErrorResponse } from "@calcom/platform-types";
|
||||
|
||||
import http from "../lib/http";
|
||||
import { QUERY_KEY } from "./useClientSchedule";
|
||||
import http from "../../lib/http";
|
||||
import { QUERY_KEY } from "./useSchedule";
|
||||
|
||||
interface IUseDeleteScheduleProps {
|
||||
onSuccess?: (res: ApiResponse) => void;
|
||||
@@ -31,7 +31,7 @@ const useDeleteSchedule = (
|
||||
const mutation = useMutation<ApiResponse<undefined>, unknown, DeleteScheduleInput>({
|
||||
mutationFn: (data) => {
|
||||
const { id } = data;
|
||||
const pathname = `/${V2_ENDPOINTS.availability}/${id}?for=atom`;
|
||||
const pathname = `/${V2_ENDPOINTS.availability}/${id}`;
|
||||
|
||||
return http?.delete(pathname).then((res) => res.data);
|
||||
},
|
||||
@@ -0,0 +1,26 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { V2_ENDPOINTS, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { GetScheduleOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
import http from "../../lib/http";
|
||||
|
||||
export const QUERY_KEY = "user-schedule";
|
||||
|
||||
export const useSchedule = (id?: string) => {
|
||||
const pathname = id ? `/${V2_ENDPOINTS.availability}/${id}` : `/${V2_ENDPOINTS.availability}/default`;
|
||||
|
||||
const { isLoading, error, data } = useQuery({
|
||||
queryKey: [QUERY_KEY, id],
|
||||
queryFn: () => {
|
||||
return http.get<GetScheduleOutput_2024_06_11>(pathname).then((res) => {
|
||||
if (res.data.status === SUCCESS_STATUS) {
|
||||
return res.data.data;
|
||||
}
|
||||
throw new Error(res.data.error?.message);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return { isLoading, error, data };
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { V2_ENDPOINTS, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { GetSchedulesOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
import http from "../../lib/http";
|
||||
|
||||
export const QUERY_KEY = "user-schedules";
|
||||
|
||||
export const useSchedules = () => {
|
||||
const pathname = `/${V2_ENDPOINTS.availability}`;
|
||||
|
||||
const { isLoading, error, data } = useQuery({
|
||||
queryKey: [QUERY_KEY],
|
||||
queryFn: () => {
|
||||
return http.get<GetSchedulesOutput_2024_06_11>(pathname).then((res) => {
|
||||
if (res.data.status === SUCCESS_STATUS) {
|
||||
return res.data.data;
|
||||
}
|
||||
throw new Error(res.data.error?.message);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return { isLoading, error, data };
|
||||
};
|
||||
+9
-9
@@ -2,14 +2,14 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { V2_ENDPOINTS } from "@calcom/platform-constants";
|
||||
import type { UpdateScheduleOutputType } from "@calcom/platform-libraries";
|
||||
import type { ApiResponse, UpdateScheduleInput, ApiErrorResponse } from "@calcom/platform-types";
|
||||
import type { ApiResponse, UpdateScheduleInput_2024_06_11, ApiErrorResponse } from "@calcom/platform-types";
|
||||
import type { ScheduleOutput_2024_06_11 } from "@calcom/platform-types";
|
||||
|
||||
import http from "../lib/http";
|
||||
import { QUERY_KEY as ScheduleQueryKey } from "./useClientSchedule";
|
||||
import http from "../../lib/http";
|
||||
import { QUERY_KEY as ScheduleQueryKey } from "./useSchedule";
|
||||
|
||||
interface IPUpdateOAuthClient {
|
||||
onSuccess?: (res: ApiResponse<UpdateScheduleOutputType>) => void;
|
||||
onSuccess?: (res: ApiResponse<ScheduleOutput_2024_06_11>) => void;
|
||||
onError?: (err: ApiErrorResponse) => void;
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ const useUpdateSchedule = (
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const mutation = useMutation<
|
||||
ApiResponse<UpdateScheduleOutputType>,
|
||||
ApiResponse<ScheduleOutput_2024_06_11>,
|
||||
unknown,
|
||||
UpdateScheduleInput & { scheduleId: number }
|
||||
UpdateScheduleInput_2024_06_11 & { id: number }
|
||||
>({
|
||||
mutationFn: (data) => {
|
||||
const pathname = `/${V2_ENDPOINTS.availability}/${data.scheduleId}?for=atom`;
|
||||
const pathname = `/${V2_ENDPOINTS.availability}/${data.id}`;
|
||||
|
||||
return http.patch<ApiResponse<UpdateScheduleOutputType>>(pathname, data).then((res) => {
|
||||
return http.patch<ApiResponse<ScheduleOutput_2024_06_11>>(pathname, data).then((res) => {
|
||||
return res.data;
|
||||
});
|
||||
},
|
||||
@@ -1,31 +0,0 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { V2_ENDPOINTS, SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import type { ScheduleWithAvailabilitiesForWeb } from "@calcom/platform-libraries";
|
||||
import type { ApiResponse } from "@calcom/platform-types";
|
||||
|
||||
import http from "../lib/http";
|
||||
|
||||
export const QUERY_KEY = "user-schedule";
|
||||
|
||||
const useClientSchedule = (id?: string) => {
|
||||
const pathname = id
|
||||
? `/${V2_ENDPOINTS.availability}/${id}?for=atom`
|
||||
: `/${V2_ENDPOINTS.availability}/default?for=atom`;
|
||||
|
||||
const { isLoading, error, data } = useQuery({
|
||||
queryKey: [QUERY_KEY, id],
|
||||
queryFn: () => {
|
||||
return http.get<ApiResponse<ScheduleWithAvailabilitiesForWeb>>(pathname).then((res) => {
|
||||
if (res.data.status === SUCCESS_STATUS) {
|
||||
return res.data;
|
||||
}
|
||||
throw new Error(res.data.error.message);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return { isLoading, error, data };
|
||||
};
|
||||
|
||||
export default useClientSchedule;
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"moduleFileExtensions": ["js", "json", "ts"],
|
||||
"rootDir": ".",
|
||||
"testEnvironment": "node",
|
||||
"testRegex": ".*\\.spec\\.ts$",
|
||||
"transform": {
|
||||
"^.+\\.ts$": "ts-jest"
|
||||
}
|
||||
}
|
||||
@@ -8,22 +8,26 @@
|
||||
"scripts": {
|
||||
"dev": "yarn vite build --watch & npx tailwindcss -i ./globals.css -o ./globals.min.css --postcss --minify --watch",
|
||||
"build": "yarn vite build && npx tailwindcss -i ./globals.css -o ./globals.min.css --postcss --minify && mkdir ./dist/packages/prisma-client && cp -rf ../../../node_modules/.prisma/client/*.d.ts ./dist/packages/prisma-client",
|
||||
"publish": "rm -rf dist && yarn build && npm publish --access public"
|
||||
"publish": "rm -rf dist && yarn build && npm publish --access public",
|
||||
"test": "jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@calcom/platform-libraries": "0.0.2",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/react": "18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@vitejs/plugin-react": "^2.2.0",
|
||||
"@vitejs/plugin-react-swc": "^3.7.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"jest": "^29.7.0",
|
||||
"postcss": "^8.4.38",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-prefixer": "^3.0.0",
|
||||
"postcss-prefixwrap": "1.46.0",
|
||||
"rollup-plugin-node-builtins": "^2.1.2",
|
||||
"ts-jest": "^29.1.2",
|
||||
"typescript": "^4.9.4",
|
||||
"vite": "^5.0.10",
|
||||
"vite-plugin-dts": "^3.7.3",
|
||||
|
||||
@@ -51,9 +51,10 @@ export const X_CAL_CLIENT_ID = "x-cal-client-id";
|
||||
// HTTP status codes
|
||||
export const HTTP_CODE_TOKEN_EXPIRED = 498;
|
||||
|
||||
export const VERSION_2024_04_15 = "2024-04-15";
|
||||
export const VERSION_2024_06_11 = "2024-06-11";
|
||||
export const VERSION_2024_05_21 = "2024-05-21";
|
||||
export const API_VERSIONS = [VERSION_2024_04_15, VERSION_2024_05_21] as const;
|
||||
export const VERSION_2024_04_15 = "2024-04-15";
|
||||
export const API_VERSIONS = [VERSION_2024_06_11, VERSION_2024_04_15, VERSION_2024_05_21] as const;
|
||||
export type API_VERSIONS_ENUM = (typeof API_VERSIONS)[number];
|
||||
export type API_VERSIONS_TYPE = typeof API_VERSIONS;
|
||||
export const CAL_API_VERSION_HEADER = "cal-api-version";
|
||||
|
||||
@@ -48,14 +48,13 @@ export type { ConnectedDestinationCalendars } from "@calcom/lib/getConnectedDest
|
||||
export { getBusyCalendarTimes } from "@calcom/core/CalendarManager";
|
||||
|
||||
export {
|
||||
transformWorkingHoursForClient,
|
||||
transformAvailabilityForClient,
|
||||
transformDateOverridesForClient,
|
||||
} from "@calcom/lib/schedules/client/transformers";
|
||||
export type {
|
||||
ScheduleWithAvailabilities,
|
||||
ScheduleWithAvailabilitiesForWeb,
|
||||
} from "@calcom/lib/schedules/client/transformers";
|
||||
transformWorkingHoursForAtom,
|
||||
transformAvailabilityForAtom,
|
||||
transformDateOverridesForAtom,
|
||||
transformApiScheduleAvailability,
|
||||
transformApiScheduleOverrides,
|
||||
} from "@calcom/lib/schedules/transformers";
|
||||
|
||||
export type {
|
||||
BookingCreateBody,
|
||||
BookingResponse,
|
||||
|
||||
@@ -3,6 +3,6 @@ export * from "./api";
|
||||
export * from "./oauth-clients";
|
||||
export * from "./slots";
|
||||
export * from "./calendars";
|
||||
export * from "./schedules";
|
||||
export * from "./bookings";
|
||||
export * from "./billing";
|
||||
export * from "./schedules";
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./schedules-2024-06-11";
|
||||
export * from "./schedules-2024-04-15";
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./schedules";
|
||||
+7
-7
@@ -4,27 +4,27 @@ import { IsString, IsBoolean, IsOptional, ValidateNested, IsArray, IsDate } from
|
||||
import { DateTime } from "luxon";
|
||||
import { z } from "zod";
|
||||
|
||||
const scheduleSchema = z.object({
|
||||
const scheduleSchema_2024_04_15 = z.object({
|
||||
id: z.number().int(),
|
||||
userId: z.number().int(),
|
||||
name: z.string(),
|
||||
timeZone: z.string().nullish(),
|
||||
});
|
||||
|
||||
const availabilitySchema = z.object({
|
||||
const availabilitySchema_2024_04_15 = z.object({
|
||||
id: z.number().int(),
|
||||
days: z.number().int().array(),
|
||||
startTime: z.date(),
|
||||
endTime: z.date(),
|
||||
});
|
||||
|
||||
export const schemaScheduleResponse = z
|
||||
export const schemaScheduleResponse_2024_04_15 = z
|
||||
.object({})
|
||||
.merge(scheduleSchema)
|
||||
.merge(scheduleSchema_2024_04_15)
|
||||
.merge(
|
||||
z.object({
|
||||
availability: z
|
||||
.array(availabilitySchema)
|
||||
.array(availabilitySchema_2024_04_15)
|
||||
.transform((availabilities) =>
|
||||
availabilities.map((availability) => ({
|
||||
...availability,
|
||||
@@ -36,7 +36,7 @@ export const schemaScheduleResponse = z
|
||||
})
|
||||
);
|
||||
|
||||
export type ScheduleResponse = z.infer<typeof schemaScheduleResponse>;
|
||||
export type ScheduleResponse = z.infer<typeof schemaScheduleResponse_2024_04_15>;
|
||||
|
||||
class ScheduleItem {
|
||||
@IsString()
|
||||
@@ -56,7 +56,7 @@ class DateOverride {
|
||||
end!: Date;
|
||||
}
|
||||
|
||||
export class UpdateScheduleInput {
|
||||
export class UpdateScheduleInput_2024_04_15 {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@DocsProperty()
|
||||
@@ -0,0 +1,13 @@
|
||||
export const WEEK_DAYS = [
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday",
|
||||
] as const;
|
||||
|
||||
export type WeekDay = (typeof WEEK_DAYS)[number];
|
||||
|
||||
export const TIME_FORMAT_HH_MM = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./inputs";
|
||||
export * from "./outputs";
|
||||
export * from "./constants";
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import {
|
||||
IsBoolean,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
IsArray,
|
||||
Matches,
|
||||
IsISO8601,
|
||||
IsTimeZone,
|
||||
IsIn,
|
||||
} from "class-validator";
|
||||
|
||||
import type { WeekDay } from "../constants";
|
||||
import { TIME_FORMAT_HH_MM, WEEK_DAYS } from "../constants";
|
||||
|
||||
export class ScheduleAvailabilityInput_2024_06_11 {
|
||||
@IsArray()
|
||||
@IsIn(WEEK_DAYS, { each: true })
|
||||
@ApiProperty({ example: ["Monday", "Tuesday"] })
|
||||
days!: WeekDay[];
|
||||
|
||||
@IsString()
|
||||
@Matches(TIME_FORMAT_HH_MM, { message: "startTime must be a valid time format HH:MM" })
|
||||
@ApiProperty({ example: "09:00" })
|
||||
startTime!: string;
|
||||
|
||||
@IsString()
|
||||
@Matches(TIME_FORMAT_HH_MM, { message: "endTime must be a valid time format HH:MM" })
|
||||
@ApiProperty({ example: "10:00" })
|
||||
endTime!: string;
|
||||
}
|
||||
|
||||
export class ScheduleOverrideInput_2024_06_11 {
|
||||
@IsISO8601({ strict: true })
|
||||
@ApiProperty({ example: "2024-05-20" })
|
||||
date!: string;
|
||||
|
||||
@IsString()
|
||||
@Matches(TIME_FORMAT_HH_MM, { message: "startTime must be a valid time format HH:MM" })
|
||||
@ApiProperty({ example: "12:00" })
|
||||
startTime!: string;
|
||||
|
||||
@IsString()
|
||||
@Matches(TIME_FORMAT_HH_MM, { message: "endTime must be a valid time format HH:MM" })
|
||||
@ApiProperty({ example: "13:00" })
|
||||
endTime!: string;
|
||||
}
|
||||
|
||||
export class CreateScheduleInput_2024_06_11 {
|
||||
@IsString()
|
||||
@ApiProperty({ example: "One-on-one coaching" })
|
||||
name!: string;
|
||||
|
||||
@IsTimeZone()
|
||||
@ApiProperty({ example: "Europe/Rome" })
|
||||
timeZone!: string;
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ScheduleAvailabilityInput_2024_06_11)
|
||||
@ApiProperty({
|
||||
type: [ScheduleAvailabilityInput_2024_06_11],
|
||||
example: [
|
||||
{
|
||||
days: ["Monday", "Tuesday"],
|
||||
startTime: "09:00",
|
||||
endTime: "10:00",
|
||||
},
|
||||
],
|
||||
required: false,
|
||||
})
|
||||
availability?: ScheduleAvailabilityInput_2024_06_11[];
|
||||
|
||||
@IsBoolean()
|
||||
@ApiProperty({ example: true })
|
||||
isDefault!: boolean;
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ScheduleOverrideInput_2024_06_11)
|
||||
@ApiProperty({
|
||||
type: [ScheduleOverrideInput_2024_06_11],
|
||||
example: [
|
||||
{
|
||||
date: "2024-05-20",
|
||||
startTime: "12:00",
|
||||
endTime: "14:00",
|
||||
},
|
||||
],
|
||||
required: false,
|
||||
})
|
||||
overrides?: ScheduleOverrideInput_2024_06_11[];
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./create-schedule.input";
|
||||
export * from "./update-schedule.input";
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsString, IsBoolean, IsOptional, ValidateNested, IsArray, IsTimeZone } from "class-validator";
|
||||
|
||||
import {
|
||||
ScheduleAvailabilityInput_2024_06_11,
|
||||
ScheduleOverrideInput_2024_06_11,
|
||||
} from "./create-schedule.input";
|
||||
|
||||
export class UpdateScheduleInput_2024_06_11 {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@ApiProperty({ example: "One-on-one coaching", required: false })
|
||||
name?: string;
|
||||
|
||||
@IsTimeZone()
|
||||
@IsOptional()
|
||||
@ApiProperty({ example: "Europe/Rome", required: false })
|
||||
timeZone?: string;
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ScheduleAvailabilityInput_2024_06_11)
|
||||
@ApiProperty({
|
||||
type: [ScheduleAvailabilityInput_2024_06_11],
|
||||
example: [
|
||||
{
|
||||
days: ["Monday", "Tuesday"],
|
||||
startTime: "09:00",
|
||||
endTime: "10:00",
|
||||
},
|
||||
],
|
||||
required: false,
|
||||
})
|
||||
availability?: ScheduleAvailabilityInput_2024_06_11[];
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@ApiProperty({ example: true, required: false })
|
||||
isDefault?: boolean;
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ScheduleOverrideInput_2024_06_11)
|
||||
@ApiProperty({
|
||||
type: [ScheduleOverrideInput_2024_06_11],
|
||||
example: [
|
||||
{
|
||||
date: "2024-05-20",
|
||||
startTime: "12:00",
|
||||
endTime: "14:00",
|
||||
},
|
||||
],
|
||||
required: false,
|
||||
})
|
||||
overrides?: ScheduleOverrideInput_2024_06_11[];
|
||||
}
|
||||
+6
-6
@@ -1,20 +1,20 @@
|
||||
import { UpdatedScheduleOutput } from "@/ee/schedules/outputs/schedule-updated.output";
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class UpdateScheduleOutput {
|
||||
import { ScheduleOutput_2024_06_11 } from "./schedule.output";
|
||||
|
||||
export class CreateScheduleOutput_2024_06_11 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({
|
||||
type: UpdatedScheduleOutput,
|
||||
type: ScheduleOutput_2024_06_11,
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => UpdatedScheduleOutput)
|
||||
data!: UpdatedScheduleOutput;
|
||||
@Type(() => ScheduleOutput_2024_06_11)
|
||||
data!: ScheduleOutput_2024_06_11;
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { IsEnum } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
export class DeleteScheduleOutput_2024_06_11 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
import { ScheduleOutput_2024_06_11 } from "./schedule.output";
|
||||
|
||||
export class GetDefaultScheduleOutput_2024_06_11 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
@ApiProperty({
|
||||
type: ScheduleOutput_2024_06_11,
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => ScheduleOutput_2024_06_11)
|
||||
data!: ScheduleOutput_2024_06_11 | null;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
import { ScheduleOutput_2024_06_11 } from "./schedule.output";
|
||||
|
||||
export class GetScheduleOutput_2024_06_11 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({
|
||||
type: ScheduleOutput_2024_06_11,
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => ScheduleOutput_2024_06_11)
|
||||
data!: ScheduleOutput_2024_06_11 | null;
|
||||
|
||||
error?: Error;
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsArray, IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
import { ScheduleOutput_2024_06_11 } from "./schedule.output";
|
||||
|
||||
export class GetSchedulesOutput_2024_06_11 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({ type: [ScheduleOutput_2024_06_11] })
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ScheduleOutput_2024_06_11)
|
||||
@IsArray()
|
||||
data!: ScheduleOutput_2024_06_11[];
|
||||
|
||||
error?: Error;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from "./schedule.output";
|
||||
export * from "./get-schedule.output";
|
||||
export * from "./get-schedules.output";
|
||||
export * from "./get-default-schedule.output";
|
||||
export * from "./create-schedule.output";
|
||||
export * from "./update-schedule.output";
|
||||
export * from "./delete-schedule.output";
|
||||
@@ -0,0 +1,69 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import {
|
||||
IsBoolean,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
IsArray,
|
||||
IsTimeZone,
|
||||
IsNumber,
|
||||
} from "class-validator";
|
||||
|
||||
import {
|
||||
ScheduleAvailabilityInput_2024_06_11,
|
||||
ScheduleOverrideInput_2024_06_11,
|
||||
} from "../inputs/create-schedule.input";
|
||||
|
||||
export class ScheduleOutput_2024_06_11 {
|
||||
@IsNumber()
|
||||
@ApiProperty({ example: 254 })
|
||||
id!: number;
|
||||
|
||||
@IsNumber()
|
||||
@ApiProperty({ example: 478 })
|
||||
ownerId!: number;
|
||||
|
||||
@IsString()
|
||||
@ApiProperty({ example: "One-on-one coaching" })
|
||||
name!: string;
|
||||
|
||||
@IsTimeZone()
|
||||
@ApiProperty({ example: "Europe/Rome" })
|
||||
timeZone!: string;
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ScheduleAvailabilityInput_2024_06_11)
|
||||
@ApiProperty({
|
||||
type: [ScheduleAvailabilityInput_2024_06_11],
|
||||
example: [
|
||||
{
|
||||
days: ["Monday", "Tuesday"],
|
||||
startTime: "09:00",
|
||||
endTime: "10:00",
|
||||
},
|
||||
],
|
||||
})
|
||||
availability!: ScheduleAvailabilityInput_2024_06_11[];
|
||||
|
||||
@IsBoolean()
|
||||
@ApiProperty({ example: true })
|
||||
isDefault!: boolean;
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ScheduleOverrideInput_2024_06_11)
|
||||
@ApiProperty({
|
||||
type: [ScheduleOverrideInput_2024_06_11],
|
||||
example: [
|
||||
{
|
||||
date: "2024-05-20",
|
||||
startTime: "12:00",
|
||||
endTime: "13:00",
|
||||
},
|
||||
],
|
||||
})
|
||||
overrides!: ScheduleOverrideInput_2024_06_11[];
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsNotEmptyObject, ValidateNested } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
|
||||
import { ScheduleOutput_2024_06_11 } from "./schedule.output";
|
||||
|
||||
export class UpdateScheduleOutput_2024_06_11 {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({
|
||||
type: ScheduleOutput_2024_06_11,
|
||||
})
|
||||
@IsNotEmptyObject()
|
||||
@ValidateNested()
|
||||
@Type(() => ScheduleOutput_2024_06_11)
|
||||
data!: ScheduleOutput_2024_06_11;
|
||||
|
||||
error?: Error;
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { ScheduleWithAvailabilitiesForWeb } from "@calcom/lib";
|
||||
import {
|
||||
transformAvailabilityForClient,
|
||||
transformDateOverridesForClient,
|
||||
transformWorkingHoursForClient,
|
||||
transformAvailabilityForAtom,
|
||||
transformDateOverridesForAtom,
|
||||
transformWorkingHoursForAtom,
|
||||
} from "@calcom/lib";
|
||||
import { hasReadPermissionsForUserId } from "@calcom/lib/hasEditPermissionForUser";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
@@ -20,7 +19,7 @@ type GetOptions = {
|
||||
input: TGetInputSchema;
|
||||
};
|
||||
|
||||
export const getHandler = async ({ ctx, input }: GetOptions): Promise<ScheduleWithAvailabilitiesForWeb> => {
|
||||
export const getHandler = async ({ ctx, input }: GetOptions) => {
|
||||
const { user } = ctx;
|
||||
|
||||
const schedule = await prisma.schedule.findUnique({
|
||||
@@ -66,11 +65,11 @@ export const getHandler = async ({ ctx, input }: GetOptions): Promise<ScheduleWi
|
||||
id: schedule.id,
|
||||
name: schedule.name,
|
||||
isManaged: schedule.userId !== user.id,
|
||||
workingHours: transformWorkingHoursForClient(schedule),
|
||||
workingHours: transformWorkingHoursForAtom(schedule),
|
||||
schedule: schedule.availability,
|
||||
availability: transformAvailabilityForClient(schedule),
|
||||
availability: transformAvailabilityForAtom(schedule),
|
||||
timeZone,
|
||||
dateOverrides: transformDateOverridesForClient(schedule, timeZone),
|
||||
dateOverrides: transformDateOverridesForAtom(schedule, timeZone),
|
||||
isDefault: !input.scheduleId || user.defaultScheduleId === schedule.id,
|
||||
isLastSchedule: schedulesCount <= 1,
|
||||
readOnly: schedule.userId !== user.id && !input.isManagedEventType,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { transformScheduleToAvailabilityForClient } from "@calcom/lib";
|
||||
import { transformScheduleToAvailabilityForAtom } from "@calcom/lib";
|
||||
import { getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
import { hasEditPermissionForUserID } from "@calcom/lib/hasEditPermissionForUser";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
@@ -118,7 +118,7 @@ export const updateHandler = async ({ input, ctx }: UpdateOptions) => {
|
||||
},
|
||||
});
|
||||
|
||||
const userAvailability = transformScheduleToAvailabilityForClient(schedule);
|
||||
const userAvailability = transformScheduleToAvailabilityForAtom(schedule);
|
||||
|
||||
return {
|
||||
schedule,
|
||||
|
||||
@@ -165,6 +165,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@antfu/utils@npm:^0.7.7":
|
||||
version: 0.7.8
|
||||
resolution: "@antfu/utils@npm:0.7.8"
|
||||
checksum: 504146b6606b53b2ff1ee9df406fd855a1854c566aa5ef4ccf4cd10c0ccdbf084a934d29a9561c5585b73f03090ef1146fd52698fab33e623cebd97e1f236f5f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@anthropic-ai/sdk@npm:^0.9.1":
|
||||
version: 0.9.1
|
||||
resolution: "@anthropic-ai/sdk@npm:0.9.1"
|
||||
@@ -3830,6 +3837,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@calcom/platform-constants": "*"
|
||||
"@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2"
|
||||
"@calcom/platform-libraries-0.0.4": "npm:@calcom/platform-libraries@0.0.4"
|
||||
"@calcom/platform-types": "*"
|
||||
"@calcom/platform-utils": "*"
|
||||
"@calcom/prisma": "*"
|
||||
@@ -3980,7 +3988,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/atoms@*, @calcom/atoms@workspace:^, @calcom/atoms@workspace:packages/platform/atoms":
|
||||
"@calcom/atoms@*, @calcom/atoms@workspace:packages/platform/atoms":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/atoms@workspace:packages/platform/atoms"
|
||||
dependencies:
|
||||
@@ -3990,13 +3998,16 @@ __metadata:
|
||||
"@radix-ui/react-toast": ^1.1.5
|
||||
"@rollup/plugin-node-resolve": ^15.0.1
|
||||
"@tanstack/react-query": ^5.17.15
|
||||
"@types/jest": ^29.5.12
|
||||
"@types/node": ^20.3.1
|
||||
"@types/react": 18.0.26
|
||||
"@types/react-dom": ^18.0.9
|
||||
"@vitejs/plugin-react": ^2.2.0
|
||||
"@vitejs/plugin-react-swc": ^3.7.0
|
||||
autoprefixer: ^10.4.19
|
||||
class-variance-authority: ^0.4.0
|
||||
clsx: ^2.0.0
|
||||
jest: ^29.7.0
|
||||
lucide-react: ^0.364.0
|
||||
postcss: ^8.4.38
|
||||
postcss-import: ^16.1.0
|
||||
@@ -4007,9 +4018,11 @@ __metadata:
|
||||
tailwind-merge: ^1.13.2
|
||||
tailwindcss: ^3.3.3
|
||||
tailwindcss-animate: ^1.0.6
|
||||
ts-jest: ^29.1.2
|
||||
typescript: ^4.9.4
|
||||
vite: ^5.0.10
|
||||
vite-plugin-dts: ^3.7.3
|
||||
vite-plugin-inspect: ^0.8.4
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -4785,6 +4798,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@calcom/platform-libraries-0.0.4@npm:@calcom/platform-libraries@0.0.4":
|
||||
version: 0.0.4
|
||||
resolution: "@calcom/platform-libraries@npm:0.0.4"
|
||||
dependencies:
|
||||
"@calcom/core": "*"
|
||||
"@calcom/features": "*"
|
||||
"@calcom/lib": "*"
|
||||
checksum: 3e8cba76f767398f9ffb95575913514925b7a51a15791741a521284eabdaba5d52f85fbcd9f032b3f2f3a6130520e67049cd8ba6f96ae4f87597de5019710c7f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@calcom/platform-libraries@workspace:packages/platform/libraries":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/platform-libraries@workspace:packages/platform/libraries"
|
||||
@@ -5384,7 +5408,6 @@ __metadata:
|
||||
dependencies:
|
||||
"@algora/sdk": ^0.1.2
|
||||
"@calcom/app-store": "*"
|
||||
"@calcom/atoms": "workspace:^"
|
||||
"@calcom/config": "*"
|
||||
"@calcom/dayjs": "*"
|
||||
"@calcom/embed-react": "workspace:^"
|
||||
@@ -5430,7 +5453,6 @@ __metadata:
|
||||
"@vercel/og": ^0.5.0
|
||||
autoprefixer: ^10.4.12
|
||||
bcryptjs: ^2.4.3
|
||||
class-variance-authority: ^0.7.0
|
||||
clsx: ^1.2.1
|
||||
cobe: ^0.4.1
|
||||
concurrently: ^7.6.0
|
||||
@@ -5443,7 +5465,6 @@ __metadata:
|
||||
env-cmd: ^10.1.0
|
||||
eslint: ^8.34.0
|
||||
fathom-client: ^3.5.0
|
||||
framer-motion: ^11.0.25
|
||||
globby: ^13.1.3
|
||||
graphql: ^16.8.0
|
||||
graphql-codegen: ^0.4.0
|
||||
@@ -5453,7 +5474,7 @@ __metadata:
|
||||
i18n-unused: ^0.13.0
|
||||
iframe-resizer-react: ^1.1.0
|
||||
keen-slider: ^6.8.0
|
||||
lucide-react: ^0.364.0
|
||||
lucide-react: ^0.171.0
|
||||
micro: ^10.0.1
|
||||
next: ^14.1.3
|
||||
next-auth: ^4.22.1
|
||||
@@ -5465,7 +5486,7 @@ __metadata:
|
||||
prism-react-renderer: ^1.3.5
|
||||
react: ^18.2.0
|
||||
react-confetti: ^6.0.1
|
||||
react-datocms: ^5.0.3
|
||||
react-datocms: ^3.1.0
|
||||
react-device-detect: ^2.2.2
|
||||
react-dom: ^18.2.0
|
||||
react-fast-marquee: ^1.6.4
|
||||
@@ -5475,10 +5496,8 @@ __metadata:
|
||||
react-live-chat-loader: ^2.8.1
|
||||
react-markdown: ^9.0.1
|
||||
react-merge-refs: 1.1.0
|
||||
react-parallax-tilt: ^1.7.226
|
||||
react-resize-detector: ^9.1.0
|
||||
react-twemoji: ^0.3.0
|
||||
react-twitter-embed: ^4.0.4
|
||||
react-use-measure: ^2.1.1
|
||||
react-wrap-balancer: ^1.0.0
|
||||
remark: ^14.0.2
|
||||
@@ -9150,59 +9169,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/mux-player-react@npm:*":
|
||||
version: 2.7.0
|
||||
resolution: "@mux/mux-player-react@npm:2.7.0"
|
||||
dependencies:
|
||||
"@mux/mux-player": 2.7.0
|
||||
"@mux/playback-core": 0.24.0
|
||||
prop-types: ^15.7.2
|
||||
peerDependencies:
|
||||
"@types/react": ^17.0.0 || ^18
|
||||
react: ^17.0.2 || ^18
|
||||
react-dom: ^17.0.2 || ^18
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
"@types/react-dom":
|
||||
optional: true
|
||||
checksum: 15ea8a8b9b2c82252e0647c22f8a1fbe7a04efaf1eb7aa61d10e4665b3dad45057c97c47cd04b8da42d02aad8288555feb9de98a8b9059b730420a8d12cada73
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/mux-player@npm:2.7.0":
|
||||
version: 2.7.0
|
||||
resolution: "@mux/mux-player@npm:2.7.0"
|
||||
dependencies:
|
||||
"@mux/mux-video": 0.19.0
|
||||
"@mux/playback-core": 0.24.0
|
||||
media-chrome: ~3.2.1
|
||||
checksum: d3254c5d82f42d26e4ec3c27e50b6438a7dc74863381ddd9003bdc92947f6db4fc45b8caee21de9125aa80e71536268426d7159617dbace739de99f8f0ed259f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/mux-video@npm:0.19.0":
|
||||
version: 0.19.0
|
||||
resolution: "@mux/mux-video@npm:0.19.0"
|
||||
dependencies:
|
||||
"@mux/playback-core": 0.24.0
|
||||
castable-video: ~1.0.6
|
||||
custom-media-element: ~1.2.3
|
||||
media-tracks: ~0.3.0
|
||||
checksum: 342d6f29fc60a9ea9694a8d794f679306e194f5de5d5cf85ed67391dce8d70330c9d78ee2681aee0e332ab1d2583a8a0174addf1182d0cf1c08fb85a01da849d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mux/playback-core@npm:0.24.0":
|
||||
version: 0.24.0
|
||||
resolution: "@mux/playback-core@npm:0.24.0"
|
||||
dependencies:
|
||||
hls.js: ~1.5.8
|
||||
mux-embed: ~5.2.0
|
||||
checksum: b9783c05b1c009fb296a84de61d7b693fd81996bd35ef26aca7342a09eee476e4d8840fde1ef89273b01db2d4f3b57692101ae7bcc4cb5b15d4d6786bd0ba961
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ndelangen/get-tarball@npm:^3.0.7":
|
||||
version: 3.0.9
|
||||
resolution: "@ndelangen/get-tarball@npm:3.0.9"
|
||||
@@ -10471,6 +10437,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@polka/url@npm:^1.0.0-next.24":
|
||||
version: 1.0.0-next.25
|
||||
resolution: "@polka/url@npm:1.0.0-next.25"
|
||||
checksum: 4ab1d7a37163139c0e7bfc9d1e3f6a2a0db91a78b9f0a21f571d6aec2cdaeaacced744d47886c117aa7579aa5694b303fe3e0bd1922bb9cb3ce6bf7c2dc09801
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@prisma/client@npm:5.4.2, @prisma/client@npm:^5.4.2":
|
||||
version: 5.4.2
|
||||
resolution: "@prisma/client@npm:5.4.2"
|
||||
@@ -14967,6 +14940,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-arm64@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-darwin-arm64@npm:1.5.28"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-darwin-x64@npm:1.3.100"
|
||||
@@ -14974,6 +14954,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-darwin-x64@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-darwin-x64@npm:1.5.28"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm-gnueabihf@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.5.28"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.100"
|
||||
@@ -14981,6 +14975,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-gnu@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-linux-arm64-gnu@npm:1.5.28"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.3.100"
|
||||
@@ -14988,6 +14989,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-arm64-musl@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-linux-arm64-musl@npm:1.5.28"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.3.100"
|
||||
@@ -14995,6 +15003,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-gnu@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-linux-x64-gnu@npm:1.5.28"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.3.100"
|
||||
@@ -15002,6 +15017,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-linux-x64-musl@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-linux-x64-musl@npm:1.5.28"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.100"
|
||||
@@ -15009,6 +15031,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-arm64-msvc@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-win32-arm64-msvc@npm:1.5.28"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.100"
|
||||
@@ -15016,6 +15045,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-ia32-msvc@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-win32-ia32-msvc@npm:1.5.28"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.3.100":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.3.100"
|
||||
@@ -15023,6 +15059,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core-win32-x64-msvc@npm:1.5.28":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core-win32-x64-msvc@npm:1.5.28"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.3.82":
|
||||
version: 1.3.100
|
||||
resolution: "@swc/core@npm:1.3.100"
|
||||
@@ -15066,6 +15109,52 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/core@npm:^1.5.7":
|
||||
version: 1.5.28
|
||||
resolution: "@swc/core@npm:1.5.28"
|
||||
dependencies:
|
||||
"@swc/core-darwin-arm64": 1.5.28
|
||||
"@swc/core-darwin-x64": 1.5.28
|
||||
"@swc/core-linux-arm-gnueabihf": 1.5.28
|
||||
"@swc/core-linux-arm64-gnu": 1.5.28
|
||||
"@swc/core-linux-arm64-musl": 1.5.28
|
||||
"@swc/core-linux-x64-gnu": 1.5.28
|
||||
"@swc/core-linux-x64-musl": 1.5.28
|
||||
"@swc/core-win32-arm64-msvc": 1.5.28
|
||||
"@swc/core-win32-ia32-msvc": 1.5.28
|
||||
"@swc/core-win32-x64-msvc": 1.5.28
|
||||
"@swc/counter": ^0.1.3
|
||||
"@swc/types": ^0.1.8
|
||||
peerDependencies:
|
||||
"@swc/helpers": "*"
|
||||
dependenciesMeta:
|
||||
"@swc/core-darwin-arm64":
|
||||
optional: true
|
||||
"@swc/core-darwin-x64":
|
||||
optional: true
|
||||
"@swc/core-linux-arm-gnueabihf":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-gnu":
|
||||
optional: true
|
||||
"@swc/core-linux-arm64-musl":
|
||||
optional: true
|
||||
"@swc/core-linux-x64-gnu":
|
||||
optional: true
|
||||
"@swc/core-linux-x64-musl":
|
||||
optional: true
|
||||
"@swc/core-win32-arm64-msvc":
|
||||
optional: true
|
||||
"@swc/core-win32-ia32-msvc":
|
||||
optional: true
|
||||
"@swc/core-win32-x64-msvc":
|
||||
optional: true
|
||||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: 9bd81dff298989d840859e957121740d8dc3154d574092c7faca874382866143b2d8279b9d6a20355221de05b2d58305581d09cf229357d97acaa5d55221b14a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/counter@npm:^0.1.1":
|
||||
version: 0.1.2
|
||||
resolution: "@swc/counter@npm:0.1.2"
|
||||
@@ -15073,6 +15162,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/counter@npm:^0.1.3":
|
||||
version: 0.1.3
|
||||
resolution: "@swc/counter@npm:0.1.3"
|
||||
checksum: df8f9cfba9904d3d60f511664c70d23bb323b3a0803ec9890f60133954173047ba9bdeabce28cd70ba89ccd3fd6c71c7b0bd58be85f611e1ffbe5d5c18616598
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/helpers@npm:0.5.2":
|
||||
version: 0.5.2
|
||||
resolution: "@swc/helpers@npm:0.5.2"
|
||||
@@ -15089,6 +15185,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/types@npm:^0.1.8":
|
||||
version: 0.1.8
|
||||
resolution: "@swc/types@npm:0.1.8"
|
||||
dependencies:
|
||||
"@swc/counter": ^0.1.3
|
||||
checksum: e564d0e37b0e28546973c6d50c7a179395912a97168d695cfe9cf1051199c8b828680cdafcb8d43948f76d3703873bafb88dfb5bc2dfe0596b4ad18fcaf90c80
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@szmarczak/http-timer@npm:^4.0.5":
|
||||
version: 4.0.6
|
||||
resolution: "@szmarczak/http-timer@npm:4.0.6"
|
||||
@@ -16164,7 +16269,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jest@npm:^29.5.10":
|
||||
"@types/jest@npm:^29.5.10, @types/jest@npm:^29.5.12":
|
||||
version: 29.5.12
|
||||
resolution: "@types/jest@npm:29.5.12"
|
||||
dependencies:
|
||||
@@ -17314,6 +17419,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitejs/plugin-react-swc@npm:^3.7.0":
|
||||
version: 3.7.0
|
||||
resolution: "@vitejs/plugin-react-swc@npm:3.7.0"
|
||||
dependencies:
|
||||
"@swc/core": ^1.5.7
|
||||
peerDependencies:
|
||||
vite: ^4 || ^5
|
||||
checksum: 87ee71cc7d261a0047a1a080c81081cb163edd555e1c8c60ff3372d14b7d76a19a28a7a03334417f622e704abd67e39e89a59d45f4742ec7036ca2988ee6651f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vitejs/plugin-react@npm:^2.2.0":
|
||||
version: 2.2.0
|
||||
resolution: "@vitejs/plugin-react@npm:2.2.0"
|
||||
@@ -20422,15 +20538,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"castable-video@npm:~1.0.6":
|
||||
version: 1.0.9
|
||||
resolution: "castable-video@npm:1.0.9"
|
||||
dependencies:
|
||||
custom-media-element: ~1.3.1
|
||||
checksum: 85600d7a257458e3ea4771a056209abada26e6a7a97e42b03402e78acd0c622923d9a55d58332937693346433c4264f578a4bfc0a49f7817cd83dd65ffe7d877
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ccount@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "ccount@npm:2.0.1"
|
||||
@@ -20888,15 +20995,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"class-variance-authority@npm:^0.7.0":
|
||||
version: 0.7.0
|
||||
resolution: "class-variance-authority@npm:0.7.0"
|
||||
dependencies:
|
||||
clsx: 2.0.0
|
||||
checksum: e7fd1fab433ef06f52a1b7b241b70b4a185864deef199d3b0a2c3412f1cc179517288264c383f3b971a00d76811625fc8f7ffe709e6170219e88cd7368f08a20
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"classnames@npm:^2.2.5, classnames@npm:^2.2.6":
|
||||
version: 2.3.2
|
||||
resolution: "classnames@npm:2.3.2"
|
||||
@@ -21169,13 +21267,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"clsx@npm:2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "clsx@npm:2.0.0"
|
||||
checksum: a2cfb2351b254611acf92faa0daf15220f4cd648bdf96ce369d729813b85336993871a4bf6978ddea2b81b5a130478339c20d9d0b5c6fc287e5147f0c059276e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"clsx@npm:^1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "clsx@npm:1.1.1"
|
||||
@@ -22481,20 +22572,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"custom-media-element@npm:~1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "custom-media-element@npm:1.2.3"
|
||||
checksum: da43680c35c870cd80ea02b9fce3efe25e9502c7088de5ab0e47ef2734aa9ce7e147c95f78a10abd4c13c47a81eae4712a7651ad18f87e023bc371082ba09842
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"custom-media-element@npm:~1.3.1":
|
||||
version: 1.3.1
|
||||
resolution: "custom-media-element@npm:1.3.1"
|
||||
checksum: d8dd50cca0e93746182e4c06290f5d96d7bf0b76d6d97fb2edbf74fd8245285e5e1c40a83f8b752aad8e9a140aff0f1a2fbbb7385c6e9f6c8d05053fd2aefeb1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"d3-array@npm:2 - 3, d3-array@npm:2.10.0 - 3, d3-array@npm:^3.1.6":
|
||||
version: 3.2.3
|
||||
resolution: "d3-array@npm:3.2.3"
|
||||
@@ -24007,6 +24084,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"error-stack-parser-es@npm:^0.1.1":
|
||||
version: 0.1.4
|
||||
resolution: "error-stack-parser-es@npm:0.1.4"
|
||||
checksum: 360da046245a42e0dbfe004d8549a224763ed249410041e8280e764743e04f405bd5167ed866d29037003516329349bd500dbb99591f04006b66697a9eb8ddd8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"error-stack-parser@npm:^2.0.6":
|
||||
version: 2.1.4
|
||||
resolution: "error-stack-parser@npm:2.1.4"
|
||||
@@ -26528,26 +26612,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"framer-motion@npm:^11.0.25":
|
||||
version: 11.1.7
|
||||
resolution: "framer-motion@npm:11.1.7"
|
||||
dependencies:
|
||||
tslib: ^2.4.0
|
||||
peerDependencies:
|
||||
"@emotion/is-prop-valid": "*"
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
"@emotion/is-prop-valid":
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
checksum: ba4f2f0823eec7b78fa87180545cf8c832929ce52de8bab34312a67bfd6dee4ab6ad17143b9df2efcd4ede7cb87fc326843a1101a6cad3031c89a6ad2160e037
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fresh@npm:0.5.2, fresh@npm:^0.5.2":
|
||||
version: 0.5.2
|
||||
resolution: "fresh@npm:0.5.2"
|
||||
@@ -28220,13 +28284,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hls.js@npm:~1.5.8":
|
||||
version: 1.5.9
|
||||
resolution: "hls.js@npm:1.5.9"
|
||||
checksum: cc98c40079df0a4b454954bd551696487573235109fb39261fc7b6728ae1fb187391a703dbed404174aef384a6eb115c82e2cd0ded99cbbb86cba0e0b6f99a2b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hmac-drbg@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "hmac-drbg@npm:1.0.1"
|
||||
@@ -33007,6 +33064,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lucide-react@npm:^0.171.0":
|
||||
version: 0.171.0
|
||||
resolution: "lucide-react@npm:0.171.0"
|
||||
peerDependencies:
|
||||
react: ^16.5.1 || ^17.0.0 || ^18.0.0
|
||||
checksum: 768ffe368c52a518ee339203d86ff4479989ab4d79c0716f721900c4bb7392ef6ff7a14807f6a685abd74d27f4c1778170bff77a0ab4c3e06c17944b557d8300
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lucide-react@npm:^0.364.0":
|
||||
version: 0.364.0
|
||||
resolution: "lucide-react@npm:0.364.0"
|
||||
@@ -33575,20 +33641,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"media-chrome@npm:~3.2.1":
|
||||
version: 3.2.3
|
||||
resolution: "media-chrome@npm:3.2.3"
|
||||
checksum: 073757ff6952045052f9c63fbb688ac8ff9f54787f5e26eaa52f47d72a8c53df65a1b62a30e2c7d90631c8c59a0ec2b960e746ab3e6dca389a3f936b42c858f2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"media-tracks@npm:~0.3.0":
|
||||
version: 0.3.2
|
||||
resolution: "media-tracks@npm:0.3.2"
|
||||
checksum: c08ea931ded4e6b3db7e0fd47259622448d9d0e965795610953f32a2d6a52bc0025870f051c2c7934c823d4b1675dac736e428445e7cbcba4326b45bb59969cb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"media-typer@npm:0.3.0":
|
||||
version: 0.3.0
|
||||
resolution: "media-typer@npm:0.3.0"
|
||||
@@ -34825,6 +34877,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mrmime@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "mrmime@npm:2.0.0"
|
||||
checksum: f6fe11ec667c3d96f1ce5fd41184ed491d5f0a5f4045e82446a471ccda5f84c7f7610dff61d378b73d964f73a320bd7f89788f9e6b9403e32cc4be28ba99f569
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ms@npm:2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "ms@npm:2.0.0"
|
||||
@@ -34943,13 +35002,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mux-embed@npm:~5.2.0":
|
||||
version: 5.2.1
|
||||
resolution: "mux-embed@npm:5.2.1"
|
||||
checksum: ec34d3e003e2520be6d1386ca2383daa198a1fa3a469ca3f06c11a742d6ab136eef4944c37e8f2dcaa0585e1b0a6dfc119e3cf2302c7eb0e7f2ebc7c1fc95fbd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mysql2@npm:3.9.1":
|
||||
version: 3.9.1
|
||||
resolution: "mysql2@npm:3.9.1"
|
||||
@@ -36443,6 +36495,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"open@npm:^10.1.0":
|
||||
version: 10.1.0
|
||||
resolution: "open@npm:10.1.0"
|
||||
dependencies:
|
||||
default-browser: ^5.2.1
|
||||
define-lazy-prop: ^3.0.0
|
||||
is-inside-container: ^1.0.0
|
||||
is-wsl: ^3.1.0
|
||||
checksum: 079b0771616bac13b08129b0300032dc9328d72f345e460dd0416b8a8196a5bdf5e0251fefec8aa2a6a97c736734ac65dd8f1d29ab3fc9a13e85624aa5bc4470
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"open@npm:^8.0.4":
|
||||
version: 8.4.2
|
||||
resolution: "open@npm:8.4.2"
|
||||
@@ -37479,6 +37543,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"perfect-debounce@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "perfect-debounce@npm:1.0.0"
|
||||
checksum: 220343acf52976947958fef3599849471605316e924fe19c633ae2772576298e9d38f02cefa8db46f06607505ce7b232cbb35c9bfd477bd0329bd0a2ce37c594
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"performance-now@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "performance-now@npm:2.1.0"
|
||||
@@ -39222,21 +39293,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-datocms@npm:^5.0.3":
|
||||
version: 5.0.3
|
||||
resolution: "react-datocms@npm:5.0.3"
|
||||
"react-datocms@npm:^3.1.0":
|
||||
version: 3.1.4
|
||||
resolution: "react-datocms@npm:3.1.4"
|
||||
dependencies:
|
||||
"@mux/mux-player-react": "*"
|
||||
datocms-listen: ^0.1.9
|
||||
datocms-structured-text-generic-html-renderer: ^2.0.1
|
||||
datocms-structured-text-utils: ^2.0.1
|
||||
react-intersection-observer: ^9.4.3
|
||||
react-intersection-observer: ^8.33.1
|
||||
react-string-replace: ^1.1.0
|
||||
universal-base64: ^2.1.0
|
||||
use-deep-compare-effect: ^1.6.1
|
||||
peerDependencies:
|
||||
react: ">= 16.12.0"
|
||||
checksum: 22c20152afb54424acfe967a2c8c525cd9f132a33374f2aba0231f16ea64dade389b096e2dac8de9ffded612bc32e9891d725609ee947639fe1cef907cb143f5
|
||||
checksum: 54aba12aef4937175c2011548a8a576c96c8d8a596e84d191826910624c1d596e76a49782689dc236388a10803b02e700ac820cb7500cca7fd147a81f6c544c3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -39488,16 +39558,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-intersection-observer@npm:^9.4.3":
|
||||
version: 9.10.2
|
||||
resolution: "react-intersection-observer@npm:9.10.2"
|
||||
"react-intersection-observer@npm:^8.33.1":
|
||||
version: 8.34.0
|
||||
resolution: "react-intersection-observer@npm:8.34.0"
|
||||
peerDependencies:
|
||||
react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
checksum: fea1104ae5515f01b6c13f8f8259bf04e44fc624e8ff5aecb1b24cca25cc04b62f7551586acd838a2c475d55fb07d9c042a412f90cd4c8e39ff4575d5a5a76ac
|
||||
react: ^15.0.0 || ^16.0.0 || ^17.0.0|| ^18.0.0
|
||||
checksum: 7713fecfd1512c7f5a60f9f0bf15403b8f8bbd4110bcafaeaea6de36a0e0eb60368c3638f99e9c97b75ad8fc787ea48c241dcb5c694f821d7f2976f709082cc5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -39607,16 +39673,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-parallax-tilt@npm:^1.7.226":
|
||||
version: 1.7.227
|
||||
resolution: "react-parallax-tilt@npm:1.7.227"
|
||||
peerDependencies:
|
||||
react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
checksum: 07a1ef95e56d35a40942976f7e9960d985f50a3330d626884b8ef75860bac1bea4c40b09b610a44c0aaa200603845ffe4975deda56c540cc364b8a26feef703d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-phone-input-2@npm:^2.15.1":
|
||||
version: 2.15.1
|
||||
resolution: "react-phone-input-2@npm:2.15.1"
|
||||
@@ -40031,18 +40087,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-twitter-embed@npm:^4.0.4":
|
||||
version: 4.0.4
|
||||
resolution: "react-twitter-embed@npm:4.0.4"
|
||||
dependencies:
|
||||
scriptjs: ^2.5.9
|
||||
peerDependencies:
|
||||
react: ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
checksum: cdb3c5bd04c4da0efa767476be47c0a3865fb6335f2a1b9e242170167b51615c38164223278cef60c77143c4bac27ba582cbea054d0af3f138104fa5ec537c4c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-universal-interface@npm:^0.6.2":
|
||||
version: 0.6.2
|
||||
resolution: "react-universal-interface@npm:0.6.2"
|
||||
@@ -41870,13 +41914,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scriptjs@npm:^2.5.9":
|
||||
version: 2.5.9
|
||||
resolution: "scriptjs@npm:2.5.9"
|
||||
checksum: fc84cb6b60b6fb9aa6f1b3bc59fc94b233bd5241ed3a04233579014382b5eb60640269c87d8657902acc09f9b785ee33230c218627cea00e653564bda8f5acb6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scuid@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "scuid@npm:1.1.0"
|
||||
@@ -42387,6 +42424,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sirv@npm:^2.0.4":
|
||||
version: 2.0.4
|
||||
resolution: "sirv@npm:2.0.4"
|
||||
dependencies:
|
||||
"@polka/url": ^1.0.0-next.24
|
||||
mrmime: ^2.0.0
|
||||
totalist: ^3.0.0
|
||||
checksum: 6853384a51d6ee9377dd657e2b257e0e98b29abbfbfa6333e105197f0f100c8c56a4520b47028b04ab1833cf2312526206f38fcd4f891c6df453f40da1a15a57
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sisteransi@npm:^1.0.5":
|
||||
version: 1.0.5
|
||||
resolution: "sisteransi@npm:1.0.5"
|
||||
@@ -44616,6 +44664,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"totalist@npm:^3.0.0":
|
||||
version: 3.0.1
|
||||
resolution: "totalist@npm:3.0.1"
|
||||
checksum: 5132d562cf88ff93fd710770a92f31dbe67cc19b5c6ccae2efc0da327f0954d211bbfd9456389655d726c624f284b4a23112f56d1da931ca7cfabbe1f45e778a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tough-cookie@npm:*, tough-cookie@npm:^4.1.2":
|
||||
version: 4.1.2
|
||||
resolution: "tough-cookie@npm:4.1.2"
|
||||
@@ -44782,6 +44837,42 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-jest@npm:^29.1.2":
|
||||
version: 29.1.4
|
||||
resolution: "ts-jest@npm:29.1.4"
|
||||
dependencies:
|
||||
bs-logger: 0.x
|
||||
fast-json-stable-stringify: 2.x
|
||||
jest-util: ^29.0.0
|
||||
json5: ^2.2.3
|
||||
lodash.memoize: 4.x
|
||||
make-error: 1.x
|
||||
semver: ^7.5.3
|
||||
yargs-parser: ^21.0.1
|
||||
peerDependencies:
|
||||
"@babel/core": ">=7.0.0-beta.0 <8"
|
||||
"@jest/transform": ^29.0.0
|
||||
"@jest/types": ^29.0.0
|
||||
babel-jest: ^29.0.0
|
||||
jest: ^29.0.0
|
||||
typescript: ">=4.3 <6"
|
||||
peerDependenciesMeta:
|
||||
"@babel/core":
|
||||
optional: true
|
||||
"@jest/transform":
|
||||
optional: true
|
||||
"@jest/types":
|
||||
optional: true
|
||||
babel-jest:
|
||||
optional: true
|
||||
esbuild:
|
||||
optional: true
|
||||
bin:
|
||||
ts-jest: cli.js
|
||||
checksum: e36cba389adbb3700b46422e883c8d25e76febcc01c4a39c801ef15e6edbd6da1695bdd144100153e992f98a754aea4099906955b1b9a83c3c72d77009c3d7e2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ts-loader@npm:^9.4.3":
|
||||
version: 9.5.1
|
||||
resolution: "ts-loader@npm:9.5.1"
|
||||
@@ -46578,6 +46669,28 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-plugin-inspect@npm:^0.8.4":
|
||||
version: 0.8.4
|
||||
resolution: "vite-plugin-inspect@npm:0.8.4"
|
||||
dependencies:
|
||||
"@antfu/utils": ^0.7.7
|
||||
"@rollup/pluginutils": ^5.1.0
|
||||
debug: ^4.3.4
|
||||
error-stack-parser-es: ^0.1.1
|
||||
fs-extra: ^11.2.0
|
||||
open: ^10.1.0
|
||||
perfect-debounce: ^1.0.0
|
||||
picocolors: ^1.0.0
|
||||
sirv: ^2.0.4
|
||||
peerDependencies:
|
||||
vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0
|
||||
peerDependenciesMeta:
|
||||
"@nuxt/kit":
|
||||
optional: true
|
||||
checksum: ba1a828ed13da03763f858452b7d514d5804c81abd97ba63366c85265dcdf148b3c93f92ddc6439ccef135768a5c7d74a89a4f2c5cc73bf2373135c151326562
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^3.0.0 || ^4.0.0 || ^5.0.0-0, vite@npm:^3.1.0 || ^4.0.0 || ^5.0.0-0, vite@npm:^5.0.10, vite@npm:^5.0.12":
|
||||
version: 5.1.6
|
||||
resolution: "vite@npm:5.1.6"
|
||||
|
||||
Reference in New Issue
Block a user