2023-03-23 22:10:01 +00:00
|
|
|
import type { Dayjs } from "@calcom/dayjs";
|
|
|
|
import dayjs from "@calcom/dayjs";
|
|
|
|
import { prisma } from "@calcom/prisma";
|
|
|
|
import type { Prisma } from "@calcom/prisma/client";
|
|
|
|
|
|
|
|
interface ITimeRange {
|
|
|
|
start: Dayjs;
|
|
|
|
end: Dayjs;
|
|
|
|
}
|
|
|
|
|
|
|
|
type TimeViewType = "week" | "month" | "year" | "day";
|
|
|
|
|
|
|
|
class EventsInsights {
|
2023-04-19 20:14:09 +00:00
|
|
|
static getBookingsInTimeRange = async (
|
|
|
|
timeRange: ITimeRange,
|
|
|
|
where: Prisma.BookingTimeStatusWhereInput
|
|
|
|
) => {
|
2023-03-23 22:10:01 +00:00
|
|
|
const { start, end } = timeRange;
|
|
|
|
|
2023-04-19 20:14:09 +00:00
|
|
|
const events = await prisma.bookingTimeStatus.count({
|
2023-03-23 22:10:01 +00:00
|
|
|
where: {
|
|
|
|
...where,
|
|
|
|
createdAt: {
|
|
|
|
gte: start.toISOString(),
|
|
|
|
lte: end.toISOString(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
return events;
|
|
|
|
};
|
|
|
|
|
2023-04-19 20:14:09 +00:00
|
|
|
static getCreatedEventsInTimeRange = async (
|
|
|
|
timeRange: ITimeRange,
|
|
|
|
where: Prisma.BookingTimeStatusWhereInput
|
|
|
|
) => {
|
2023-03-23 22:10:01 +00:00
|
|
|
const result = await this.getBookingsInTimeRange(timeRange, where);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
|
2023-04-19 20:14:09 +00:00
|
|
|
static getCancelledEventsInTimeRange = async (
|
|
|
|
timeRange: ITimeRange,
|
|
|
|
where: Prisma.BookingTimeStatusWhereInput
|
|
|
|
) => {
|
2023-03-23 22:10:01 +00:00
|
|
|
const result = await this.getBookingsInTimeRange(timeRange, {
|
|
|
|
...where,
|
2023-04-19 20:14:09 +00:00
|
|
|
timeStatus: "cancelled",
|
2023-03-23 22:10:01 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
|
2023-04-19 20:14:09 +00:00
|
|
|
static getCompletedEventsInTimeRange = async (
|
|
|
|
timeRange: ITimeRange,
|
|
|
|
where: Prisma.BookingTimeStatusWhereInput
|
|
|
|
) => {
|
2023-03-23 22:10:01 +00:00
|
|
|
const result = await this.getBookingsInTimeRange(timeRange, {
|
|
|
|
...where,
|
2023-04-19 20:14:09 +00:00
|
|
|
timeStatus: "completed",
|
2023-03-23 22:10:01 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
|
2023-04-19 20:14:09 +00:00
|
|
|
static getRescheduledEventsInTimeRange = async (
|
|
|
|
timeRange: ITimeRange,
|
|
|
|
where: Prisma.BookingTimeStatusWhereInput
|
|
|
|
) => {
|
2023-03-23 22:10:01 +00:00
|
|
|
const result = await this.getBookingsInTimeRange(timeRange, {
|
|
|
|
...where,
|
2023-04-19 20:14:09 +00:00
|
|
|
timeStatus: "rescheduled",
|
2023-03-23 22:10:01 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
|
2023-08-10 17:36:29 +00:00
|
|
|
static getBaseBookingCountForEventStatus = async (where: Prisma.BookingTimeStatusWhereInput) => {
|
|
|
|
const baseBookings = await prisma.bookingTimeStatus.count({
|
2023-03-23 22:10:01 +00:00
|
|
|
where,
|
|
|
|
});
|
|
|
|
|
|
|
|
return baseBookings;
|
|
|
|
};
|
|
|
|
|
2023-08-10 17:36:29 +00:00
|
|
|
static getTotalCompletedEvents = async (whereConditional: Prisma.BookingTimeStatusWhereInput) => {
|
2023-07-20 19:19:13 +00:00
|
|
|
return await prisma.bookingTimeStatus.count({
|
|
|
|
where: {
|
2023-08-10 17:36:29 +00:00
|
|
|
...whereConditional,
|
2023-07-20 19:19:13 +00:00
|
|
|
timeStatus: "completed",
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-08-10 17:36:29 +00:00
|
|
|
static getTotalRescheduledEvents = async (whereConditional: Prisma.BookingTimeStatusWhereInput) => {
|
2023-04-19 20:14:09 +00:00
|
|
|
return await prisma.bookingTimeStatus.count({
|
2023-03-23 22:10:01 +00:00
|
|
|
where: {
|
2023-08-10 17:36:29 +00:00
|
|
|
...whereConditional,
|
2023-04-19 20:14:09 +00:00
|
|
|
timeStatus: "rescheduled",
|
2023-03-23 22:10:01 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-08-10 17:36:29 +00:00
|
|
|
static getTotalCancelledEvents = async (whereConditional: Prisma.BookingTimeStatusWhereInput) => {
|
2023-04-19 20:14:09 +00:00
|
|
|
return await prisma.bookingTimeStatus.count({
|
2023-03-23 22:10:01 +00:00
|
|
|
where: {
|
2023-08-10 17:36:29 +00:00
|
|
|
...whereConditional,
|
2023-04-19 20:14:09 +00:00
|
|
|
timeStatus: "cancelled",
|
2023-03-23 22:10:01 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
static getTimeLine = async (timeView: TimeViewType, startDate: Dayjs, endDate: Dayjs) => {
|
|
|
|
let resultTimeLine: string[] = [];
|
|
|
|
|
|
|
|
if (timeView) {
|
|
|
|
switch (timeView) {
|
2023-06-29 17:03:44 +00:00
|
|
|
case "day":
|
|
|
|
resultTimeLine = this.getDailyTimeline(startDate, endDate);
|
|
|
|
break;
|
2023-03-23 22:10:01 +00:00
|
|
|
case "week":
|
|
|
|
resultTimeLine = this.getWeekTimeline(startDate, endDate);
|
|
|
|
break;
|
|
|
|
case "month":
|
|
|
|
resultTimeLine = this.getMonthTimeline(startDate, endDate);
|
|
|
|
break;
|
|
|
|
case "year":
|
|
|
|
resultTimeLine = this.getYearTimeline(startDate, endDate);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
resultTimeLine = this.getWeekTimeline(startDate, endDate);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return resultTimeLine;
|
|
|
|
};
|
|
|
|
|
|
|
|
static getTimeView = (timeView: TimeViewType, startDate: Dayjs, endDate: Dayjs) => {
|
|
|
|
let resultTimeView = timeView;
|
|
|
|
|
|
|
|
if (startDate.diff(endDate, "day") > 90) {
|
|
|
|
resultTimeView = "month";
|
|
|
|
} else if (startDate.diff(endDate, "day") > 365) {
|
|
|
|
resultTimeView = "year";
|
|
|
|
}
|
|
|
|
|
|
|
|
return resultTimeView;
|
|
|
|
};
|
|
|
|
|
2023-06-29 17:03:44 +00:00
|
|
|
static getDailyTimeline(startDate: Dayjs, endDate: Dayjs): string[] {
|
|
|
|
const now = dayjs();
|
|
|
|
const endOfDay = now.endOf("day");
|
|
|
|
let pivotDate = dayjs(startDate);
|
|
|
|
const dates: string[] = [];
|
|
|
|
while ((pivotDate.isBefore(endDate) || pivotDate.isSame(endDate)) && pivotDate.isBefore(endOfDay)) {
|
|
|
|
dates.push(pivotDate.format("YYYY-MM-DD"));
|
|
|
|
pivotDate = pivotDate.add(1, "day");
|
|
|
|
}
|
|
|
|
return dates;
|
|
|
|
}
|
|
|
|
|
2023-04-04 11:58:19 +00:00
|
|
|
static getWeekTimeline(startDate: Dayjs, endDate: Dayjs): string[] {
|
|
|
|
const now = dayjs();
|
|
|
|
const endOfDay = now.endOf("day");
|
2023-03-23 22:10:01 +00:00
|
|
|
let pivotDate = dayjs(startDate);
|
2023-04-04 11:58:19 +00:00
|
|
|
const dates: string[] = [];
|
2023-06-29 17:03:44 +00:00
|
|
|
|
|
|
|
while (pivotDate.isBefore(endDate) || pivotDate.isSame(endDate)) {
|
|
|
|
const pivotAdded = pivotDate.add(6, "day");
|
|
|
|
const weekEndDate = pivotAdded.isBefore(endOfDay) ? pivotAdded : endOfDay;
|
2023-03-23 22:10:01 +00:00
|
|
|
dates.push(pivotDate.format("YYYY-MM-DD"));
|
2023-06-29 17:03:44 +00:00
|
|
|
|
|
|
|
if (pivotDate.isSame(endDate)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-04-04 11:58:19 +00:00
|
|
|
pivotDate = weekEndDate.add(1, "day");
|
2023-03-23 22:10:01 +00:00
|
|
|
}
|
2023-06-29 17:03:44 +00:00
|
|
|
|
2023-03-23 22:10:01 +00:00
|
|
|
return dates;
|
|
|
|
}
|
|
|
|
|
|
|
|
static getMonthTimeline(startDate: Dayjs, endDate: Dayjs) {
|
|
|
|
let pivotDate = dayjs(startDate);
|
|
|
|
const dates = [];
|
|
|
|
while (pivotDate.isBefore(endDate)) {
|
|
|
|
pivotDate = pivotDate.set("month", pivotDate.get("month") + 1);
|
|
|
|
|
|
|
|
dates.push(pivotDate.format("YYYY-MM-DD"));
|
|
|
|
}
|
|
|
|
return dates;
|
|
|
|
}
|
|
|
|
|
|
|
|
static getYearTimeline(startDate: Dayjs, endDate: Dayjs) {
|
|
|
|
const pivotDate = dayjs(startDate);
|
|
|
|
const dates = [];
|
|
|
|
while (pivotDate.isBefore(endDate)) {
|
|
|
|
pivotDate.set("year", pivotDate.get("year") + 1);
|
|
|
|
dates.push(pivotDate.format("YYYY-MM-DD"));
|
|
|
|
}
|
|
|
|
return dates;
|
|
|
|
}
|
|
|
|
|
|
|
|
static getPercentage = (actualMetric: number, previousMetric: number) => {
|
|
|
|
const differenceActualVsPrevious = actualMetric - previousMetric;
|
|
|
|
if (differenceActualVsPrevious === 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
const result = (differenceActualVsPrevious * 100) / previousMetric;
|
|
|
|
if (isNaN(result) || !isFinite(result)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export { EventsInsights };
|