minimum booking notice allows hours and days

This commit is contained in:
123om123 2022-10-24 18:47:04 -04:00
parent 9f1341e94e
commit 27a31d70e2
5 changed files with 157 additions and 63 deletions

View File

@ -9,7 +9,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { PeriodType } from "@calcom/prisma/client";
import type { BookingLimit } from "@calcom/types/Calendar";
import { Icon } from "@calcom/ui";
import { Select, Switch, Label, Input, MinutesField, Button } from "@calcom/ui/v2";
import { Select, Switch, Label, Input, DurationField, Button } from "@calcom/ui/v2";
import DateRangePicker from "@calcom/ui/v2/core/form/date-range-picker/DateRangePicker";
export const EventLimitsTab = (props: Pick<EventTypeSetupInfered, "eventType">) => {
@ -45,6 +45,8 @@ export const EventLimitsTab = (props: Pick<EventTypeSetupInfered, "eventType">)
defaultValue: periodType?.type,
});
const durationArray = [eventType.minimumBookingNoticeType];
return (
<div>
<div className="flex flex-col space-y-4 lg:flex-row lg:space-y-0 lg:space-x-4">
@ -114,13 +116,94 @@ export const EventLimitsTab = (props: Pick<EventTypeSetupInfered, "eventType">)
</div>
</div>
<div className="flex flex-col space-y-4 pt-4 lg:flex-row lg:space-y-0 lg:space-x-4">
<div className="w-full">
<MinutesField
required
label={t("minimum_booking_notice")}
type="number"
placeholder="120"
{...formMethods.register("minimumBookingNotice", { valueAsNumber: true })}
<div className="flex w-full items-end">
<Controller
name="minimumBookingNotice"
control={formMethods.control}
render={() => {
const minBookingValue = formMethods.watch("minimumBookingNotice");
let newMinBookingValue: number;
const convertToNewDurationType = function (
prevType: string,
newType: string,
prevValue: number
) {
console.log(prevType, newType, prevValue);
if (!prevType) {
prevType = eventType.minimumBookingNoticeType;
}
if (newType == "mins") {
if (prevType == "hours") {
newMinBookingValue = prevValue * 60;
}
if (prevType == "calendar days") {
newMinBookingValue = prevValue * 1440;
}
} else if (newType == "hours") {
if (prevType == "mins") {
newMinBookingValue = prevValue / 60;
}
if (prevType == "calendar days") {
newMinBookingValue = prevValue * 24;
}
} else if (newType == "calendar days") {
if (prevType == "mins") {
newMinBookingValue = prevValue / 1440;
}
if (prevType == "hours") {
newMinBookingValue = prevValue / 24;
}
} else if (newType == prevType) {
newMinBookingValue = prevValue;
}
};
const durationTypeOptions = [
{
label: t("minutes"),
value: "mins",
},
{
label: t("hours"),
value: "hours",
},
{
label: t("calendar_days"),
value: "calendar days",
},
];
return (
<>
<DurationField
required
label={t("minimum_booking_notice")}
type="number"
placeholder="120"
className="mr-2 w-full"
defaultValue={eventType.minimumBookingNotice}
{...formMethods.register("minimumBookingNotice", { valueAsNumber: true })}
/>
<Select
isSearchable={false}
className="mb-2 ml-2 w-1/3"
defaultValue={durationTypeOptions.find(
(option) => option.value === eventType.minimumBookingNoticeType
)}
onChange={(val) => {
if (val) {
durationArray.unshift(val.value);
const previousValue = durationArray[1];
eventType.minimumBookingNoticeType = val.value;
convertToNewDurationType(previousValue, val.value, minBookingValue);
formMethods.setValue("minimumBookingNotice", newMinBookingValue);
}
}}
options={durationTypeOptions}
/>
</>
);
}}
/>
</div>
<div className="w-full">

View File

@ -72,6 +72,7 @@ export type FormValues = {
seatsShowAttendees: boolean | null;
seatsPerTimeSlotEnabled: boolean;
minimumBookingNotice: number;
minimumBookingNoticeType: string;
beforeBufferTime: number;
afterBufferTime: number;
slotInterval: number | null;
@ -163,6 +164,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
},
schedulingType: eventType.schedulingType,
minimumBookingNotice: eventType.minimumBookingNotice,
minimumBookingNoticeType: eventType.minimumBookingNoticeType,
metadata: eventType.metadata,
},
});
@ -228,6 +230,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
const {
periodDates,
periodCountCalendarDays,
minimumBookingNoticeType,
beforeBufferTime,
afterBufferTime,
seatsPerTimeSlot,
@ -254,6 +257,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
periodStartDate: periodDates.startDate,
periodEndDate: periodDates.endDate,
periodCountCalendarDays: periodCountCalendarDays === "1",
minimumBookingNoticeType,
id: eventType.id,
beforeEventBuffer: beforeBufferTime,
afterEventBuffer: afterBufferTime,
@ -355,6 +359,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
hideCalendarNotes: true,
disableGuests: true,
minimumBookingNotice: true,
minimumBookingNoticeType: true,
beforeEventBuffer: true,
afterEventBuffer: true,
slotInterval: true,

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "EventType" ADD COLUMN "minimumBookingNoticeType" TEXT NOT NULL DEFAULT 'mins';

View File

@ -30,60 +30,61 @@ enum PeriodType {
}
model EventType {
id Int @id @default(autoincrement())
id Int @id @default(autoincrement())
/// @zod.min(1)
title String
/// @zod.custom(imports.eventTypeSlug)
slug String
description String?
position Int @default(0)
/// @zod.custom(imports.eventTypeLocations)
locations Json?
length Int
hidden Boolean @default(false)
users User[] @relation("user_eventtype")
owner User? @relation("owner", fields: [userId], references: [id], onDelete: Cascade)
userId Int?
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
teamId Int?
hashedLink HashedLink?
bookings Booking[]
availability Availability[]
webhooks Webhook[]
destinationCalendar DestinationCalendar?
eventName String?
customInputs EventTypeCustomInput[]
timeZone String?
periodType PeriodType @default(UNLIMITED)
periodStartDate DateTime?
periodEndDate DateTime?
periodDays Int?
periodCountCalendarDays Boolean?
requiresConfirmation Boolean @default(false)
/// @zod.custom(imports.recurringEventType)
recurringEvent Json?
disableGuests Boolean @default(false)
hideCalendarNotes Boolean @default(false)
minimumBookingNotice Int @default(120)
beforeEventBuffer Int @default(0)
afterEventBuffer Int @default(0)
seatsPerTimeSlot Int?
seatsShowAttendees Boolean?
schedulingType SchedulingType?
schedule Schedule? @relation(fields: [scheduleId], references: [id])
scheduleId Int?
// price is deprecated. It has now moved to metadata.apps.stripe.price. Plan to drop this column.
price Int @default(0)
// currency is deprecated. It has now moved to metadata.apps.stripe.currency. Plan to drop this column.
currency String @default("usd")
slotInterval Int?
/// @zod.custom(imports.EventTypeMetaDataSchema)
metadata Json?
/// @zod.custom(imports.successRedirectUrl)
successRedirectUrl String?
workflows WorkflowsOnEventTypes[]
/// @zod.custom(imports.bookingLimitsType)
bookingLimits Json?
title String
/// @zod.custom(imports. eventTypeSlug)
slug String
description String?
position Int @default(0)
/// @zod.custom(imports. eventTypeLocations)
locations Json?
length Int
hidden Boolean @default(false)
users User[] @relation("user_eventtype")
owner User? @relation("owner", fields: [userId], references: [id], onDelete: Cascade)
userId Int?
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
teamId Int?
hashedLink HashedLink?
bookings Booking[]
availability Availability[]
webhooks Webhook[]
destinationCalendar DestinationCalendar?
eventName String?
customInputs EventTypeCustomInput[]
timeZone String?
periodType PeriodType @default(UNLIMITED)
periodStartDate DateTime?
periodEndDate DateTime?
periodDays Int?
periodCountCalendarDays Boolean?
requiresConfirmation Boolean @default(false)
/// @zod.custom(imports. recurringEventType)
recurringEvent Json?
disableGuests Boolean @default(false)
hideCalendarNotes Boolean @default(false)
minimumBookingNotice Int @default(120)
minimumBookingNoticeType String @default("mins")
beforeEventBuffer Int @default(0)
afterEventBuffer Int @default(0)
seatsPerTimeSlot Int?
seatsShowAttendees Boolean?
schedulingType SchedulingType?
schedule Schedule? @relation(fields: [scheduleId], references: [id])
scheduleId Int?
// price is deprecated. It has now moved to metadata.apps.stripe.price. Plan to drop this column.
price Int @default(0)
// currency is deprecate d. It has now moved to metadata.apps.stripe.currency. Plan to drop this column.
currency String @default("usd")
slotInterval Int?
/// @zod.custom(imports. EventTypeMetaDataSchema)
metadata Json?
/// @zod.custom(imports. successRedirectUrl)
successRedirectUrl String?
workflows WorkflowsOnEventTypes[]
/// @zod.custom(imports. bookingLimitsType)
bookingLimits Json?
@@unique([userId, slug])
@@unique([teamId, slug])

View File

@ -453,6 +453,9 @@ export function InputGroupBox(props: JSX.IntrinsicElements["div"]) {
);
}
export const MinutesField = forwardRef<HTMLInputElement, InputFieldProps>(function MinutesField(props, ref) {
return <InputField ref={ref} type="number" min={0} {...props} addOnSuffix="mins" />;
export const DurationField = forwardRef<HTMLInputElement, InputFieldProps>(function DurationField(
props,
ref
) {
return <InputField ref={ref} type="number" min={0} {...props} />;
});