Skip to content

Commit

Permalink
refactor: Clean out old code, no longer needed (#19323)
Browse files Browse the repository at this point in the history
* refactor: Clean out old code, no longer needed

* Removed a sneaky one keen to stay behind
  • Loading branch information
emrysal authored Feb 17, 2025
1 parent eb86064 commit 84b265c
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 274 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
// @ts-nocheck

/* eslint-enable @typescript-eslint/ban-ts-comment */
// TODO: Currently this file is not type checked as it's deprecated
// it must be refactored if we want to restore TeamAvailability
import classNames from "classnames";
import React from "react";
import type { ITimezone } from "react-timezone-select";
Expand Down
162 changes: 3 additions & 159 deletions packages/lib/slots.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { describe, expect, it, beforeAll, vi } from "vitest";

import dayjs from "@calcom/dayjs";
import { MINUTES_DAY_END, MINUTES_DAY_START } from "@calcom/lib/availability";

import type { DateRange } from "./date-ranges";
import getSlots from "./slots";
Expand All @@ -23,7 +22,7 @@ beforeAll(() => {
];
});

describe("Tests the date-range slot logic", () => {
describe("Tests the slot logic", () => {
it("can fit 24 hourly slots for an empty day", async () => {
expect(
getSlots({
Expand Down Expand Up @@ -342,167 +341,12 @@ describe("Tests the date-range slot logic", () => {
});
});

describe("Tests the slot logic", () => {
it("can fit 24 hourly slots for an empty day", async () => {
// 24h in a day.
expect(
getSlots({
inviteeDate: dayjs.utc().add(1, "day"),
frequency: 60,
minimumBookingNotice: 0,
workingHours: [
{
userId: 1,
days: Array.from(Array(7).keys()),
startTime: MINUTES_DAY_START,
endTime: MINUTES_DAY_END,
},
],
eventLength: 60,
offsetStart: 0,
organizerTimeZone: "America/Toronto",
})
).toHaveLength(24);
});

// TODO: This test is sound; it should pass!
it("only shows future booking slots on the same day", async () => {
// The mock date is 1s to midday, so 12 slots should be open given 0 booking notice.
expect(
getSlots({
inviteeDate: dayjs.utc(),
frequency: 60,
minimumBookingNotice: 0,
workingHours: [
{
userId: 1,
days: Array.from(Array(7).keys()),
startTime: MINUTES_DAY_START,
endTime: MINUTES_DAY_END,
},
],
eventLength: 60,
offsetStart: 0,
organizerTimeZone: "America/Toronto",
})
).toHaveLength(12);
});

it("can cut off dates that due to invitee timezone differences fall on the next day", async () => {
expect(
getSlots({
inviteeDate: dayjs().tz("Europe/Amsterdam").startOf("day"), // time translation +01:00
frequency: 60,
minimumBookingNotice: 0,
workingHours: [
{
userId: 1,
days: [0],
startTime: 23 * 60, // 23h
endTime: MINUTES_DAY_END,
},
],
eventLength: 60,
offsetStart: 0,
organizerTimeZone: "America/Toronto",
})
).toHaveLength(0);
});

it("can cut off dates that due to invitee timezone differences fall on the previous day", async () => {
const workingHours = [
{
userId: 1,
days: [0],
startTime: MINUTES_DAY_START,
endTime: 1 * 60, // 1h
},
];
expect(
getSlots({
inviteeDate: dayjs().tz("Atlantic/Cape_Verde").startOf("day"), // time translation -01:00
frequency: 60,
minimumBookingNotice: 0,
workingHours,
eventLength: 60,
offsetStart: 0,
organizerTimeZone: "America/Toronto",
})
).toHaveLength(0);
});

it("adds minimum booking notice correctly", async () => {
// 24h in a day.
expect(
getSlots({
inviteeDate: dayjs.utc().add(1, "day").startOf("day"),
frequency: 60,
minimumBookingNotice: 1500,
workingHours: [
{
userId: 1,
days: Array.from(Array(7).keys()),
startTime: MINUTES_DAY_START,
endTime: MINUTES_DAY_END,
},
],
eventLength: 60,
offsetStart: 0,
organizerTimeZone: "America/Toronto",
})
).toHaveLength(11);
});

it("can fit 48 25 minute slots with a 5 minute offset for an empty day", async () => {
expect(
getSlots({
inviteeDate: dayjs.utc().add(1, "day"),
frequency: 25,
minimumBookingNotice: 0,
workingHours: [
{
userId: 1,
days: Array.from(Array(7).keys()),
startTime: MINUTES_DAY_START,
endTime: MINUTES_DAY_END,
},
],
eventLength: 25,
offsetStart: 5,
organizerTimeZone: "America/Toronto",
})
).toHaveLength(48);
});
});

describe("Tests the date-range slot logic with custom env variable", () => {
describe("Tests the slot logic with custom env variable", () => {
beforeAll(() => {
vi.stubEnv("NEXT_PUBLIC_AVAILABILITY_SCHEDULE_INTERVAL", "10");
});

it("can fit 11 10 minute slots within a 2 hour window using a 10 mintue availabilty option with a starting time of 10 past the hour", async () => {
expect(Number(process.env.NEXT_PUBLIC_AVAILABILITY_SCHEDULE_INTERVAL)).toBe(10);
expect(
getSlots({
inviteeDate: dayjs.utc().add(1, "day"),
frequency: 10,
minimumBookingNotice: 0,
workingHours: [
{
userId: 1,
days: Array.from(Array(7).keys()),
startTime: 10,
endTime: 120,
},
],
eventLength: 10,
offsetStart: 0,
organizerTimeZone: "America/Toronto",
})
).toHaveLength(11);
});

it("test buildSlotsWithDateRanges using a 10 mintue interval", async () => {
it("test using a 10 minute interval", async () => {
expect(Number(process.env.NEXT_PUBLIC_AVAILABILITY_SCHEDULE_INTERVAL)).toBe(10);
expect(
getSlots({
Expand Down
117 changes: 2 additions & 115 deletions packages/lib/slots.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import type { IFromUser, IOutOfOfficeData, IToUser } from "@calcom/core/getUserAvailability";
import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import type { WorkingHours, TimeRange as DateOverride } from "@calcom/types/schedule";

import { getWorkingHours } from "./availability";
import { getTimeZone } from "./date-fns";
import type { DateRange } from "./date-ranges";

export type GetSlots = {
inviteeDate: Dayjs;
frequency: number;
workingHours?: WorkingHours[];
dateOverrides?: DateOverride[];
dateRanges?: DateRange[];
minimumBookingNotice: number;
eventLength: number;
Expand Down Expand Up @@ -373,8 +369,6 @@ const getSlots = ({
inviteeDate,
frequency,
minimumBookingNotice,
workingHours = [],
dateOverrides = [],
dateRanges,
eventLength,
offsetStart = 0,
Expand Down Expand Up @@ -411,115 +405,8 @@ const getSlots = ({
datesOutOfOffice,
});
}

if (!organizerTimeZone) {
throw new Error("organizerTimeZone is required during getSlots call without dateRanges");
}

// current date in invitee tz
const startDate = dayjs().utcOffset(inviteeDate.utcOffset()).add(minimumBookingNotice, "minute");

// This code is ran client side, startOf() does some conversions based on the
// local tz of the client. Sometimes this shifts the day incorrectly.
const startOfDayUTC = dayjs.utc().set("hour", 0).set("minute", 0).set("second", 0);
const startOfInviteeDay = inviteeDate.startOf("day");
// checks if the start date is in the past

/**
* TODO: change "day" for "hour" to stop displaying 1 day before today
* This is displaying a day as available as sometimes difference between two dates is < 24 hrs.
* But when doing timezones an available day for an owner can be 2 days available in other users tz.
*
* */
if (inviteeDate.isBefore(startDate, "day")) {
return [];
}

const timeZone: string = getTimeZone(inviteeDate);
const workingHoursUTC = workingHours.map((schedule) => ({
userId: schedule.userId,
days: schedule.days,
startTime: /* Why? */ startOfDayUTC.add(schedule.startTime, "minute"),
endTime: /* Why? */ startOfDayUTC.add(schedule.endTime, "minute"),
}));

const localWorkingHours = getWorkingHours(
{
// initialize current day with timeZone without conversion, just parse.
utcOffset: -dayjs.tz(dayjs(), timeZone).utcOffset(),
},
workingHoursUTC
).filter((hours) => hours.days.includes(inviteeDate.day()));

// Here we split working hour in chunks for every frequency available that can fit in whole working hours
const computedLocalAvailability: TimeFrame[] = [];
let tempComputeTimeFrame: TimeFrame | undefined;
const computeLength = localWorkingHours.length - 1;
const makeTimeFrame = (item: (typeof localWorkingHours)[0]): TimeFrame => ({
userIds: item.userId ? [item.userId] : [],
startTime: item.startTime,
endTime: item.endTime,
});

localWorkingHours.forEach((item, index) => {
if (!tempComputeTimeFrame) {
tempComputeTimeFrame = makeTimeFrame(item);
} else {
// please check the comment in splitAvailableTime func for the added 1 minute
if (tempComputeTimeFrame.endTime + 1 === item.startTime) {
// to deal with time that across the day, e.g. from 11:59 to to 12:01
tempComputeTimeFrame.endTime = item.endTime;
} else {
computedLocalAvailability.push(tempComputeTimeFrame);
tempComputeTimeFrame = makeTimeFrame(item);
}
}
if (index == computeLength) {
computedLocalAvailability.push(tempComputeTimeFrame);
}
});
// an override precedes all the local working hour availability logic.
const activeOverrides = dateOverrides.filter((override) => {
return dayjs.utc(override.start).isBetween(startOfInviteeDay, startOfInviteeDay.endOf("day"), null, "[)");
});

if (activeOverrides.length) {
const overrides = activeOverrides.flatMap((override) => ({
userIds: override.userId ? [override.userId] : [],
startTime: override.start.getUTCHours() * 60 + override.start.getUTCMinutes(),
endTime: override.end.getUTCHours() * 60 + override.end.getUTCMinutes(),
}));
// unset all working hours that relate to this user availability override
overrides.forEach((override) => {
let i = -1;
const indexes: number[] = [];
while (
(i = computedLocalAvailability.findIndex(
fromIndex(
(a) => !a.userIds?.length || (!!override.userIds[0] && a.userIds?.includes(override.userIds[0])),
i + 1
)
)) != -1
) {
indexes.push(i);
}
// work backwards as splice modifies the original array.
indexes.reverse().forEach((idx) => computedLocalAvailability.splice(idx, 1));
});
// and push all overrides as new computed availability
computedLocalAvailability.push(...overrides);
}

return buildSlots({
computedLocalAvailability,
startOfInviteeDay,
startDate,
frequency,
eventLength,
offsetStart,
organizerTimeZone,
inviteeTimeZone: timeZone,
});
// just to ensure we don't call this anywhere. APIv1/v2 + webapp use dateRanges.
throw new Error("Deprecated invocation of getSlots, use dateRanges instead.");
};

export default getSlots;

0 comments on commit 84b265c

Please sign in to comment.