refactor: trpc get schedule handler (#13586)

This commit is contained in:
Lauris Skraucis authored and GitHub committed 2024-02-07 09:43:19 -07:00
1 parent c4803be323
commit 9df9f9bb6b
6 files changed
+118 -83

No files matched your search

+1
View File
@@ -4,3 +4,4 @@ export * from "./isRecurringEvent";
export * from "./isBookingLimits";
export * from "./isDurationLimits";
export * from "./validateIntervalLimitOrder";
export * from "./schedules";
@@ -0,0 +1,101 @@
import type { Availability as AvailabilityModel, Schedule as ScheduleModel } 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[] };
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) {
return getWorkingHours(
{ timeZone: schedule.timeZone || undefined, utcOffset: 0 },
schedule.availability || []
);
}
export function transformAvailabilityForClient(schedule: ScheduleWithAvailabilities) {
return transformScheduleToAvailabilityForClient(schedule).map((a) =>
a.map((startAndEnd) => ({
...startAndEnd,
end: new Date(startAndEnd.end.toISOString().replace("23:59:00.000Z", "23:59:59.999Z")),
}))
);
}
export function transformDateOverridesForClient(schedule: ScheduleWithAvailabilities, timeZone: string) {
return schedule.availability.reduce((acc, override) => {
// only iff future date override
if (!override.date || dayjs.tz(override.date, timeZone).isBefore(dayjs(), "day")) {
return acc;
}
const newValue = {
start: dayjs
.utc(override.date)
.hour(override.startTime.getUTCHours())
.minute(override.startTime.getUTCMinutes())
.toDate(),
end: dayjs
.utc(override.date)
.hour(override.endTime.getUTCHours())
.minute(override.endTime.getUTCMinutes())
.toDate(),
};
const dayRangeIndex = acc.findIndex(
// early return prevents override.date from ever being empty.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(item) => yyyymmdd(item.ranges[0].start) === yyyymmdd(override.date!)
);
if (dayRangeIndex === -1) {
acc.push({ ranges: [newValue] });
return acc;
}
acc[dayRangeIndex].ranges.push(newValue);
return acc;
}, [] as { ranges: TimeRange[] }[]);
}
export const transformScheduleToAvailabilityForClient = (
schedule: Partial<ScheduleModel> & { availability: AvailabilityModel[] }
) => {
return schedule.availability.reduce(
(schedule: Schedule, availability) => {
availability.days.forEach((day) => {
schedule[day].push({
start: new Date(
Date.UTC(
new Date().getUTCFullYear(),
new Date().getUTCMonth(),
new Date().getUTCDate(),
availability.startTime.getUTCHours(),
availability.startTime.getUTCMinutes()
)
),
end: new Date(
Date.UTC(
new Date().getUTCFullYear(),
new Date().getUTCMonth(),
new Date().getUTCDate(),
availability.endTime.getUTCHours(),
availability.endTime.getUTCMinutes()
)
),
});
});
return schedule;
},
Array.from([...Array(7)]).map(() => [])
);
};
+1
View File
@@ -0,0 +1 @@
export * from "./client/transformers";
@@ -1,14 +1,16 @@
import dayjs from "@calcom/dayjs";
import { getWorkingHours } from "@calcom/lib/availability";
import { yyyymmdd } from "@calcom/lib/date-fns";
import type { ScheduleWithAvailabilitiesForWeb } from "@calcom/lib";
import {
transformAvailabilityForClient,
transformDateOverridesForClient,
transformWorkingHoursForClient,
} from "@calcom/lib";
import { hasReadPermissionsForUserId } from "@calcom/lib/hasEditPermissionForUser";
import { prisma } from "@calcom/prisma";
import type { TimeRange } from "@calcom/types/schedule";
import { TRPCError } from "@trpc/server";
import type { TrpcSessionUser } from "../../../../trpc";
import { convertScheduleToAvailability, getDefaultScheduleId } from "../util";
import { getDefaultScheduleId } from "../util";
import type { TGetInputSchema } from "./get.schema";
type GetOptions = {
@@ -18,7 +20,7 @@ type GetOptions = {
input: TGetInputSchema;
};
export const getHandler = async ({ ctx, input }: GetOptions) => {
export const getHandler = async ({ ctx, input }: GetOptions): Promise<ScheduleWithAvailabilitiesForWeb> => {
const { user } = ctx;
const schedule = await prisma.schedule.findUnique({
@@ -64,48 +66,11 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
id: schedule.id,
name: schedule.name,
isManaged: schedule.userId !== user.id,
workingHours: getWorkingHours(
{ timeZone: schedule.timeZone || undefined, utcOffset: 0 },
schedule.availability || []
),
workingHours: transformWorkingHoursForClient(schedule),
schedule: schedule.availability,
availability: convertScheduleToAvailability(schedule).map((a) =>
a.map((startAndEnd) => ({
...startAndEnd,
// Turn our limited granularity into proper end of day.
end: new Date(startAndEnd.end.toISOString().replace("23:59:00.000Z", "23:59:59.999Z")),
}))
),
availability: transformAvailabilityForClient(schedule),
timeZone,
dateOverrides: schedule.availability.reduce((acc, override) => {
// only iff future date override
if (!override.date || dayjs.tz(override.date, timeZone).isBefore(dayjs(), "day")) {
return acc;
}
const newValue = {
start: dayjs
.utc(override.date)
.hour(override.startTime.getUTCHours())
.minute(override.startTime.getUTCMinutes())
.toDate(),
end: dayjs
.utc(override.date)
.hour(override.endTime.getUTCHours())
.minute(override.endTime.getUTCMinutes())
.toDate(),
};
const dayRangeIndex = acc.findIndex(
// early return prevents override.date from ever being empty.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(item) => yyyymmdd(item.ranges[0].start) === yyyymmdd(override.date!)
);
if (dayRangeIndex === -1) {
acc.push({ ranges: [newValue] });
return acc;
}
acc[dayRangeIndex].ranges.push(newValue);
return acc;
}, [] as { ranges: TimeRange[] }[]),
dateOverrides: transformDateOverridesForClient(schedule, timeZone),
isDefault: !input.scheduleId || user.defaultScheduleId === schedule.id,
isLastSchedule: schedulesCount <= 1,
readOnly: schedule.userId !== user.id && !input.isManagedEventType,
@@ -1,3 +1,4 @@
import { transformScheduleToAvailabilityForClient } from "@calcom/lib";
import { getAvailabilityFromSchedule } from "@calcom/lib/availability";
import { hasEditPermissionForUserID } from "@calcom/lib/hasEditPermissionForUser";
import { prisma } from "@calcom/prisma";
@@ -5,7 +6,7 @@ import { prisma } from "@calcom/prisma";
import { TRPCError } from "@trpc/server";
import type { TrpcSessionUser } from "../../../../trpc";
import { convertScheduleToAvailability, setupDefaultSchedule } from "../util";
import { setupDefaultSchedule } from "../util";
import type { TUpdateInputSchema } from "./update.schema";
type UpdateOptions = {
@@ -116,7 +117,7 @@ export const updateHandler = async ({ input, ctx }: UpdateOptions) => {
},
});
const userAvailability = convertScheduleToAvailability(schedule);
const userAvailability = transformScheduleToAvailabilityForClient(schedule);
return {
schedule,
@@ -1,7 +1,6 @@
import type { Availability as AvailabilityModel, Schedule as ScheduleModel, User } from "@prisma/client";
import type { User } from "@prisma/client";
import type { PrismaClient } from "@calcom/prisma";
import type { Schedule } from "@calcom/types/schedule";
export const getDefaultScheduleId = async (userId: number, prisma: PrismaClient) => {
const user = await prisma.user.findUnique({
@@ -44,39 +43,6 @@ export const hasDefaultSchedule = async (user: Partial<User>, prisma: PrismaClie
return !!user.defaultScheduleId || !!defaultSchedule;
};
export const convertScheduleToAvailability = (
schedule: Partial<ScheduleModel> & { availability: AvailabilityModel[] }
) => {
return schedule.availability.reduce(
(schedule: Schedule, availability) => {
availability.days.forEach((day) => {
schedule[day].push({
start: new Date(
Date.UTC(
new Date().getUTCFullYear(),
new Date().getUTCMonth(),
new Date().getUTCDate(),
availability.startTime.getUTCHours(),
availability.startTime.getUTCMinutes()
)
),
end: new Date(
Date.UTC(
new Date().getUTCFullYear(),
new Date().getUTCMonth(),
new Date().getUTCDate(),
availability.endTime.getUTCHours(),
availability.endTime.getUTCMinutes()
)
),
});
});
return schedule;
},
Array.from([...Array(7)]).map(() => [])
);
};
export const setupDefaultSchedule = async (userId: number, scheduleId: number, prisma: PrismaClient) => {
return prisma.user.update({
where: {