feat: link advanced event type settings to docs (#24629)

* feat: link advanced event type settings to docs

* Limits and Assignment tab settings

* remove testing code

* add noopener noreferrer rel to links

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
This commit is contained in:
Dhairyashil Shinde
2025-10-31 15:47:11 +05:30
committed by GitHub
co-authored by Udit Takkar
parent 6beb279a27
commit 9d1cf3e70e
9 changed files with 169 additions and 33 deletions
+17 -17
View File
@@ -367,8 +367,8 @@
"available_apps_lower_case": "Available apps",
"available_apps_desc": "View popular apps below and explore more in our <0>App Store</0>",
"fixed_host_helper": "Add anyone who needs to attend the event. <0>Learn more</0>",
"round_robin_groups_helper": "People in a group take turns, one person of each group will show up for the event.",
"round_robin_helper": "People in the group take turns and only one person will show up for the event.",
"round_robin_groups_helper": "People in a group take turns, one person of each group will show up for the event. <0>Learn more</0>",
"round_robin_helper": "People in the group take turns and only one person will show up for the event. <0>Learn more</0>",
"check_email_reset_password": "Check your email. We sent you a link to reset your password.",
"finish": "Finish",
"organization_general_description": "Manage settings for your team language and timezone",
@@ -1056,11 +1056,11 @@
"edit": "Edit",
"add_input": "Add an Input",
"disable_notes": "Hide notes in calendar",
"disable_notes_description": "For privacy reasons, additional inputs and notes will be hidden in the calendar entry. They will still be sent to your email.",
"requires_confirmation_description": "The booking needs to be manually confirmed before it is pushed to your calendar and a confirmation is sent.",
"disable_notes_description": "For privacy reasons, additional inputs and notes will be hidden in the calendar entry. They will still be sent to your email. <0>Learn more</0>",
"requires_confirmation_description": "The booking needs to be manually confirmed before it is pushed to your calendar and a confirmation is sent. <0>Learn more</0>",
"requires_confirmation_will_block_slot_description": "Unconfirmed bookings still block calendar slots.",
"recurring_event": "Recurring Event",
"recurring_event_description": "People can subscribe for recurring events",
"recurring_event_description": "People can subscribe for recurring events. <0>Learn more</0>",
"connect_and_join": "Connect and Join",
"cannot_be_used_with_paid_event_types": "It cannot be used with paid event types",
"warning_payment_instant_meeting_event": "Instant Meetings are not supported with recurring events and payment apps yet",
@@ -1076,7 +1076,7 @@
"copy_private_link_to_event": "Copy private link to event",
"private_link_description": "Generate a private URL to share without exposing your {{appName}} username",
"multiple_private_links_title": "Private Links",
"multiple_private_links_description": "Generate private URLs without exposing the username, with configurable expiry and usage limits",
"multiple_private_links_description": "Generate private URLs without exposing the username, with configurable expiry and usage limits. <0>Learn more</0>",
"add_a_multiple_private_link": "Add new link",
"multiple_private_link_copied": "Private link copied",
"invitees_can_schedule": "Invitees can schedule",
@@ -1280,7 +1280,7 @@
"redirect_url_description": "Redirect to a custom URL after a successful booking",
"duplicate": "Duplicate",
"offer_seats": "Offer seats",
"offer_seats_description": "Offer seats for booking. This automatically disables guest & opt-in bookings.",
"offer_seats_description": "Offer seats for booking. This automatically disables guest & opt-in bookings. <0>Learn more</0>",
"seats_available_one": "Seat available",
"seats_available_other": "Seats available",
"seats_nearly_full": "Seats almost full",
@@ -1315,11 +1315,11 @@
"enabled_after_update_description": "The private link will work after saving",
"confirm_delete_api_key": "Revoke this API key",
"disable_rescheduling": "Disable Rescheduling",
"description_disable_rescheduling": "Guests can no longer reschedule the event with calendar invite or email",
"description_disable_rescheduling": "Guests can no longer reschedule the event with calendar invite or email. <0>Learn more</0>",
"allow_rescheduling_cancelled_bookings": "Allow booking through reschedule link",
"description_allow_rescheduling_cancelled_bookings": "When enabled, users will be able to create a new booking when trying to reschedule a cancelled booking",
"disable_cancelling": "Disable Cancelling",
"description_disable_cancelling": "Guests can no longer cancel the event with calendar invite or email",
"description_disable_cancelling": "Guests can no longer cancel the event with calendar invite or email. <0>Learn more</0>",
"revoke_api_key": "Revoke API key",
"api_key_copied": "API key copied!",
"api_key_expires_on": "The API key will expire on",
@@ -1901,13 +1901,13 @@
"every_app_published": "Every app published on the {{appName}} App Store is open source and thoroughly tested via peer reviews. Nevertheless, {{companyName}} does not endorse or certify these apps unless they are published by {{appName}}. If you encounter inappropriate content or behaviour please report it.",
"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_frequency_description": "Limit how many times this event can be booked. <0>Learn more</0>",
"only_show_first_available_slot": "Only show the first slot of each day as available",
"only_show_first_available_slot_description": "This will limit your availability for this event type to one slot per day, scheduled at the earliest available time.",
"limit_total_booking_duration": "Limit total booking duration",
"limit_total_booking_duration_description": "Limit total amount of time that this event can be booked",
"booker_upcoming_limit": "Limit number of upcoming bookings per booker",
"booker_booking_limit_description": "Limit the number of active bookings a booker can make for this event type",
"booker_booking_limit_description": "Limit the number of active bookings a booker can make for this event type. <0>Learn more</0>",
"recurring_event_doesnt_support_booker_booking_limit": "Recurring events don't support booker booking limit",
"add_limit": "Add Limit",
"team_name_required": "Team name required",
@@ -1975,7 +1975,7 @@
"saml_sp_entity_id_copied": "SP Entity ID copied!",
"add_calendar": "Add Calendar",
"limit_future_bookings": "Limit future bookings",
"limit_future_bookings_description": "Limit how far in the future this event can be booked",
"limit_future_bookings_description": "Limit how far in the future this event can be booked. <0>Learn more</0>",
"no_event_types": "No event types setup",
"no_event_types_description": "{{name}} has not setup any event types for you to book.",
"billing_frequency": "Billing Frequency",
@@ -2231,7 +2231,7 @@
"under_maintenance_description": "The {{appName}} team are performing scheduled maintenance. If you have any questions, please contact support.",
"event_type_seats": "{{numberOfSeats}} seats",
"booking_questions_title": "Booking questions",
"booking_questions_description": "Customize the questions asked on the booking page",
"booking_questions_description": "Customize the questions asked on the booking page. <0>Learn more</0>",
"add_a_booking_question": "Add a question",
"identifier": "Identifier",
"duplicate_email": "Email is duplicate",
@@ -2715,7 +2715,7 @@
"locked": "Locked",
"unlocked": "Unlocked",
"lock_timezone_toggle_on_booking_page": "Lock timezone on booking page",
"description_lock_timezone_toggle_on_booking_page": "To lock the timezone on booking page, useful for in-person events.",
"description_lock_timezone_toggle_on_booking_page": "To lock the timezone on booking page, useful for in-person events. <0>Learn more</0>",
"event_setup_multiple_payment_apps_error": "You can only have one payment app enabled per event type.",
"number_in_international_format": "Please enter number in international format.",
"install_calendar": "Install Calendar",
@@ -3232,7 +3232,7 @@
"routed": "Routed",
"reassigned": "Reassigned",
"allow_rescheduling_past_events": "Allow rescheduling past events",
"allow_rescheduling_past_events_description": "Enabling this option allows for past events to be rescheduled",
"allow_rescheduling_past_events_description": "Enabling this option allows for past events to be rescheduled. <0>Learn more</0>",
"rerouted": "Rerouted",
"salesforce_assigned": "Salesforce assignment",
"router_position": "Router Position",
@@ -3459,7 +3459,7 @@
"hide_organizer_email": "Hide organizer's email",
"platform_customer_cant_create_organization": "You are already part of a platform organization which is why you can't create a new organization. Each user can only belong to one organization. Please, create a new cal.com account with a different email and use that account to subscribe to the organizations plan.",
"organization_customer_cant_create_platform": "You are already part of an organization which is why you can't create a platform organization. Each user can only belong to one organization. Please, create a new cal.com account with a different email and use that account to subscribe to the platform plan.",
"hide_organizer_email_description": "Hide organizer's email address from the booking screen, email notifications, and calendar events",
"hide_organizer_email_description": "Hide organizer's email address from the booking screen, email notifications, and calendar events. <0>Learn more</0>",
"you_and_conjunction": "You &",
"select_verified_email": "Select a verified email",
"add_verified_email": "Add verified email",
@@ -3694,7 +3694,7 @@
"license_key_saved": "License key saved successfully",
"timezone_mismatch_tooltip": "You are viewing the report based on your profile timezone ({{userTimezone}}), while your browser is set to timezone ({{browserTimezone}})",
"show_optimized_slots": "Optimized slots",
"show_optimized_slots_description": "Arrange time slots to optimize availability.",
"show_optimized_slots_description": "Arrange time slots to optimize availability. <0>Learn more</0>",
"failed_bookings_by_field": "Failed Bookings By Field",
"failed_bookings": "Failed bookings",
"event_type_no_hosts": "No hosts are assigned to event type",
@@ -0,0 +1,37 @@
import type { TFunction } from "i18next";
import Link from "next/link";
import ServerTrans from "@calcom/lib/components/ServerTrans";
import { IS_CALCOM } from "@calcom/lib/constants";
type LearnMoreLinkProps = {
t: TFunction;
i18nKey: string;
href: string;
};
export const LearnMoreLink = ({ t, i18nKey, href }: LearnMoreLinkProps) => {
if (!IS_CALCOM) {
const text = t(i18nKey)
.replace(/<0>[\s\S]*?<\/0>/g, "")
.trim();
return <>{text}</>;
}
return (
<ServerTrans
t={t}
i18nKey={i18nKey}
components={[
<Link
key={i18nKey}
className="underline underline-offset-2"
target="_blank"
rel="noopener noreferrer"
href={href}>
Learn more
</Link>,
]}
/>
);
};
@@ -3,5 +3,6 @@ import dynamic from "next/dynamic";
export { default as CheckedTeamSelect } from "./CheckedTeamSelect";
export { CreateEventTypeDialog } from "./CreateEventTypeDialog";
export { default as EventTypeDescription } from "./EventTypeDescription";
export { LearnMoreLink } from "./LearnMoreLink";
export { MultiplePrivateLinksController } from "./MultiplePrivateLinksController";
export const EventTypeDescriptionLazy = dynamic(() => import("./EventTypeDescription"));
@@ -21,6 +21,7 @@ import {
allowDisablingHostConfirmationEmails,
} from "@calcom/features/ee/workflows/lib/allowDisablingStandardEmails";
import { MultiplePrivateLinksController } from "@calcom/features/eventtypes/components";
import { LearnMoreLink } from "@calcom/features/eventtypes/components/LearnMoreLink";
import type { EventNameObjectType } from "@calcom/features/eventtypes/lib/eventNaming";
import { getEventName } from "@calcom/features/eventtypes/lib/eventNaming";
import type {
@@ -638,7 +639,11 @@ export const EventAdvancedTab = ({
{t("booking_questions_title")}
</div>
<p className="text-subtle mt-1 max-w-[280px] break-words text-sm sm:max-w-[500px]">
{t("booking_questions_description")}
<LearnMoreLink
t={t}
i18nKey="booking_questions_description"
href="https://cal.com/help/event-types/booking-questions"
/>
</p>
</div>
<div className="border-subtle bg-default rounded-lg border p-5">
@@ -689,7 +694,13 @@ export const EventAdvancedTab = ({
title={t("disable_cancelling")}
data-testid="disable-cancelling-toggle"
{...disableCancellingLocked}
description={t("description_disable_cancelling")}
description={
<LearnMoreLink
t={t}
i18nKey="description_disable_cancelling"
href="https://cal.com/help/event-types/disable-canceling-rescheduling#disable-cancelling"
/>
}
checked={disableCancelling}
onCheckedChange={(val) => {
setDisableCancelling(val);
@@ -709,7 +720,13 @@ export const EventAdvancedTab = ({
title={t("disable_rescheduling")}
data-testid="disable-rescheduling-toggle"
{...disableReschedulingLocked}
description={t("description_disable_rescheduling")}
description={
<LearnMoreLink
t={t}
i18nKey="description_disable_rescheduling"
href="https://cal.com/help/event-types/disable-canceling-rescheduling#disable-rescheduling"
/>
}
checked={disableRescheduling}
onCheckedChange={(val) => {
setDisableRescheduling(val);
@@ -841,7 +858,13 @@ export const EventAdvancedTab = ({
data-testid="disable-notes"
title={t("disable_notes")}
{...hideCalendarNotesLocked}
description={t("disable_notes_description")}
description={
<LearnMoreLink
t={t}
i18nKey="disable_notes_description"
href="https://cal.com/help/event-types/hide-notes"
/>
}
checked={value}
onCheckedChange={(e) => onChange(e)}
/>
@@ -958,7 +981,13 @@ export const EventAdvancedTab = ({
data-testid="multiplePrivateLinksCheck"
title={t("multiple_private_links_title")}
{...multiplePrivateLinksLocked}
description={t("multiple_private_links_description", { appName: APP_NAME })}
description={
<LearnMoreLink
t={t}
i18nKey="multiple_private_links_description"
href="https://cal.com/help/event-types/private-links"
/>
}
tooltip={isManagedEventType ? t("managed_event_field_parent_control_disabled") : ""}
checked={multiplePrivateLinksVisible}
onCheckedChange={(e) => {
@@ -1005,7 +1034,13 @@ export const EventAdvancedTab = ({
data-testid="offer-seats-toggle"
title={t("offer_seats")}
{...seatsLocked}
description={t("offer_seats_description")}
description={
<LearnMoreLink
t={t}
i18nKey="offer_seats_description"
href="https://cal.com/help/event-types/offer-seats"
/>
}
checked={value}
disabled={noShowFeeEnabled || multiLocation || (!seatsEnabled && isRecurringEvent)}
tooltip={
@@ -1131,7 +1166,13 @@ export const EventAdvancedTab = ({
)}
title={t("hide_organizer_email")}
{...hideOrganizerEmailLocked}
description={t("hide_organizer_email_description")}
description={
<LearnMoreLink
t={t}
i18nKey="hide_organizer_email_description"
href="https://cal.com/help/event-types/hideorganizersemail#hide-organizers-email"
/>
}
descriptionClassName={customClassNames?.hideOrganizerEmail?.description}
checked={value}
onCheckedChange={(e) => onChange(e)}
@@ -1161,7 +1202,13 @@ export const EventAdvancedTab = ({
)}
title={t("lock_timezone_toggle_on_booking_page")}
{...lockTimeZoneToggleOnBookingPageLocked}
description={t("description_lock_timezone_toggle_on_booking_page")}
description={
<LearnMoreLink
t={t}
i18nKey="description_lock_timezone_toggle_on_booking_page"
href="https://cal.com/help/event-types/timezone-lock"
/>
}
checked={value}
onCheckedChange={(e) => {
onChange(e);
@@ -1208,7 +1255,13 @@ export const EventAdvancedTab = ({
switchContainerClassName={classNames("border-subtle rounded-lg border py-6 px-4 sm:px-6")}
title={t("allow_rescheduling_past_events")}
{...reschedulingPastBookingsLocked}
description={t("allow_rescheduling_past_events_description")}
description={
<LearnMoreLink
t={t}
i18nKey="allow_rescheduling_past_events_description"
href="https://cal.com/help/event-types/allow-rescheduling"
/>
}
checked={value}
onCheckedChange={(e) => onChange(e)}
/>
@@ -1376,7 +1429,13 @@ export const EventAdvancedTab = ({
toggleSwitchAtTheEnd={true}
labelClassName="text-sm"
title={t("show_optimized_slots")}
description={t("show_optimized_slots_description")}
description={
<LearnMoreLink
t={t}
i18nKey="show_optimized_slots_description"
href="https://cal.com/help/event-types/optimized-slots#optimized-slots"
/>
}
checked={isChecked}
{...showOptimizedSlotsLocked}
onCheckedChange={(active) => {
@@ -6,6 +6,7 @@ import { Controller, useFormContext } from "react-hook-form";
import type z from "zod";
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
import { LearnMoreLink } from "@calcom/features/eventtypes/components/LearnMoreLink";
import type { EventTypeSetup, SettingsToggleClassNames } from "@calcom/features/eventtypes/lib/types";
import type { FormValues } from "@calcom/features/eventtypes/lib/types";
import ServerTrans from "@calcom/lib/components/ServerTrans";
@@ -99,7 +100,13 @@ export default function RequiresConfirmationController({
data-testid="requires-confirmation"
disabled={seatsEnabled || requiresConfirmationLockedProps.disabled}
tooltip={seatsEnabled ? t("seat_options_doesnt_support_confirmation") : undefined}
description={t("requires_confirmation_description")}
description={
<LearnMoreLink
t={t}
i18nKey="requires_confirmation_description"
href="https://cal.com/help/event-types/how-to-requires"
/>
}
checked={requiresConfirmation}
LockedIcon={requiresConfirmationLockedProps.LockedIcon}
onCheckedChange={(val) => {
@@ -14,6 +14,7 @@ import AssignAllTeamMembers from "@calcom/features/eventtypes/components/AssignA
import type { ChildrenEventTypeSelectCustomClassNames } from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect";
import ChildrenEventTypeSelect from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect";
import { sortHosts } from "@calcom/features/eventtypes/components/HostEditDialogs";
import { LearnMoreLink } from "@calcom/features/eventtypes/components/LearnMoreLink";
import type {
FormValues,
TeamMember,
@@ -477,7 +478,11 @@ const RoundRobinHosts = ({
"text-subtle max-w-full break-words text-sm leading-tight",
customClassNames?.description
)}>
{hostGroups?.length > 0 ? t("round_robin_groups_helper") : t("round_robin_helper")}
<LearnMoreLink
t={t}
i18nKey={hostGroups?.length > 0 ? "round_robin_groups_helper" : "round_robin_helper"}
href="https://cal.com/help/event-types/round-robin"
/>
</p>
</div>
<Button color="secondary" size="sm" StartIcon="plus" onClick={handleAddGroup}>
@@ -7,6 +7,7 @@ import { Controller, useFormContext } from "react-hook-form";
import type { SingleValue } from "react-select";
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
import { LearnMoreLink } from "@calcom/features/eventtypes/components/LearnMoreLink";
import { getDefinedBufferTimes } from "@calcom/features/eventtypes/lib/getDefinedBufferTimes";
import type { FormValues, EventTypeSetupProps, InputClassNames } from "@calcom/features/eventtypes/lib/types";
import type { SelectClassNames, SettingsToggleClassNames } from "@calcom/features/eventtypes/lib/types";
@@ -594,7 +595,13 @@ export const EventLimitsTab = ({ eventType, customClassNames }: EventLimitsTabPr
labelClassName={classNames("text-sm", customClassNames?.bookingFrequencyLimit?.label)}
title={t("limit_booking_frequency")}
{...bookingLimitsLocked}
description={t("limit_booking_frequency_description")}
description={
<LearnMoreLink
t={t}
i18nKey="limit_booking_frequency_description"
href="https://cal.com/help/event-types/booking-frequency"
/>
}
checked={isChecked}
onCheckedChange={(active) => {
if (active) {
@@ -725,7 +732,13 @@ export const EventLimitsTab = ({ eventType, customClassNames }: EventLimitsTabPr
childrenClassName={classNames("lg:ml-0", customClassNames?.futureBookingLimit?.children)}
descriptionClassName={customClassNames?.futureBookingLimit?.description}
title={t("limit_future_bookings")}
description={t("limit_future_bookings_description")}
description={
<LearnMoreLink
t={t}
i18nKey="limit_future_bookings_description"
href="https://cal.com/help/event-types/limit-future-bookings"
/>
}
{...periodTypeLocked}
checked={isChecked}
onCheckedChange={(isEnabled) => {
@@ -1,6 +1,7 @@
import { useState } from "react";
import { Controller, useFormContext } from "react-hook-form";
import { LearnMoreLink } from "@calcom/features/eventtypes/components/LearnMoreLink";
import type { FormValues } from "@calcom/features/eventtypes/lib/types";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import classNames from "@calcom/ui/classNames";
@@ -48,7 +49,13 @@ export default function MaxActiveBookingsPerBookerController({
)}
childrenClassName={classNames("lg:ml-0")}
title={t("booker_upcoming_limit")}
description={t("booker_booking_limit_description")}
description={
<LearnMoreLink
t={t}
i18nKey="booker_booking_limit_description"
href="https://cal.com/help/event-types/booker-active-booking-limit"
/>
}
checked={isChecked}
onCheckedChange={(active) => {
if (active) {
@@ -2,6 +2,7 @@ import { useState } from "react";
import { useFormContext } from "react-hook-form";
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
import { LearnMoreLink } from "@calcom/features/eventtypes/components/LearnMoreLink";
import type {
EventTypeSetup,
InputClassNames,
@@ -91,7 +92,13 @@ export default function RecurringEventController({
descriptionClassName={customClassNames?.recurringToggle?.description}
title={t("recurring_event")}
{...recurringLocked}
description={t("recurring_event_description")}
description={
<LearnMoreLink
t={t}
i18nKey="recurring_event_description"
href="https://cal.com/help/event-types/recurring-events"
/>
}
checked={!!recurringEventState}
data-testid="recurring-event-check"
disabled={(!recurringEventState && isSeatsOffered) || hasBookingLimitPerBooker}