refactor: trpc get schedule handler (#13586)
This commit is contained in:
1 parent
c4803be323
commit
9df9f9bb6b
6 files changed
+118
-83
No files matched your search
@@ -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(() => [])
|
||||
);
|
||||
};
|
||||
@@ -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: {
|
||||
|
||||
Reference in new issue
Block a user