* Moved prisma to packages * Add missing prisma configs * Extracts common libs and types * Build and pipeline fixes * Adds missing package * Prisma scripts cleanup * Updates lint staged * Type fixes * Sort imports * Updates yarn lock file * Fixes for yarn dx * Revert "Sort imports" This reverts commit 076109decab9b9ba307fc03696c3b0da5c4896f3. * Formatting * Prevent double TS version * Fix conflict * Extracted e2e configs
		
			
				
	
	
		
			126 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import dayjs, { ConfigType } from "dayjs";
 | 
						|
import customParseFormat from "dayjs/plugin/customParseFormat";
 | 
						|
import timezone from "dayjs/plugin/timezone";
 | 
						|
import utc from "dayjs/plugin/utc";
 | 
						|
 | 
						|
import type { Availability } from "@calcom/prisma/client";
 | 
						|
import type { Schedule, TimeRange, WorkingHours } from "@calcom/types/schedule";
 | 
						|
 | 
						|
dayjs.extend(utc);
 | 
						|
dayjs.extend(timezone);
 | 
						|
dayjs.extend(customParseFormat);
 | 
						|
// sets the desired time in current date, needs to be current date for proper DST translation
 | 
						|
export const defaultDayRange: TimeRange = {
 | 
						|
  start: new Date(new Date().setUTCHours(9, 0, 0, 0)),
 | 
						|
  end: new Date(new Date().setUTCHours(17, 0, 0, 0)),
 | 
						|
};
 | 
						|
 | 
						|
export const DEFAULT_SCHEDULE: Schedule = [
 | 
						|
  [],
 | 
						|
  [defaultDayRange],
 | 
						|
  [defaultDayRange],
 | 
						|
  [defaultDayRange],
 | 
						|
  [defaultDayRange],
 | 
						|
  [defaultDayRange],
 | 
						|
  [],
 | 
						|
];
 | 
						|
 | 
						|
export function getAvailabilityFromSchedule(schedule: Schedule): Availability[] {
 | 
						|
  return schedule.reduce((availability: Availability[], times: TimeRange[], day: number) => {
 | 
						|
    const addNewTime = (time: TimeRange) =>
 | 
						|
      ({
 | 
						|
        days: [day],
 | 
						|
        startTime: time.start,
 | 
						|
        endTime: time.end,
 | 
						|
      } as Availability);
 | 
						|
 | 
						|
    const filteredTimes = times.filter((time) => {
 | 
						|
      let idx;
 | 
						|
      if (
 | 
						|
        (idx = availability.findIndex(
 | 
						|
          (schedule) => schedule.startTime === time.start && schedule.endTime === time.end
 | 
						|
        )) !== -1
 | 
						|
      ) {
 | 
						|
        availability[idx].days.push(day);
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
      return true;
 | 
						|
    });
 | 
						|
    filteredTimes.forEach((time) => {
 | 
						|
      availability.push(addNewTime(time));
 | 
						|
    });
 | 
						|
    return availability;
 | 
						|
  }, [] as Availability[]);
 | 
						|
}
 | 
						|
 | 
						|
export const MINUTES_IN_DAY = 60 * 24;
 | 
						|
export const MINUTES_DAY_END = MINUTES_IN_DAY - 1;
 | 
						|
export const MINUTES_DAY_START = 0;
 | 
						|
 | 
						|
/**
 | 
						|
 * Allows "casting" availability (days, startTime, endTime) given in UTC to a timeZone or utcOffset
 | 
						|
 */
 | 
						|
export function getWorkingHours(
 | 
						|
  relativeTimeUnit: {
 | 
						|
    timeZone?: string;
 | 
						|
    utcOffset?: number;
 | 
						|
  },
 | 
						|
  availability: { days: number[]; startTime: ConfigType; endTime: ConfigType }[]
 | 
						|
) {
 | 
						|
  // clearly bail when availability is not set, set everything available.
 | 
						|
  if (!availability.length) {
 | 
						|
    return [
 | 
						|
      {
 | 
						|
        days: [0, 1, 2, 3, 4, 5, 6],
 | 
						|
        // shorthand for: dayjs().startOf("day").tz(timeZone).diff(dayjs.utc().startOf("day"), "minutes")
 | 
						|
        startTime: MINUTES_DAY_START,
 | 
						|
        endTime: MINUTES_DAY_END,
 | 
						|
      },
 | 
						|
    ];
 | 
						|
  }
 | 
						|
 | 
						|
  const utcOffset = relativeTimeUnit.utcOffset ?? dayjs().tz(relativeTimeUnit.timeZone).utcOffset();
 | 
						|
 | 
						|
  const workingHours = availability.reduce((workingHours: WorkingHours[], schedule) => {
 | 
						|
    // Get times localised to the given utcOffset/timeZone
 | 
						|
    const startTime =
 | 
						|
      dayjs.utc(schedule.startTime).get("hour") * 60 +
 | 
						|
      dayjs.utc(schedule.startTime).get("minute") -
 | 
						|
      utcOffset;
 | 
						|
    const endTime =
 | 
						|
      dayjs.utc(schedule.endTime).get("hour") * 60 + dayjs.utc(schedule.endTime).get("minute") - utcOffset;
 | 
						|
 | 
						|
    // add to working hours, keeping startTime and endTimes between bounds (0-1439)
 | 
						|
    const sameDayStartTime = Math.max(MINUTES_DAY_START, Math.min(MINUTES_DAY_END, startTime));
 | 
						|
    const sameDayEndTime = Math.max(MINUTES_DAY_START, Math.min(MINUTES_DAY_END, endTime));
 | 
						|
    if (sameDayStartTime !== sameDayEndTime) {
 | 
						|
      workingHours.push({
 | 
						|
        days: schedule.days,
 | 
						|
        startTime: sameDayStartTime,
 | 
						|
        endTime: sameDayEndTime,
 | 
						|
      });
 | 
						|
    }
 | 
						|
    // check for overflow to the previous day
 | 
						|
    if (startTime < MINUTES_DAY_START || endTime < MINUTES_DAY_START) {
 | 
						|
      workingHours.push({
 | 
						|
        days: schedule.days.map((day) => day - 1),
 | 
						|
        startTime: startTime + MINUTES_IN_DAY,
 | 
						|
        endTime: Math.min(endTime + MINUTES_IN_DAY, MINUTES_DAY_END),
 | 
						|
      });
 | 
						|
    }
 | 
						|
    // else, check for overflow in the next day
 | 
						|
    else if (startTime > MINUTES_DAY_END || endTime > MINUTES_DAY_END) {
 | 
						|
      workingHours.push({
 | 
						|
        days: schedule.days.map((day) => day + 1),
 | 
						|
        startTime: Math.max(startTime - MINUTES_IN_DAY, MINUTES_DAY_START),
 | 
						|
        endTime: endTime - MINUTES_IN_DAY,
 | 
						|
      });
 | 
						|
    }
 | 
						|
 | 
						|
    return workingHours;
 | 
						|
  }, []);
 | 
						|
 | 
						|
  workingHours.sort((a, b) => a.startTime - b.startTime);
 | 
						|
 | 
						|
  return workingHours;
 | 
						|
}
 |