From 9d1cf3e70eff54d17a50ebe4784b98b50cccf62b Mon Sep 17 00:00:00 2001 From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com> Date: Fri, 31 Oct 2025 15:47:11 +0530 Subject: [PATCH] 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> --- apps/web/public/static/locales/en/common.json | 34 ++++---- .../eventtypes/components/LearnMoreLink.tsx | 37 +++++++++ .../features/eventtypes/components/index.ts | 1 + .../tabs/advanced/EventAdvancedTab.tsx | 79 ++++++++++++++++--- .../RequiresConfirmationController.tsx | 9 ++- .../assignment/EventTeamAssignmentTab.tsx | 7 +- .../components/tabs/limits/EventLimitsTab.tsx | 17 +++- .../MaxActiveBookingsPerBookerController.tsx | 9 ++- .../recurring/RecurringEventController.tsx | 9 ++- 9 files changed, 169 insertions(+), 33 deletions(-) create mode 100644 packages/features/eventtypes/components/LearnMoreLink.tsx diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 69933eb439..597fdceb0a 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -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", "fixed_host_helper": "Add anyone who needs to attend the event. <0>Learn more", - "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", + "round_robin_helper": "People in the group take turns and only one person will show up for the event. <0>Learn more", "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", + "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", "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", "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", "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", "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", "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", "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", "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", "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", "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", "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", "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", "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", "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", "failed_bookings_by_field": "Failed Bookings By Field", "failed_bookings": "Failed bookings", "event_type_no_hosts": "No hosts are assigned to event type", diff --git a/packages/features/eventtypes/components/LearnMoreLink.tsx b/packages/features/eventtypes/components/LearnMoreLink.tsx new file mode 100644 index 0000000000..12547a49ce --- /dev/null +++ b/packages/features/eventtypes/components/LearnMoreLink.tsx @@ -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 ( + + Learn more + , + ]} + /> + ); +}; diff --git a/packages/features/eventtypes/components/index.ts b/packages/features/eventtypes/components/index.ts index 6b4a013ec3..b777134e83 100644 --- a/packages/features/eventtypes/components/index.ts +++ b/packages/features/eventtypes/components/index.ts @@ -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")); diff --git a/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx b/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx index 97297122e7..292ca66979 100644 --- a/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx +++ b/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx @@ -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")}

- {t("booking_questions_description")} +

@@ -689,7 +694,13 @@ export const EventAdvancedTab = ({ title={t("disable_cancelling")} data-testid="disable-cancelling-toggle" {...disableCancellingLocked} - description={t("description_disable_cancelling")} + description={ + + } 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={ + + } 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={ + + } 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={ + + } 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={ + + } 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={ + + } 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={ + + } 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={ + + } 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={ + + } checked={isChecked} {...showOptimizedSlotsLocked} onCheckedChange={(active) => { diff --git a/packages/features/eventtypes/components/tabs/advanced/RequiresConfirmationController.tsx b/packages/features/eventtypes/components/tabs/advanced/RequiresConfirmationController.tsx index 444f3f1539..ac0bf0b205 100644 --- a/packages/features/eventtypes/components/tabs/advanced/RequiresConfirmationController.tsx +++ b/packages/features/eventtypes/components/tabs/advanced/RequiresConfirmationController.tsx @@ -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={ + + } checked={requiresConfirmation} LockedIcon={requiresConfirmationLockedProps.LockedIcon} onCheckedChange={(val) => { diff --git a/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx b/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx index 8132295efa..b0296fb919 100644 --- a/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx +++ b/packages/features/eventtypes/components/tabs/assignment/EventTeamAssignmentTab.tsx @@ -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")} + 0 ? "round_robin_groups_helper" : "round_robin_helper"} + href="https://cal.com/help/event-types/round-robin" + />