feat: added validation to limit event duration to 1440 minutes (24 ho… (#21379)

* feat: added validation to limit event duration to 1440 minutes (24 hours)

* Update English locale strings in common.json

* feat: introduce minimum event duration constant and update validations and fixed some suggested changes

* fix: remove static error message for maximum event duration validation

* fix: update minimum event duration to 1 minute and adjust validations accordingly

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: amrit <iamamrit27@gmail.com>
This commit is contained in:
authored and GitHub committed 2025-06-12 17:09:21 +00:00
1 parent 5a1e1e231b
commit 9f655ed819
6 files changed
+45 -8

No files matched your search

+6 -2
View File
@@ -1,6 +1,10 @@
import { z } from "zod";
import { MAX_SEATS_PER_TIME_SLOT } from "@calcom/lib/constants";
import {
MAX_SEATS_PER_TIME_SLOT,
MAX_EVENT_DURATION_MINUTES,
MIN_EVENT_DURATION_MINUTES,
} from "@calcom/lib/constants";
import slugify from "@calcom/lib/slugify";
import { _EventTypeModel as EventType, _HostModel } from "@calcom/prisma/zod";
import { customInputSchema, eventTypeBookingFields } from "@calcom/prisma/zod-utils";
@@ -80,7 +84,7 @@ const schemaEventTypeCreateParams = z
title: z.string(),
slug: z.string().transform((s) => slugify(s)),
description: z.string().optional().nullable(),
length: z.number().int(),
length: z.number().int().min(MIN_EVENT_DURATION_MINUTES).max(MAX_EVENT_DURATION_MINUTES),
metadata: z.any().optional(),
recurringEvent: recurringEventInputSchema.optional(),
seatsPerTimeSlot: z.number().optional(),
@@ -3241,5 +3241,7 @@
"meeting_start_time": "Meeting Start Time",
"members_affected_by_disabling_delegation_credential": "Affected members",
"no_members_affected_by_disabling_delegation_credential": "No members affected by disabling delegation credential",
"duration_min_error": "Duration must be at least {{min}} minute(s)",
"duration_max_error": "Duration cannot exceed {{max}} minutes (24 hours)",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
@@ -3,6 +3,7 @@ import { useState } from "react";
import type { UseFormReturn } from "react-hook-form";
import { useIsPlatform } from "@calcom/atoms/hooks/useIsPlatform";
import { MAX_EVENT_DURATION_MINUTES, MIN_EVENT_DURATION_MINUTES } from "@calcom/lib/constants";
import type { CreateEventTypeFormValues } from "@calcom/lib/hooks/useCreateEventType";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { md } from "@calcom/lib/markdownIt";
@@ -124,11 +125,22 @@ export default function CreateEventTypeForm({
<TextField
type="number"
required
min="10"
min={MIN_EVENT_DURATION_MINUTES}
max={MAX_EVENT_DURATION_MINUTES}
placeholder="15"
label={t("duration")}
className="pr-4"
{...register("length", { valueAsNumber: true })}
{...register("length", {
valueAsNumber: true,
min: {
value: MIN_EVENT_DURATION_MINUTES,
message: t("duration_min_error", { min: MIN_EVENT_DURATION_MINUTES }),
},
max: {
value: MAX_EVENT_DURATION_MINUTES,
message: t("duration_max_error", { max: MAX_EVENT_DURATION_MINUTES }),
},
})}
addOnSuffix={t("minutes")}
/>
</div>
@@ -14,6 +14,7 @@ import type {
SettingsToggleClassNames,
} from "@calcom/features/eventtypes/lib/types";
import type { FormValues, LocationFormValues } from "@calcom/features/eventtypes/lib/types";
import { MAX_EVENT_DURATION_MINUTES, MIN_EVENT_DURATION_MINUTES } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { md } from "@calcom/lib/markdownIt";
import { slugify } from "@calcom/lib/slugify";
@@ -337,9 +338,20 @@ export const EventSetupTab = (
{...(isManagedEventType || isChildrenManagedEventType ? lengthLockedProps : {})}
label={t("duration")}
defaultValue={formMethods.getValues("length") ?? 15}
{...formMethods.register("length")}
{...formMethods.register("length", {
valueAsNumber: true,
min: {
value: MIN_EVENT_DURATION_MINUTES,
message: t("duration_min_error", { min: MIN_EVENT_DURATION_MINUTES }),
},
max: {
value: MAX_EVENT_DURATION_MINUTES,
message: t("duration_max_error", { max: MAX_EVENT_DURATION_MINUTES }),
},
})}
addOnSuffix={<>{t("minutes")}</>}
min={1}
min={MIN_EVENT_DURATION_MINUTES}
max={MAX_EVENT_DURATION_MINUTES}
/>
)}
{!lengthLockedProps.disabled && (
+6
View File
@@ -61,6 +61,12 @@ export const EMBED_LIB_URL = process.env.NEXT_PUBLIC_EMBED_LIB_URL || `${WEBAPP_
export const TRIAL_LIMIT_DAYS = 14;
export const MAX_SEATS_PER_TIME_SLOT = 1000;
/** Maximum duration allowed for an event in minutes (24 hours) */
export const MAX_EVENT_DURATION_MINUTES = 1440;
/** Minimum duration allowed for an event in minutes */
export const MIN_EVENT_DURATION_MINUTES = 1;
export const HOSTED_CAL_FEATURES = process.env.NEXT_PUBLIC_HOSTED_CAL_FEATURES || !IS_SELF_HOSTED;
export const PUBLIC_QUERY_RESERVATION_INTERVAL_SECONDS =
+3 -2
View File
@@ -1,6 +1,7 @@
import { SchedulingType } from "@calcom/prisma/enums";
import { z } from "zod";
import * as imports from "../../zod-utils";
import { MIN_EVENT_DURATION_MINUTES, MAX_EVENT_DURATION_MINUTES } from "@calcom/lib/constants";
// TODO: figure out why EventTypeModel is being called even if it's not imported here, causing a circular dependency
// import { _EventTypeModel } from "../eventtype";
@@ -8,7 +9,7 @@ export const createEventTypeInput = z.object({
title: z.string().min(1),
slug: imports.eventTypeSlug,
description: z.string().nullish(),
length: z.number().int(),
length: z.number().int().min(MIN_EVENT_DURATION_MINUTES).max(MAX_EVENT_DURATION_MINUTES),
hidden: z.boolean(),
teamId: z.number().int().nullish(),
schedulingType: z.nativeEnum(SchedulingType).nullish(),
@@ -32,7 +33,7 @@ export const createEventTypeInput = z.object({
slug: z.string(),
title: z.string().min(1),
description: z.string(),
length: z.number(),
length: z.number().int().min(MIN_EVENT_DURATION_MINUTES).max(MAX_EVENT_DURATION_MINUTES),
teamId: z.number().nullish(),
}).strict();