From eeb0cd7e4da1853ec920f9c08d602cbed388eab5 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 4 Mar 2022 15:49:03 +0530 Subject: [PATCH] Set buffer time before/after event type (#2015) * before and after buffer added to handleAvailableSlots function * --WIP * added migration * pull buffer data from DB * cleanup * added buffer input in form * removed unused functions in controller field * improved the buffer time check * fixed default value and added preceding event afterbuffer consideration * fixed e2e test issue Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../web/components/booking/AvailableTimes.tsx | 6 + .../booking/pages/AvailabilityPage.tsx | 2 + apps/web/lib/hooks/useSlots.ts | 36 +++++- apps/web/lib/types/event-type.ts | 2 + apps/web/pages/[user]/[type].tsx | 2 + apps/web/pages/event-types/[type].tsx | 107 +++++++++++++++++- apps/web/pages/team/[slug]/[type].tsx | 2 + apps/web/public/static/locales/en/common.json | 4 + .../migration.sql | 3 + packages/prisma/schema.prisma | 2 + 10 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 packages/prisma/migrations/20220302035831_add_before_and_after_event_buffer/migration.sql diff --git a/apps/web/components/booking/AvailableTimes.tsx b/apps/web/components/booking/AvailableTimes.tsx index 3391f259..a427e0fc 100644 --- a/apps/web/components/booking/AvailableTimes.tsx +++ b/apps/web/components/booking/AvailableTimes.tsx @@ -14,6 +14,8 @@ import Loader from "@components/Loader"; type AvailableTimesProps = { timeFormat: string; minimumBookingNotice: number; + beforeBufferTime: number; + afterBufferTime: number; eventTypeId: number; eventLength: number; slotInterval: number | null; @@ -33,6 +35,8 @@ const AvailableTimes: FC = ({ timeFormat, users, schedulingType, + beforeBufferTime, + afterBufferTime, }) => { const { t, i18n } = useLocale(); const router = useRouter(); @@ -45,6 +49,8 @@ const AvailableTimes: FC = ({ schedulingType, users, minimumBookingNotice, + beforeBufferTime, + afterBufferTime, eventTypeId, }); diff --git a/apps/web/components/booking/pages/AvailabilityPage.tsx b/apps/web/components/booking/pages/AvailabilityPage.tsx index a3365920..27f89fe2 100644 --- a/apps/web/components/booking/pages/AvailabilityPage.tsx +++ b/apps/web/components/booking/pages/AvailabilityPage.tsx @@ -241,6 +241,8 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => { date={selectedDate} users={eventType.users} schedulingType={eventType.schedulingType ?? null} + beforeBufferTime={eventType.beforeEventBuffer} + afterBufferTime={eventType.afterEventBuffer} /> )} diff --git a/apps/web/lib/hooks/useSlots.ts b/apps/web/lib/hooks/useSlots.ts index 196651f5..8845cf2a 100644 --- a/apps/web/lib/hooks/useSlots.ts +++ b/apps/web/lib/hooks/useSlots.ts @@ -30,10 +30,21 @@ type UseSlotsProps = { date: Dayjs; users: { username: string | null }[]; schedulingType: SchedulingType | null; + beforeBufferTime?: number; + afterBufferTime?: number; }; export const useSlots = (props: UseSlotsProps) => { - const { slotInterval, eventLength, minimumBookingNotice = 0, date, users, eventTypeId } = props; + const { + slotInterval, + eventLength, + minimumBookingNotice = 0, + beforeBufferTime = 0, + afterBufferTime = 0, + date, + users, + eventTypeId, + } = props; const [slots, setSlots] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); @@ -124,6 +135,29 @@ export const useSlots = (props: UseSlotsProps) => { // Check if startTime is between slot else if (startTime.isBetween(times[i], times[i].add(eventLength, "minutes"))) { times.splice(i, 1); + } + // Check if time is between afterBufferTime and beforeBufferTime + else if ( + times[i].isBetween( + startTime.subtract(beforeBufferTime, "minutes"), + endTime.add(afterBufferTime, "minutes") + ) + ) { + times.splice(i, 1); + } + // considering preceding event's after buffer time + else if ( + i > 0 && + times[i - 1] + .add(eventLength + afterBufferTime, "minutes") + .isBetween( + startTime.subtract(beforeBufferTime, "minutes"), + endTime.add(afterBufferTime, "minutes"), + null, + "[)" + ) + ) { + times.splice(i, 1); } else { return true; } diff --git a/apps/web/lib/types/event-type.ts b/apps/web/lib/types/event-type.ts index 14d3b46b..ec8442ef 100644 --- a/apps/web/lib/types/event-type.ts +++ b/apps/web/lib/types/event-type.ts @@ -14,6 +14,8 @@ export type AdvancedOptions = { requiresConfirmation?: boolean; disableGuests?: boolean; minimumBookingNotice?: number; + beforeBufferTime?: number; + afterBufferTime?: number; slotInterval?: number | null; price?: number; currency?: string; diff --git a/apps/web/pages/[user]/[type].tsx b/apps/web/pages/[user]/[type].tsx index 59dd149a..21b1892a 100644 --- a/apps/web/pages/[user]/[type].tsx +++ b/apps/web/pages/[user]/[type].tsx @@ -44,6 +44,8 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => periodCountCalendarDays: true, schedulingType: true, minimumBookingNotice: true, + beforeEventBuffer: true, + afterEventBuffer: true, timeZone: true, metadata: true, slotInterval: true, diff --git a/apps/web/pages/event-types/[type].tsx b/apps/web/pages/event-types/[type].tsx index 8993a476..0958dfc9 100644 --- a/apps/web/pages/event-types/[type].tsx +++ b/apps/web/pages/event-types/[type].tsx @@ -364,6 +364,8 @@ const EventTypePage = (props: inferSSRProps) => { periodCountCalendarDays: "1" | "0"; periodDates: { startDate: Date; endDate: Date }; minimumBookingNotice: number; + beforeBufferTime: number; + afterBufferTime: number; slotInterval: number | null; destinationCalendar: { integration: string; @@ -683,7 +685,14 @@ const EventTypePage = (props: inferSSRProps) => {
{ - const { periodDates, periodCountCalendarDays, smartContractAddress, ...input } = values; + const { + periodDates, + periodCountCalendarDays, + smartContractAddress, + beforeBufferTime, + afterBufferTime, + ...input + } = values; updateMutation.mutate({ ...input, availability: availabilityState, @@ -691,6 +700,8 @@ const EventTypePage = (props: inferSSRProps) => { periodEndDate: periodDates.endDate, periodCountCalendarDays: periodCountCalendarDays === "1", id: eventType.id, + beforeEventBuffer: beforeBufferTime, + afterEventBuffer: afterBufferTime, metadata: smartContractAddress ? { smartContractAddress, @@ -1189,6 +1200,98 @@ const EventTypePage = (props: inferSSRProps) => { /> +
+
+
+ +
+
+
+
+ + { + const beforeBufferOptions = [ + { + label: t("event_buffer_default"), + value: 0, + }, + ...[5, 10, 15, 20, 30, 45, 60].map((minutes) => ({ + label: minutes + " " + t("minutes"), + value: minutes, + })), + ]; + return ( + { + if (val) onChange(val.value); + }} + defaultValue={ + afterBufferOptions.find((option) => option.value === value) || + afterBufferOptions[0] + } + options={afterBufferOptions} + /> + ); + }} + /> +
+
+
+

@@ -1618,6 +1721,8 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => requiresConfirmation: true, disableGuests: true, minimumBookingNotice: true, + beforeEventBuffer: true, + afterEventBuffer: true, slotInterval: true, team: { select: { diff --git a/apps/web/pages/team/[slug]/[type].tsx b/apps/web/pages/team/[slug]/[type].tsx index 9ca9ea57..b1abadf8 100644 --- a/apps/web/pages/team/[slug]/[type].tsx +++ b/apps/web/pages/team/[slug]/[type].tsx @@ -61,6 +61,8 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => periodDays: true, periodCountCalendarDays: true, minimumBookingNotice: true, + beforeEventBuffer: true, + afterEventBuffer: true, price: true, currency: true, timeZone: true, diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index cc9188b6..67fa3055 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -284,6 +284,10 @@ "hover_over_bold_times_tip": "Tip: Hover over the bold times for a full timestamp", "start_time": "Start time", "end_time": "End time", + "buffer_time": "Buffer time", + "before_event": "Before event", + "after_event": "After event", + "event_buffer_default": "No buffer time", "buffer": "Buffer", "your_day_starts_at": "Your day starts at", "your_day_ends_at": "Your day ends at", diff --git a/packages/prisma/migrations/20220302035831_add_before_and_after_event_buffer/migration.sql b/packages/prisma/migrations/20220302035831_add_before_and_after_event_buffer/migration.sql new file mode 100644 index 00000000..dec9e5df --- /dev/null +++ b/packages/prisma/migrations/20220302035831_add_before_and_after_event_buffer/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "EventType" ADD COLUMN "afterEventBuffer" INTEGER NOT NULL DEFAULT 0, +ADD COLUMN "beforeEventBuffer" INTEGER NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 2fefa2b7..073170ba 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -59,6 +59,8 @@ model EventType { requiresConfirmation Boolean @default(false) disableGuests Boolean @default(false) minimumBookingNotice Int @default(120) + beforeEventBuffer Int @default(0) + afterEventBuffer Int @default(0) schedulingType SchedulingType? Schedule Schedule[] price Int @default(0)