diff --git a/apps/api/lib/validations/event-type.ts b/apps/api/lib/validations/event-type.ts
index 70823213bf0922..cbabad6dc492ae 100644
--- a/apps/api/lib/validations/event-type.ts
+++ b/apps/api/lib/validations/event-type.ts
@@ -60,6 +60,7 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({
successRedirectUrl: true,
locations: true,
bookingLimits: true,
+ onlyShowFirstAvailableSlot: true,
durationLimits: true,
})
.merge(
@@ -147,6 +148,7 @@ export const schemaEventTypeReadPublic = EventType.pick({
seatsShowAvailabilityCount: true,
bookingFields: true,
bookingLimits: true,
+ onlyShowFirstAvailableSlot: true,
durationLimits: true,
}).merge(
z.object({
diff --git a/apps/web/components/eventtype/EventLimitsTab.tsx b/apps/web/components/eventtype/EventLimitsTab.tsx
index 24502bb2b872fe..da68c260a9b3c6 100644
--- a/apps/web/components/eventtype/EventLimitsTab.tsx
+++ b/apps/web/components/eventtype/EventLimitsTab.tsx
@@ -298,6 +298,29 @@ export const EventLimitsTab = ({ eventType }: Pick
+ {
+ const isChecked = value;
+ return (
+ {
+ formMethods.setValue("onlyShowFirstAvailableSlot", active ?? false);
+ }}
+ switchContainerClassName={classNames(
+ "border-subtle mt-6 rounded-lg border py-6 px-4 sm:px-6",
+ isChecked && "rounded-b-none"
+ )}
+ />
+ );
+ }}
+ />
;
@@ -250,6 +251,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
description: eventType.description ?? undefined,
schedule: eventType.schedule || undefined,
bookingLimits: eventType.bookingLimits || undefined,
+ onlyShowFirstAvailableSlot: eventType.onlyShowFirstAvailableSlot || undefined,
durationLimits: eventType.durationLimits || undefined,
length: eventType.length,
hidden: eventType.hidden,
@@ -429,6 +431,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
seatsShowAttendees,
seatsShowAvailabilityCount,
bookingLimits,
+ onlyShowFirstAvailableSlot,
durationLimits,
recurringEvent,
locations,
@@ -491,6 +494,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
beforeEventBuffer: beforeBufferTime,
afterEventBuffer: afterBufferTime,
bookingLimits,
+ onlyShowFirstAvailableSlot,
durationLimits,
seatsPerTimeSlot,
seatsShowAttendees,
@@ -532,6 +536,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
seatsShowAttendees,
seatsShowAvailabilityCount,
bookingLimits,
+ onlyShowFirstAvailableSlot,
durationLimits,
recurringEvent,
locations,
@@ -584,6 +589,7 @@ const EventTypePage = (props: EventTypeSetupProps) => {
beforeEventBuffer: beforeBufferTime,
afterEventBuffer: afterBufferTime,
bookingLimits,
+ onlyShowFirstAvailableSlot,
durationLimits,
seatsPerTimeSlot,
seatsShowAttendees,
diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json
index a29287a20b1893..39e5906ea2466a 100644
--- a/apps/web/public/static/locales/en/common.json
+++ b/apps/web/public/static/locales/en/common.json
@@ -1481,6 +1481,8 @@
"report_app": "Report app",
"limit_booking_frequency": "Limit booking frequency",
"limit_booking_frequency_description": "Limit how many times this event can be booked",
+ "limit_booking_only_first_slot": "Limit booking only first slot",
+ "limit_booking_only_first_slot_description": "Allow only the first slot of every day to be booked",
"limit_total_booking_duration": "Limit total booking duration",
"limit_total_booking_duration_description": "Limit total amount of time that this event can be booked",
"add_limit": "Add Limit",
diff --git a/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts b/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts
index 585981796e39b2..043f717d82d7f7 100644
--- a/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts
+++ b/packages/features/ee/managed-event-types/lib/handleChildrenEventTypes.ts
@@ -186,6 +186,7 @@ export default async function handleChildrenEventTypes({
metadata: (managedEventTypeValues.metadata as Prisma.InputJsonValue) ?? undefined,
bookingFields: (managedEventTypeValues.bookingFields as Prisma.InputJsonValue) ?? undefined,
durationLimits: (managedEventTypeValues.durationLimits as Prisma.InputJsonValue) ?? undefined,
+ onlyShowFirstAvailableSlot: managedEventTypeValues.onlyShowFirstAvailableSlot ?? false,
userId,
users: {
connect: [{ id: userId }],
@@ -235,6 +236,7 @@ export default async function handleChildrenEventTypes({
hidden: children?.find((ch) => ch.owner.id === userId)?.hidden ?? false,
bookingLimits:
(managedEventTypeValues.bookingLimits as unknown as Prisma.InputJsonObject) ?? undefined,
+ onlyShowFirstAvailableSlot: managedEventTypeValues.onlyShowFirstAvailableSlot ?? false,
recurringEvent:
(managedEventTypeValues.recurringEvent as unknown as Prisma.InputJsonValue) ?? undefined,
metadata: (managedEventTypeValues.metadata as Prisma.InputJsonValue) ?? undefined,
diff --git a/packages/lib/defaultEvents.ts b/packages/lib/defaultEvents.ts
index 5243b63ebdfda7..ad0857f3d100a5 100644
--- a/packages/lib/defaultEvents.ts
+++ b/packages/lib/defaultEvents.ts
@@ -81,6 +81,7 @@ const commons = {
seatsPerTimeSlot: null,
seatsShowAttendees: null,
seatsShowAvailabilityCount: null,
+ onlyShowFirstAvailableSlot: false,
id: 0,
hideCalendarNotes: false,
recurringEvent: null,
diff --git a/packages/lib/getEventTypeById.ts b/packages/lib/getEventTypeById.ts
index be26508d9fb913..9606d35108e3f3 100644
--- a/packages/lib/getEventTypeById.ts
+++ b/packages/lib/getEventTypeById.ts
@@ -101,6 +101,7 @@ export default async function getEventTypeById({
slotInterval: true,
hashedLink: true,
bookingLimits: true,
+ onlyShowFirstAvailableSlot: true,
durationLimits: true,
successRedirectUrl: true,
currency: true,
diff --git a/packages/lib/test/builder.ts b/packages/lib/test/builder.ts
index 4a2f79c891ef40..f766d74578c3ac 100644
--- a/packages/lib/test/builder.ts
+++ b/packages/lib/test/builder.ts
@@ -92,6 +92,7 @@ export const buildEventType = (eventType?: Partial): EventType => {
minimumBookingNotice: 120,
beforeEventBuffer: 0,
afterEventBuffer: 0,
+ onlyShowFirstAvailableSlot: false,
seatsPerTimeSlot: null,
seatsShowAttendees: null,
seatsShowAvailabilityCount: null,
diff --git a/packages/prisma/migrations/20231202181233_adding_show_first_available_timeslot/migration.sql b/packages/prisma/migrations/20231202181233_adding_show_first_available_timeslot/migration.sql
new file mode 100644
index 00000000000000..9cb3a0d629fe33
--- /dev/null
+++ b/packages/prisma/migrations/20231202181233_adding_show_first_available_timeslot/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "EventType" ADD COLUMN "onlyShowFirstAvailableSlot" BOOLEAN NOT NULL DEFAULT false;
diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma
index 8cc61111fa89ed..ef3e541070705a 100644
--- a/packages/prisma/schema.prisma
+++ b/packages/prisma/schema.prisma
@@ -98,6 +98,7 @@ model EventType {
beforeEventBuffer Int @default(0)
afterEventBuffer Int @default(0)
seatsPerTimeSlot Int?
+ onlyShowFirstAvailableSlot Boolean @default(false)
seatsShowAttendees Boolean? @default(false)
seatsShowAvailabilityCount Boolean? @default(true)
schedulingType SchedulingType?
diff --git a/packages/prisma/zod-utils.ts b/packages/prisma/zod-utils.ts
index dba23604b7ff9c..b5a2296a6f43d9 100644
--- a/packages/prisma/zod-utils.ts
+++ b/packages/prisma/zod-utils.ts
@@ -585,6 +585,7 @@ export const allManagedEventTypeProps: { [k in keyof Omit 0) {
+ return r;
+ }
r[dateString].push({
...passThroughProps,
time: time.toISOString(),