perf: don't fetch all the hosts #18319 followup (#19021)

* perf: don't fetch all the hosts #18319 followup

* undo for user events

* undo for regular user events

* fix: limitHostsToThree -> hostsLimit

* accepting hostLimit prop in <Booker />

* Update booking.tsx

* hostLimit -> hostsLimit
This commit is contained in:
Somay Chauhan
2025-01-31 12:19:21 +02:00
committed by GitHub
parent 8d2dc0bbe5
commit 56cd9cef8b
10 changed files with 138 additions and 66 deletions
@@ -149,10 +149,14 @@ export class OrganizationsEventTypesController {
@Param("teamId", ParseIntPipe) teamId: number,
@Query() queryParams: GetTeamEventTypesQuery_2024_06_14
): Promise<GetTeamEventTypesOutput> {
const { eventSlug } = queryParams;
const { eventSlug, hostsLimit } = queryParams;
if (eventSlug) {
const eventType = await this.organizationsEventTypesService.getTeamEventTypeBySlug(teamId, eventSlug);
const eventType = await this.organizationsEventTypesService.getTeamEventTypeBySlug(
teamId,
eventSlug,
hostsLimit
);
return {
status: SUCCESS_STATUS,
@@ -64,8 +64,12 @@ export class OrganizationsEventTypesService {
return this.teamsEventTypesService.getTeamEventType(teamId, eventTypeId);
}
async getTeamEventTypeBySlug(teamId: number, eventTypeSlug: string): Promise<DatabaseTeamEventType | null> {
return this.teamsEventTypesService.getTeamEventTypeBySlug(teamId, eventTypeSlug);
async getTeamEventTypeBySlug(
teamId: number,
eventTypeSlug: string,
hostsLimit?: number
): Promise<DatabaseTeamEventType | null> {
return this.teamsEventTypesService.getTeamEventTypeBySlug(teamId, eventTypeSlug, hostsLimit);
}
async getTeamEventTypes(teamId: number): Promise<DatabaseTeamEventType[]> {
@@ -75,8 +75,16 @@ export class TeamsEventTypesService {
return eventType;
}
async getTeamEventTypeBySlug(teamId: number, eventTypeSlug: string): Promise<DatabaseTeamEventType | null> {
const eventType = await this.teamsEventTypesRepository.getTeamEventTypeBySlug(teamId, eventTypeSlug);
async getTeamEventTypeBySlug(
teamId: number,
eventTypeSlug: string,
hostsLimit?: number
): Promise<DatabaseTeamEventType | null> {
const eventType = await this.teamsEventTypesRepository.getTeamEventTypeBySlug(
teamId,
eventTypeSlug,
hostsLimit
);
if (!eventType) {
return null;
@@ -16,7 +16,7 @@ export class TeamsEventTypesRepository {
});
}
async getTeamEventTypeBySlug(teamId: number, eventTypeSlug: string) {
async getTeamEventTypeBySlug(teamId: number, eventTypeSlug: string, hostsLimit?: number) {
return this.dbRead.prisma.eventType.findUnique({
where: {
teamId_slug: {
@@ -27,7 +27,11 @@ export class TeamsEventTypesRepository {
include: {
users: true,
schedule: true,
hosts: true,
hosts: hostsLimit
? {
take: hostsLimit,
}
: true,
destinationCalendar: true,
team: {
select: {
+18
View File
@@ -1251,6 +1251,15 @@
"schema": {
"type": "string"
}
},
{
"name": "hostsLimit",
"required": false,
"in": "query",
"description": "Specifies the maximum number of hosts to include in the response. This limit helps optimize performance. If not provided, all Hosts will be fetched.",
"schema": {
"type": "number"
}
}
],
"responses": {
@@ -5889,6 +5898,15 @@
"schema": {
"type": "string"
}
},
{
"name": "hostsLimit",
"required": false,
"in": "query",
"description": "Specifies the maximum number of hosts to include in the response. This limit helps optimize performance. If not provided, all Hosts will be fetched.",
"schema": {
"type": "number"
}
}
],
"responses": {
@@ -81,6 +81,7 @@ export type BookerPlatformWrapperAtomProps = Omit<
metadata?: Record<string, string>;
bannerUrl?: string;
onDryRunSuccess?: () => void;
hostsLimit?: number;
};
type VIEW_TYPE = keyof typeof BookerLayouts;
@@ -151,7 +152,7 @@ export const BookerPlatformWrapper = (
isError: isTeamError,
isPending: isTeamPending,
data: teamEventTypeData,
} = useTeamEventType(teamId, props.eventSlug, props.isTeamEvent);
} = useTeamEventType(teamId, props.eventSlug, props.isTeamEvent, props.hostsLimit);
const event = useMemo(() => {
if (props.isTeamEvent && !isTeamPending && teamId && teamEventTypeData && teamEventTypeData.length > 0) {
@@ -161,7 +162,12 @@ export const BookerPlatformWrapper = (
isPending: isTeamPending,
data:
teamEventTypeData && teamEventTypeData.length > 0
? transformApiTeamEventTypeForAtom(teamEventTypeData[0], props.entity, props.defaultFormValues)
? transformApiTeamEventTypeForAtom(
teamEventTypeData[0],
props.entity,
props.defaultFormValues,
!!props.hostsLimit
)
: undefined,
};
}
@@ -172,7 +178,7 @@ export const BookerPlatformWrapper = (
isPending,
data:
data && data.length > 0
? transformApiEventTypeForAtom(data[0], props.entity, props.defaultFormValues)
? transformApiEventTypeForAtom(data[0], props.entity, props.defaultFormValues, !!props.hostsLimit)
: undefined,
};
}, [
@@ -187,6 +193,7 @@ export const BookerPlatformWrapper = (
isTeamPending,
isTeamSuccess,
isTeamError,
props.hostsLimit,
]);
if (isDynamic && props.duration && event.data) {
@@ -37,7 +37,8 @@ import type { BookerPlatformWrapperAtomProps } from "../../booker/BookerPlatform
export function transformApiEventTypeForAtom(
eventType: Omit<EventTypeOutput_2024_06_14, "ownerId"> & { bannerUrl?: string },
entity: BookerPlatformWrapperAtomProps["entity"] | undefined,
defaultFormValues: BookerPlatformWrapperAtomProps["defaultFormValues"] | undefined
defaultFormValues: BookerPlatformWrapperAtomProps["defaultFormValues"] | undefined,
limitHosts = false
) {
const {
lengthInMinutes,
@@ -70,6 +71,25 @@ export function transformApiEventTypeForAtom(
firstUsersMetadata?.defaultBookerLayouts || defaultEventBookerLayouts
);
const metadata = EventTypeMetaDataSchema.parse(eventType.metadata);
const usersTransformed = users.map((user) => ({
...user,
metadata: undefined,
bookerUrl: getBookerBaseUrlSync(null),
profile: {
username: user.username || "",
name: user.name,
weekStart: user.weekStart,
image: "",
brandColor: user.brandColor,
darkBrandColor: user.darkBrandColor,
theme: null,
organization: null,
id: user.id,
organizationId: null,
userId: user.id,
upId: `usr-${user.id}`,
},
}));
return {
...rest,
@@ -106,25 +126,9 @@ export function transformApiEventTypeForAtom(
logoUrl: undefined,
},
hosts: [],
users: users.map((user) => ({
...user,
metadata: undefined,
bookerUrl: getBookerBaseUrlSync(null),
profile: {
username: user.username || "",
name: user.name,
weekStart: user.weekStart,
image: "",
brandColor: user.brandColor,
darkBrandColor: user.darkBrandColor,
theme: null,
organization: null,
id: user.id,
organizationId: null,
userId: user.id,
upId: `usr-${user.id}`,
},
})),
subsetOfHosts: [],
users: !limitHosts ? usersTransformed : undefined,
subsetOfUsers: usersTransformed,
bookingLimits: bookingLimitsCount ? transformIntervalLimitsApiToInternal(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
? transformIntervalLimitsApiToInternal(bookingLimitsDuration)
@@ -153,7 +157,8 @@ export function transformApiEventTypeForAtom(
export function transformApiTeamEventTypeForAtom(
eventType: TeamEventTypeOutput_2024_06_14,
entity: BookerPlatformWrapperAtomProps["entity"] | undefined,
defaultFormValues: BookerPlatformWrapperAtomProps["defaultFormValues"] | undefined
defaultFormValues: BookerPlatformWrapperAtomProps["defaultFormValues"] | undefined,
limitHosts = false
) {
const {
lengthInMinutes,
@@ -188,6 +193,40 @@ export function transformApiTeamEventTypeForAtom(
firstUsersMetadata?.defaultBookerLayouts || defaultEventBookerLayouts
);
const hostTransformed = hosts.map((host) => ({
user: {
id: host.userId,
avatarUrl: null,
name: host.name,
username: "",
metadata: {},
darkBrandColor: null,
brandColor: null,
theme: null,
weekStart: "Sunday",
},
}));
const usersTransformed = hosts.map((host) => ({
...host,
metadata: undefined,
bookerUrl: getBookerBaseUrlSync(null),
profile: {
username: "",
name: host.name,
weekStart: "Sunday",
image: "",
brandColor: null,
darkBrandColor: null,
theme: null,
organization: null,
id: host.userId,
organizationId: null,
userId: host.userId,
upId: `usr-${host.userId}`,
},
}));
return {
...rest,
length: lengthInMinutes,
@@ -223,38 +262,10 @@ export function transformApiTeamEventTypeForAtom(
name: team?.name,
logoUrl: team?.logoUrl,
},
hosts: hosts.map((host) => ({
user: {
id: host.userId,
avatarUrl: null,
name: host.name,
username: "",
metadata: {},
darkBrandColor: null,
brandColor: null,
theme: null,
weekStart: "Sunday",
},
})),
users: hosts.map((host) => ({
...host,
metadata: undefined,
bookerUrl: getBookerBaseUrlSync(null),
profile: {
username: "",
name: host.name,
weekStart: "Sunday",
image: "",
brandColor: null,
darkBrandColor: null,
theme: null,
organization: null,
id: host.userId,
organizationId: null,
userId: host.userId,
upId: `usr-${host.userId}`,
},
})),
hosts: !limitHosts ? hostTransformed : undefined,
subsetOfHosts: hostTransformed,
users: !limitHosts ? usersTransformed : undefined,
subsetOfUsers: usersTransformed,
recurringEvent: recurrence ? transformRecurrenceApiToInternal(recurrence) : null,
bookingLimits: bookingLimitsCount ? transformIntervalLimitsApiToInternal(bookingLimitsCount) : undefined,
durationLimits: bookingLimitsDuration
@@ -9,13 +9,18 @@ import { useAtomsContext } from "../../useAtomsContext";
export const QUERY_KEY = "use-team-event-type";
export const useTeamEventType = (teamId: number | undefined, eventSlug: string, isTeamEvent: boolean | undefined) => {
export const useTeamEventType = (teamId: number | undefined, eventSlug: string, isTeamEvent: boolean | undefined, hostsLimit?: number) => {
const { organizationId } = useAtomsContext();
const requestEventSlug = eventSlug;
const pathname = `/organizations/${organizationId}/teams/${teamId}/event-types?eventSlug=${requestEventSlug}`;
let pathname = `/organizations/${organizationId}/teams/${teamId}/event-types?eventSlug=${requestEventSlug}`;
if (hostsLimit !== undefined) {
pathname += `&hostsLimit=${hostsLimit}`;
}
const event = useQuery({
queryKey: [QUERY_KEY, eventSlug, organizationId, teamId],
@@ -118,6 +118,7 @@ export default function Bookings(props: { calUsername: string; calEmail: string
{...(isTeamEvent
? { isTeamEvent: true, teamId: teams?.[0]?.id || 0 }
: { username: props.calUsername })}
hostsLimit={3}
/>
</>
)}
@@ -132,6 +133,7 @@ export default function Bookings(props: { calUsername: string; calEmail: string
}}
duration={eventTypeDuration}
bannerUrl="https://i0.wp.com/mahala.co.uk/wp-content/uploads/2014/12/img_banner-thin_mountains.jpg?fit=800%2C258&ssl=1"
hostsLimit={3}
/>
)}
{bookingTitle && <p>Booking created: {bookingTitle}</p>}
@@ -55,6 +55,15 @@ export class GetTeamEventTypesQuery_2024_06_14 {
description: "Slug of team event type to return.",
})
eventSlug?: string;
@Transform(({ value }) => Number(value))
@IsOptional()
@IsNumber()
@ApiPropertyOptional({
description:
"Specifies the maximum number of hosts to include in the response. This limit helps optimize performance. If not provided, all Hosts will be fetched.",
})
hostsLimit?: number;
}
function TransformUsernames() {