diff --git a/packages/features/insights/components/AverageEventDurationChart.tsx b/packages/features/insights/components/AverageEventDurationChart.tsx index 1c38ff0707..f2320f7f41 100644 --- a/packages/features/insights/components/AverageEventDurationChart.tsx +++ b/packages/features/insights/components/AverageEventDurationChart.tsx @@ -16,13 +16,21 @@ export const AverageEventDurationChart = () => { const [startDate, endDate] = dateRange; const { selectedTeamId: teamId, selectedUserId } = filter; - const { data, isSuccess, isLoading } = trpc.viewer.insights.averageEventDuration.useQuery({ - startDate: startDate.toISOString(), - endDate: endDate.toISOString(), - teamId: teamId ?? undefined, - memberUserId: selectedMemberUserId ?? undefined, - userId: selectedUserId ?? undefined, - }); + const { data, isSuccess, isLoading } = trpc.viewer.insights.averageEventDuration.useQuery( + { + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + teamId: teamId ?? undefined, + memberUserId: selectedMemberUserId ?? undefined, + userId: selectedUserId ?? undefined, + }, + { + staleTime: 30000, + trpc: { + context: { skipBatch: true }, + }, + } + ); if (isLoading) return ; diff --git a/packages/features/insights/components/BookingKPICards.tsx b/packages/features/insights/components/BookingKPICards.tsx index fc50b5f621..3487dbad8d 100644 --- a/packages/features/insights/components/BookingKPICards.tsx +++ b/packages/features/insights/components/BookingKPICards.tsx @@ -16,14 +16,22 @@ export const BookingKPICards = () => { const { selectedTeamId: teamId } = filter; - const { data, isSuccess, isLoading } = trpc.viewer.insights.eventsByStatus.useQuery({ - startDate: startDate.toISOString(), - endDate: endDate.toISOString(), - teamId, - eventTypeId: selectedEventTypeId ?? undefined, - memberUserId: selectedMemberUserId ?? undefined, - userId: selectedUserId ?? undefined, - }); + const { data, isSuccess, isLoading } = trpc.viewer.insights.eventsByStatus.useQuery( + { + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + teamId, + eventTypeId: selectedEventTypeId ?? undefined, + memberUserId: selectedMemberUserId ?? undefined, + userId: selectedUserId ?? undefined, + }, + { + staleTime: 30000, + trpc: { + context: { skipBatch: true }, + }, + } + ); const categories: { title: string; diff --git a/packages/features/insights/components/BookingStatusLineChart.tsx b/packages/features/insights/components/BookingStatusLineChart.tsx index 00ed4fd0d3..f16cfb4e8b 100644 --- a/packages/features/insights/components/BookingStatusLineChart.tsx +++ b/packages/features/insights/components/BookingStatusLineChart.tsx @@ -27,14 +27,22 @@ export const BookingStatusLineChart = () => { data: eventsTimeLine, isSuccess, isLoading, - } = trpc.viewer.insights.eventsTimeline.useQuery({ - timeView: selectedTimeView, - startDate: startDate.toISOString(), - endDate: endDate.toISOString(), - teamId: selectedTeamId ?? undefined, - eventTypeId: selectedEventTypeId ?? undefined, - userId: selectedUserId ?? undefined, - }); + } = trpc.viewer.insights.eventsTimeline.useQuery( + { + timeView: selectedTimeView, + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + teamId: selectedTeamId ?? undefined, + eventTypeId: selectedEventTypeId ?? undefined, + userId: selectedUserId ?? undefined, + }, + { + staleTime: 30000, + trpc: { + context: { skipBatch: true }, + }, + } + ); if (isLoading) return ; diff --git a/packages/features/insights/components/LeastBookedTeamMembersTable.tsx b/packages/features/insights/components/LeastBookedTeamMembersTable.tsx index 8285088ee3..5ba2766511 100644 --- a/packages/features/insights/components/LeastBookedTeamMembersTable.tsx +++ b/packages/features/insights/components/LeastBookedTeamMembersTable.tsx @@ -14,12 +14,20 @@ export const LeastBookedTeamMembersTable = () => { const { dateRange, selectedEventTypeId, selectedTeamId: teamId } = filter; const [startDate, endDate] = dateRange; - const { data, isSuccess, isLoading } = trpc.viewer.insights.membersWithLeastBookings.useQuery({ - startDate: startDate.toISOString(), - endDate: endDate.toISOString(), - teamId, - eventTypeId: selectedEventTypeId ?? undefined, - }); + const { data, isSuccess, isLoading } = trpc.viewer.insights.membersWithLeastBookings.useQuery( + { + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + teamId, + eventTypeId: selectedEventTypeId ?? undefined, + }, + { + staleTime: 30000, + trpc: { + context: { skipBatch: true }, + }, + } + ); if (isLoading) return ; diff --git a/packages/features/insights/components/MostBookedTeamMembersTable.tsx b/packages/features/insights/components/MostBookedTeamMembersTable.tsx index b83f714d44..984c4701c5 100644 --- a/packages/features/insights/components/MostBookedTeamMembersTable.tsx +++ b/packages/features/insights/components/MostBookedTeamMembersTable.tsx @@ -15,12 +15,20 @@ export const MostBookedTeamMembersTable = () => { const [startDate, endDate] = dateRange; const { selectedTeamId: teamId } = filter; - const { data, isSuccess, isLoading } = trpc.viewer.insights.membersWithMostBookings.useQuery({ - startDate: startDate.toISOString(), - endDate: endDate.toISOString(), - teamId, - eventTypeId: selectedEventTypeId ?? undefined, - }); + const { data, isSuccess, isLoading } = trpc.viewer.insights.membersWithMostBookings.useQuery( + { + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + teamId, + eventTypeId: selectedEventTypeId ?? undefined, + }, + { + staleTime: 30000, + trpc: { + context: { skipBatch: true }, + }, + } + ); if (isLoading) return ; diff --git a/packages/features/insights/components/PopularEventsTable.tsx b/packages/features/insights/components/PopularEventsTable.tsx index dfc2109fa5..9af8458027 100644 --- a/packages/features/insights/components/PopularEventsTable.tsx +++ b/packages/features/insights/components/PopularEventsTable.tsx @@ -14,13 +14,21 @@ export const PopularEventsTable = () => { const [startDate, endDate] = dateRange; const { selectedTeamId: teamId } = filter; - const { data, isSuccess, isLoading } = trpc.viewer.insights.popularEventTypes.useQuery({ - startDate: startDate.toISOString(), - endDate: endDate.toISOString(), - teamId: teamId ?? undefined, - userId: selectedUserId ?? undefined, - memberUserId: selectedMemberUserId ?? undefined, - }); + const { data, isSuccess, isLoading } = trpc.viewer.insights.popularEventTypes.useQuery( + { + startDate: startDate.toISOString(), + endDate: endDate.toISOString(), + teamId: teamId ?? undefined, + userId: selectedUserId ?? undefined, + memberUserId: selectedMemberUserId ?? undefined, + }, + { + staleTime: 30000, + trpc: { + context: { skipBatch: true }, + }, + } + ); if (isLoading) return ; diff --git a/packages/features/insights/context/FiltersProvider.tsx b/packages/features/insights/context/FiltersProvider.tsx index 05c97ebdb2..5fc726537a 100644 --- a/packages/features/insights/context/FiltersProvider.tsx +++ b/packages/features/insights/context/FiltersProvider.tsx @@ -117,9 +117,10 @@ export function FiltersProvider({ children }: { children: React.ReactNode }) { setSelectedTimeView: (selectedTimeView) => setSelectedTimeView(selectedTimeView), setSelectedMemberUserId: (selectedMemberUserId) => { setSelectedMemberUserId(selectedMemberUserId); + const { userId, eventTypeId, ...rest } = router.query; router.push({ query: { - ...router.query, + ...rest, memberUserId: selectedMemberUserId, }, }); @@ -127,8 +128,10 @@ export function FiltersProvider({ children }: { children: React.ReactNode }) { setSelectedTeamId: (selectedTeamId) => { setSelectedTeamId(selectedTeamId); setSelectedUserId(null); + setSelectedMemberUserId(null); + setSelectedEventTypeId(null); const { teamId, eventTypeId, memberUserId, ...rest } = router.query; - router.replace({ + router.push({ query: { ...rest, teamId: selectedTeamId, @@ -139,8 +142,9 @@ export function FiltersProvider({ children }: { children: React.ReactNode }) { setSelectedUserId(selectedUserId); setSelectedTeamId(null); setSelectedTeamName(null); + setSelectedEventTypeId(null); const { teamId, eventTypeId, memberUserId, ...rest } = router.query; - router.replace({ + router.push({ query: { ...rest, userId: selectedUserId, diff --git a/packages/features/insights/server/events.ts b/packages/features/insights/server/events.ts index ac9800eed5..5c9f878dee 100644 --- a/packages/features/insights/server/events.ts +++ b/packages/features/insights/server/events.ts @@ -11,10 +11,13 @@ interface ITimeRange { type TimeViewType = "week" | "month" | "year" | "day"; class EventsInsights { - static getBookingsInTimeRange = async (timeRange: ITimeRange, where: Prisma.BookingWhereInput) => { + static getBookingsInTimeRange = async ( + timeRange: ITimeRange, + where: Prisma.BookingTimeStatusWhereInput + ) => { const { start, end } = timeRange; - const events = await prisma.booking.count({ + const events = await prisma.bookingTimeStatus.count({ where: { ...where, createdAt: { @@ -27,48 +30,56 @@ class EventsInsights { return events; }; - static getCreatedEventsInTimeRange = async (timeRange: ITimeRange, where: Prisma.BookingWhereInput) => { + static getCreatedEventsInTimeRange = async ( + timeRange: ITimeRange, + where: Prisma.BookingTimeStatusWhereInput + ) => { const result = await this.getBookingsInTimeRange(timeRange, where); return result; }; - static getCancelledEventsInTimeRange = async (timeRange: ITimeRange, where: Prisma.BookingWhereInput) => { + static getCancelledEventsInTimeRange = async ( + timeRange: ITimeRange, + where: Prisma.BookingTimeStatusWhereInput + ) => { const result = await this.getBookingsInTimeRange(timeRange, { ...where, - status: "CANCELLED", + timeStatus: "cancelled", }); return result; }; - static getCompletedEventsInTimeRange = async (timeRange: ITimeRange, where: Prisma.BookingWhereInput) => { + static getCompletedEventsInTimeRange = async ( + timeRange: ITimeRange, + where: Prisma.BookingTimeStatusWhereInput + ) => { const result = await this.getBookingsInTimeRange(timeRange, { ...where, - status: "ACCEPTED", - endTime: { - lte: dayjs().toISOString(), - }, + timeStatus: "completed", }); return result; }; - static getRescheduledEventsInTimeRange = async (timeRange: ITimeRange, where: Prisma.BookingWhereInput) => { + static getRescheduledEventsInTimeRange = async ( + timeRange: ITimeRange, + where: Prisma.BookingTimeStatusWhereInput + ) => { const result = await this.getBookingsInTimeRange(timeRange, { ...where, - rescheduled: true, + timeStatus: "rescheduled", }); return result; }; - static getBaseBookingForEventStatus = async (where: Prisma.BookingWhereInput) => { - const baseBookings = await prisma.booking.findMany({ + static getBaseBookingForEventStatus = async (where: Prisma.BookingTimeStatusWhereInput) => { + const baseBookings = await prisma.bookingTimeStatus.findMany({ where, select: { id: true, - eventType: true, }, }); @@ -76,23 +87,23 @@ class EventsInsights { }; static getTotalRescheduledEvents = async (bookingIds: number[]) => { - return await prisma.booking.count({ + return await prisma.bookingTimeStatus.count({ where: { id: { in: bookingIds, }, - rescheduled: true, + timeStatus: "rescheduled", }, }); }; static getTotalCancelledEvents = async (bookingIds: number[]) => { - return await prisma.booking.count({ + return await prisma.bookingTimeStatus.count({ where: { id: { in: bookingIds, }, - status: "CANCELLED", + timeStatus: "cancelled", }, }); }; diff --git a/packages/features/insights/server/trpc-router.ts b/packages/features/insights/server/trpc-router.ts index 6a62434647..38cda62918 100644 --- a/packages/features/insights/server/trpc-router.ts +++ b/packages/features/insights/server/trpc-router.ts @@ -93,7 +93,7 @@ export const insightsRouter = router({ throw new TRPCError({ code: "UNAUTHORIZED" }); } - let whereConditional: Prisma.BookingWhereInput = {}; + let whereConditional: Prisma.BookingTimeStatusWhereInput = {}; if (eventTypeId) { whereConditional["eventTypeId"] = eventTypeId; @@ -102,9 +102,7 @@ export const insightsRouter = router({ whereConditional["userId"] = memberUserId; } if (userId) { - whereConditional["eventType"] = { - teamId: null, - }; + whereConditional["teamId"] = null; whereConditional["userId"] = userId; } @@ -122,14 +120,13 @@ export const insightsRouter = router({ ...whereConditional, OR: [ { - eventType: { - teamId: teamId, - }, + teamId, }, { userId: { in: userIdsFromTeam, }, + teamId: null, }, ], }; @@ -161,9 +158,7 @@ export const insightsRouter = router({ gte: lastPeriodStartDate.toDate(), lte: lastPeriodEndDate.toDate(), }, - eventType: { - teamId: teamId, - }, + teamId: teamId, }); const lastPeriodBaseBookingIds = lastPeriodBaseBookings.map((b) => b.id); @@ -246,7 +241,7 @@ export const insightsRouter = router({ const timeView = inputTimeView; - let whereConditional: Prisma.BookingWhereInput = {}; + let whereConditional: Prisma.BookingTimeStatusWhereInput = {}; if (teamId) { const usersFromTeam = await ctx.prisma.membership.findMany({ @@ -262,14 +257,13 @@ export const insightsRouter = router({ whereConditional = { OR: [ { - eventType: { - teamId, - }, + teamId, }, { userId: { in: userIdsFromTeams, }, + teamId: null, }, ], }; @@ -291,9 +285,7 @@ export const insightsRouter = router({ if (selfUserId && !!whereConditional) { // In this delete we are deleting the teamId filter whereConditional["userId"] = selfUserId; - whereConditional["eventType"] = { - teamId: null, - }; + whereConditional["teamId"] = null; } // Get timeline data @@ -382,7 +374,7 @@ export const insightsRouter = router({ return []; } - let bookingWhere: Prisma.BookingWhereInput = { + let bookingWhere: Prisma.BookingTimeStatusWhereInput = { createdAt: { gte: dayjs(startDate).startOf("day").toDate(), lte: dayjs(endDate).endOf("day").toDate(), @@ -403,14 +395,13 @@ export const insightsRouter = router({ ...bookingWhere, OR: [ { - eventType: { - teamId, - }, + teamId, }, { userId: { in: userIdsFromTeams, }, + teamId: null, }, ], }; @@ -419,16 +410,14 @@ export const insightsRouter = router({ if (userId) { bookingWhere.userId = userId; // Don't take bookings from any team - bookingWhere.eventType = { - teamId: null, - }; + bookingWhere.teamId = null; } if (memberUserId) { bookingWhere.userId = memberUserId; } - const bookingsFromSelected = await ctx.prisma.booking.groupBy({ + const bookingsFromSelected = await ctx.prisma.bookingTimeStatus.groupBy({ by: ["eventTypeId"], where: bookingWhere, _count: { @@ -545,14 +534,14 @@ export const insightsRouter = router({ const startDate = dayjs(startDateString); const endDate = dayjs(endDateString); - let whereConditional: Prisma.BookingWhereInput = { + let whereConditional: Prisma.BookingTimeStatusWhereInput = { createdAt: { gte: dayjs(startDate).startOf("day").toDate(), lte: dayjs(endDate).endOf("day").toDate(), }, }; if (userId) { - delete whereConditional.eventType; + delete whereConditional.teamId; whereConditional["userId"] = userId; } @@ -571,14 +560,13 @@ export const insightsRouter = router({ ...whereConditional, OR: [ { - eventType: { - teamId, - }, + teamId, }, { userId: { in: userIdsFromTeams, }, + teamId: null, }, ], }; @@ -587,9 +575,7 @@ export const insightsRouter = router({ if (memberUserId) { whereConditional = { userId: memberUserId, - eventType: { - teamId, - }, + teamId, }; } @@ -614,7 +600,10 @@ export const insightsRouter = router({ const startDate = dayjs(date).startOf(startOfEndOf); const endDate = dayjs(date).endOf(startOfEndOf); - const bookingsInTimeRange = await ctx.prisma.booking.findMany({ + const bookingsInTimeRange = await ctx.prisma.bookingTimeStatus.findMany({ + select: { + eventLength: true, + }, where: { ...whereConditional, createdAt: { @@ -622,14 +611,11 @@ export const insightsRouter = router({ lte: endDate.toDate(), }, }, - include: { - eventType: true, - }, }); const avgDuration = bookingsInTimeRange.reduce((acc, booking) => { - const duration = booking.eventType?.length || 0; + const duration = booking.eventLength || 0; return acc + duration; }, 0) / bookingsInTimeRange.length; @@ -654,21 +640,19 @@ export const insightsRouter = router({ return []; } const user = ctx.user; - const eventTypeWhere: Prisma.EventTypeWhereInput = { - teamId: teamId, - }; - if (eventTypeId) { - eventTypeWhere["id"] = eventTypeId; - } - const bookingWhere: Prisma.BookingWhereInput = { - eventType: eventTypeWhere, + const bookingWhere: Prisma.BookingTimeStatusWhereInput = { + teamId, createdAt: { gte: dayjs(startDate).startOf("day").toDate(), lte: dayjs(endDate).endOf("day").toDate(), }, }; + if (eventTypeId) { + bookingWhere.eventTypeId = eventTypeId; + } + if (teamId) { const usersFromTeam = await ctx.prisma.membership.findMany({ where: { @@ -679,22 +663,22 @@ export const insightsRouter = router({ }, }); const userIdsFromTeams = usersFromTeam.map((u) => u.userId); - delete bookingWhere.eventType; + delete bookingWhere.eventTypeId; + delete bookingWhere.teamId; bookingWhere["OR"] = [ { - eventType: { - teamId, - }, + teamId, }, { userId: { in: userIdsFromTeams, }, + teamId: null, }, ]; } - const bookingsFromTeam = await ctx.prisma.booking.groupBy({ + const bookingsFromTeam = await ctx.prisma.bookingTimeStatus.groupBy({ by: ["userId"], where: bookingWhere, _count: { @@ -753,15 +737,9 @@ export const insightsRouter = router({ return []; } const user = ctx.user; - const eventTypeWhere: Prisma.EventTypeWhereInput = { - teamId: teamId, - }; - if (eventTypeId) { - eventTypeWhere["id"] = eventTypeId; - } - const bookingWhere: Prisma.BookingWhereInput = { - eventType: eventTypeWhere, + const bookingWhere: Prisma.BookingTimeStatusWhereInput = { + eventTypeId, createdAt: { gte: dayjs(startDate).startOf("day").toDate(), lte: dayjs(endDate).endOf("day").toDate(), @@ -778,22 +756,20 @@ export const insightsRouter = router({ }, }); const userIdsFromTeams = usersFromTeam.map((u) => u.userId); - delete bookingWhere.eventType; bookingWhere["OR"] = [ { - eventType: { - teamId, - }, + teamId, }, { userId: { in: userIdsFromTeams, }, + teamId: null, }, ]; } - const bookingsFromTeam = await ctx.prisma.booking.groupBy({ + const bookingsFromTeam = await ctx.prisma.bookingTimeStatus.groupBy({ by: ["userId"], where: bookingWhere, _count: { diff --git a/packages/prisma/migrations/20230418002117_booking_time_status/migration.sql b/packages/prisma/migrations/20230418002117_booking_time_status/migration.sql new file mode 100644 index 0000000000..5c628d044e --- /dev/null +++ b/packages/prisma/migrations/20230418002117_booking_time_status/migration.sql @@ -0,0 +1,34 @@ +-- View: public.BookingsTimeStatus + +-- DROP VIEW public."BookingsTimeStatus"; + +CREATE OR REPLACE VIEW public."BookingTimeStatus" + AS + SELECT "Booking".id, + "Booking".uid, + "Booking"."eventTypeId", + "Booking".title, + "Booking".description, + "Booking"."startTime", + "Booking"."endTime", + "Booking"."createdAt", + "Booking".location, + "Booking".paid, + "Booking".status, + "Booking".rescheduled, + "Booking"."userId", + "et"."teamId", + "et"."length" as "eventLength", + CASE + WHEN "Booking".rescheduled IS TRUE THEN 'rescheduled'::text + WHEN "Booking".status = 'cancelled'::"BookingStatus" AND "Booking".rescheduled IS FALSE THEN 'cancelled'::text + WHEN "Booking"."endTime" < now() THEN 'completed'::text + WHEN "Booking"."endTime" > now() THEN 'uncompleted'::text + ELSE NULL::text + END AS "timeStatus" + FROM "Booking" + LEFT JOIN "EventType" et ON "Booking"."eventTypeId" = et.id + LEFT JOIN "Membership" mb ON "mb"."userId" = "Booking"."userId"; + + + diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index cbcd199605..054a5999b3 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -8,7 +8,7 @@ datasource db { generator client { provider = "prisma-client-js" - previewFeatures = [] + previewFeatures = ["views"] } generator zod { @@ -817,3 +817,22 @@ model SelectedSlots { @@unique(fields: [userId, slotUtcStartDate, slotUtcEndDate, uid], name: "selectedSlotUnique") } + +view BookingTimeStatus { + id Int @unique + uid String? + eventTypeId Int? + title String? + description String? + startTime DateTime? + endTime DateTime? + createdAt DateTime? + location String? + paid Boolean? + status BookingStatus? + rescheduled Boolean? + userId Int? + teamId Int? + eventLength Int? + timeStatus String? +} diff --git a/packages/prisma/seed-insights.ts b/packages/prisma/seed-insights.ts index 8a832d3ddf..5c784450c5 100644 --- a/packages/prisma/seed-insights.ts +++ b/packages/prisma/seed-insights.ts @@ -268,7 +268,7 @@ async function main() { await prisma.booking.createMany({ data: [ - ...new Array(100) + ...new Array(10000) .fill(0) .map(() => shuffle({ ...baseBookingSingle }, dayjs().get("y") - 1, singleEvents)), ], @@ -276,7 +276,7 @@ async function main() { await prisma.booking.createMany({ data: [ - ...new Array(100) + ...new Array(10000) .fill(0) .map(() => shuffle({ ...baseBookingSingle }, dayjs().get("y") - 0, singleEvents)), ], @@ -332,7 +332,7 @@ async function main() { // Create past bookings -2y, -1y, -0y await prisma.booking.createMany({ data: [ - ...new Array(100) + ...new Array(10000) .fill(0) .map(() => shuffle({ ...baseBooking }, dayjs().get("y") - 2, teamEvents, [ @@ -345,7 +345,7 @@ async function main() { await prisma.booking.createMany({ data: [ - ...new Array(100) + ...new Array(10000) .fill(0) .map(() => shuffle({ ...baseBooking }, dayjs().get("y") - 1, teamEvents, [ @@ -358,7 +358,7 @@ async function main() { await prisma.booking.createMany({ data: [ - ...new Array(100) + ...new Array(10000) .fill(0) .map(() => shuffle({ ...baseBooking }, dayjs().get("y"), teamEvents, [ @@ -392,3 +392,149 @@ main() await prisma.$disconnect(); process.exit(1); }); + +/** + * This will create many users in insights teams with bookings 1y in the past + * Should be run after the main function is executed once + */ +async function createPerformanceData() { + const createExtraMembers = false; // Turn ON to be executed + let extraMembersIds; + const insightsTeam = await prisma.team.findFirst({ + where: { + slug: "insights-team", + }, + }); + + if (createExtraMembers) { + const insightsRandomUsers: Prisma.UserCreateManyArgs["data"] = []; + const numInsightsUsers = 50; // Change this value to adjust the number of insights users to create + for (let i = 0; i < numInsightsUsers; i++) { + const timestamp = Date.now(); + const email = `insightsuser${timestamp}@example.com`; + const insightsUser = { + email, + password: await hashPassword("insightsuser"), + name: `Insights User ${timestamp}`, + username: `insights-user-${timestamp}`, + completedOnboarding: true, + }; + insightsRandomUsers.push(insightsUser); + } + + await prisma.user.createMany({ + data: insightsRandomUsers, + }); + // Lets find the ids of the users we just created + extraMembersIds = await prisma.user.findMany({ + where: { + email: { + in: insightsRandomUsers.map((user) => user.email), + }, + }, + select: { + id: true, + }, + }); + } + + if (createExtraMembers) { + if (insightsTeam === null) { + console.log("This should not happen"); + throw new Error("Insights team id is undefined or null"); + } + + await prisma.membership.createMany({ + data: extraMembersIds.map((memberId) => ({ + teamId: insightsTeam?.id ?? 1, + userId: memberId.id, + role: "MEMBER", + accepted: true, + })), + }); + + const updateMemberPromises = extraMembersIds.map((memberId) => + prisma.team.update({ + where: { + id: insightsTeam?.id, + }, + data: { + members: { + connect: { + userId_teamId: { + userId: memberId.id, + teamId: insightsTeam?.id ?? 1, + }, + }, + }, + }, + }) + ); + + await Promise.all(updateMemberPromises); + + // Create events for every Member id + const createEvents = extraMembersIds.map((memberId) => ({ + title: `Single Event User - ${memberId.id}`, + slug: `single-event-user-${memberId.id}`, + description: `Single Event User - ${memberId.id}`, + length: 30, + userId: memberId.id, + users: { + connect: { + id: memberId.id, + }, + }, + })); + const createEventPromises = createEvents.map((data) => + prisma.eventType.create({ + data, + }) + ); + await Promise.all(createEventPromises); + + // load the events we just created + const singleEventsCreated = await prisma.eventType.findMany({ + where: { + userId: { + in: extraMembersIds.map((memberId) => memberId.id), + }, + }, + }); + + // Create bookings for every single event + const baseBooking = { + uid: "demo performance data booking", + title: "Single Event Booking Perf", + description: "Single Event Booking Perf", + startTime: dayjs().toISOString(), + endTime: dayjs().toISOString(), + eventTypeId: singleEventsCreated[0].id, + }; + + await prisma.booking.createMany({ + data: [ + ...new Array(10000) + .fill(0) + .map(() => shuffle({ ...baseBooking }, dayjs().get("y"), singleEventsCreated)), + ], + }); + } +} + +createPerformanceData() + .then(async () => { + await prisma.$disconnect(); + }) + .catch(async (e) => { + console.error(e); + await prisma.user.deleteMany({ + where: { + username: { + contains: "insights-user-", + }, + }, + }); + await prisma.$disconnect(); + process.exit(1); + });