minimum booking notice allows hours and days
This commit is contained in:
parent
9f1341e94e
commit
27a31d70e2
|
@ -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">
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "EventType" ADD COLUMN "minimumBookingNoticeType" TEXT NOT NULL DEFAULT 'mins';
|
|
@ -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])
|
||||
|
|
|
@ -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} />;
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user