chore: some minor QA fixes (#22727)
Post release / release (push) Canceled after 0s

* Various fixes

* Remove tooltip

* another string change

* Fix width of custom event name modal to prevent overflow

* Booking questions fixes

* minor string fix

* checkbox alignment

* padding in reassign dialog

* fix: update FormBuilder tests for checkbox UI changes

- Updated test utilities to work with CheckboxField instead of BooleanToggleGroupField
- Fixed badge expectations to check for 'optional' instead of 'required'
- Updated dialog interaction methods to use checkbox.checked instead of button text
- All 13 FormBuilder tests now pass successfully

Fixes failing tests in PR #22727 caused by UI changes from toggle buttons to checkboxes for required field selection.

Co-Authored-By: amit@cal.com <samit91848@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: amit@cal.com <samit91848@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
This commit is contained in:
Bailey Pumfleet
2025-08-25 18:11:18 +09:00
committed by GitHub
co-authored by amit@cal.com Devin AI Alex van Andel
parent 9b7c6585d8
commit 5bab2af500
66 changed files with 232 additions and 221 deletions
+4 -1
View File
@@ -2,6 +2,7 @@
import { TrpcProvider } from "app/_trpc/trpc-provider";
import { SessionProvider } from "next-auth/react";
import { usePathname } from "next/navigation";
import CacheProvider from "react-inlinesvg/provider";
import { WebPushProvider } from "@calcom/features/notifications/WebPushContext";
@@ -17,11 +18,13 @@ type ProvidersProps = {
};
export function Providers({ isEmbed, children, nonce }: ProvidersProps) {
const isBookingPage = useIsBookingPage();
const pathname = usePathname();
const isOnboardingPage = pathname?.startsWith("/getting-started");
return (
<SessionProvider>
<TrpcProvider>
{!isBookingPage ? <PlainChat nonce={nonce} /> : null}
{!isBookingPage && !isOnboardingPage ? <PlainChat nonce={nonce} /> : null}
{!isEmbed && !isBookingPage && <NotificationSoundHandler />}
{/* @ts-expect-error FIXME remove this comment when upgrading typescript to v5 */}
<CacheProvider>
@@ -218,7 +218,7 @@ export const ReassignDialog = ({
placeholder={t("search")}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<div className="scroll-bar flex h-[150px] flex-col gap-0.5 overflow-y-scroll rounded-md border p-1">
<div className="scroll-bar mt-2 flex h-[150px] flex-col gap-0.5 overflow-y-scroll rounded-md border p-1">
{teamMemberOptions.map((member) => (
<label
key={member.value}
@@ -84,6 +84,7 @@ const AppConnectionItem = (props: IAppConnectionItem) => {
{t("this_app_requires_connected_account", {
appName: title,
dependencyName: dependency.name,
interpolation: { escapeValue: false },
})}
</span>
@@ -92,7 +92,7 @@ const ConnectedCalendars = (props: IConnectCalendarsProps) => {
loading={isPageLoading}
onClick={() => nextStep()}
disabled={disabledNextButton}>
{firstCalendar ? `${t("continue")}` : `${t("next_step_text")}`}
{firstCalendar ? `${t("connect_your_video")}` : `${t("connect_calendar_first")}`}
</Button>
</>
);
@@ -105,7 +105,7 @@ const ConnectedVideoStep = (props: ConnectedAppStepProps) => {
disabled={!hasAnyInstalledVideoApps}
loading={isPageLoading}
onClick={() => nextStep()}>
{t("next_step_text")}
{t("set_availability")}
</Button>
</>
);
@@ -81,7 +81,7 @@ const SetupAvailability = (props: ISetupAvailabilityProps) => {
className="mt-2 w-full justify-center p-2 text-sm sm:mt-8"
loading={availabilityForm.formState.isSubmitting}
disabled={availabilityForm.formState.isSubmitting}>
{t("next_step_text")}
{t("complete_profile")}
</Button>
</div>
</Form>
@@ -164,7 +164,7 @@ const UserProfile = ({ user }: UserProfileProps) => {
EndIcon="arrow-right"
type="submit"
className="mt-8 w-full items-center justify-center">
{t("finish")}
{t("finish_and_start")}
</Button>
</form>
);
@@ -88,6 +88,7 @@ const UserSettings = (props: IUserSettingsProps) => {
id="name"
name="name"
type="text"
placeholder="John Doe"
autoComplete="off"
autoCorrect="off"
/>
@@ -121,7 +122,7 @@ const UserSettings = (props: IUserSettingsProps) => {
className="mt-8 flex w-full flex-row justify-center"
loading={mutation.isPending}
disabled={mutation.isPending}>
{t("next_step_text")}
{t("connect_your_calendar")}
</Button>
</form>
);
@@ -120,6 +120,7 @@ const UsernameTextfield = (props: ICustomUsernameProps & Partial<React.Component
<TextField
ref={usernameRef}
name="username"
placeholder="john"
value={inputUsernameValue}
autoComplete="none"
autoCapitalize="none"
@@ -42,7 +42,7 @@ const getStepsAndHeadersForUser = (t: TFunction) => {
}[] = [
{
title: t("welcome_to_cal_header", { appName: APP_NAME }),
subtitle: [t("we_just_need_basic_info"), t("edit_form_later_subtitle")],
subtitle: [t("we_just_need_basic_info")],
},
{
title: t("connect_your_calendar"),
@@ -57,8 +57,9 @@ const getStepsAndHeadersForUser = (t: TFunction) => {
{
title: t("set_availability"),
subtitle: [
t("set_availability_getting_started_subtitle_1"),
t("set_availability_getting_started_subtitle_2"),
`${t("set_availability_getting_started_subtitle_1")} ${t(
"set_availability_getting_started_subtitle_2"
)}`,
],
},
{
@@ -109,10 +109,7 @@ test("multiple duration selection updates event length correctly", async ({ page
await page.waitForSelector('[data-testid="event-types"]');
await page.click(`text=Multiple duration`);
await page.waitForSelector('[data-testid="event-title"]');
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toHaveAttribute(
"aria-current",
"page"
);
await expect(page.getByTestId("vertical-tab-basics")).toHaveAttribute("aria-current", "page");
await page.getByTestId("vertical-tab-event_advanced_tab_title").click();
await page.fill('[name="eventName"]', "{Event duration} event btwn {Organiser} {Scheduler}");
await page.locator('[data-testid="update-eventtype"]').click();
+1 -4
View File
@@ -77,10 +77,7 @@ test.describe("Event Types tests", () => {
// fix the race condition
await page.waitForSelector('[data-testid="event-title"]');
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toHaveAttribute(
"aria-current",
"page"
);
await expect(page.getByTestId("vertical-tab-basics")).toHaveAttribute("aria-current", "page");
await page.click("[data-testid=vertical-tab-recurring]");
await expect(page.locator("[data-testid=recurring-event-collapsible]")).toBeHidden();
+1 -1
View File
@@ -123,7 +123,7 @@ export function createAppsFixture(page: Page) {
},
verifyAppsInfoNew: async (app: string, eventTypeId: number) => {
await page.goto(`event-types/${eventTypeId}?tabName=apps`);
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toContainText("Event Setup"); // fix the race condition
await expect(page.getByTestId("vertical-tab-basics")).toContainText("Basics"); // fix the race condition
await expect(page.locator(`[data-testid='${app}-app-switch'][data-state="checked"]`)).toBeVisible();
},
};
+1 -1
View File
@@ -69,7 +69,7 @@ test.describe("private links creation and usage", () => {
// Ensure that private URL is enabled after modifying the event type.
// Additionally, if the slug is changed, ensure that the private URL is updated accordingly.
await page.getByTestId("vertical-tab-event_setup_tab_title").click();
await page.getByTestId("vertical-tab-basics").click();
await page.locator("[data-testid=event-title]").first().fill("somethingrandom");
await page.locator("[data-testid=event-slug]").first().fill("somethingrandom");
await expect(page.locator('[data-testid="event-slug"]').first()).toHaveValue("somethingrandom");
+1 -4
View File
@@ -222,10 +222,7 @@ export const createNewSeatedEventType = async (page: Page, args: { eventTitle: s
const eventTitle = args.eventTitle;
await createNewUserEventType(page, { eventTitle });
await page.waitForSelector('[data-testid="event-title"]');
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toHaveAttribute(
"aria-current",
"page"
);
await expect(page.getByTestId("vertical-tab-basics")).toHaveAttribute("aria-current", "page");
await page.locator('[data-testid="vertical-tab-event_advanced_tab_title"]').click();
await page.locator('[data-testid="offer-seats-toggle"]').click();
await page.locator('[data-testid="update-eventtype"]').click();
@@ -70,10 +70,7 @@ test.describe("Manage Booking Questions", () => {
const firstEventTypeElement = $eventTypes.first();
await firstEventTypeElement.click();
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toHaveAttribute(
"aria-current",
"page"
);
await expect(page.getByTestId("vertical-tab-basics")).toHaveAttribute("aria-current", "page");
await page.getByTestId("vertical-tab-event_advanced_tab_title").click();
});
@@ -117,10 +114,7 @@ test.describe("Manage Booking Questions", () => {
const firstEventTypeElement = $eventTypes.first();
await firstEventTypeElement.click();
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toHaveAttribute(
"aria-current",
"page"
);
await expect(page.getByTestId("vertical-tab-basics")).toHaveAttribute("aria-current", "page");
});
await test.step("Open the 'Name' field dialog", async () => {
@@ -642,8 +636,8 @@ async function toggleQuestionRequireStatusAndSave({
await page.locator(`[data-testid="field-${name}"]`).locator('[data-testid="edit-field-action"]').click();
await page
.locator('[data-testid="edit-field-dialog"]')
.locator('[data-testid="field-required"] button')
.locator(`text=${required ? "Yes" : "No"}`)
.locator('[data-testid="field-required"]')
.first()
.click();
await page.locator('[data-testid="field-add-save"]').click();
await saveEventType(page);
@@ -754,11 +748,8 @@ test.describe("Text area min and max characters text", () => {
await page.waitForSelector('[data-testid="event-types"]');
await createNewUserEventType(page, { eventTitle });
await page.waitForSelector('[data-testid="event-title"]');
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toContainText("Event Setup"); //fix the race condition
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toHaveAttribute(
"aria-current",
"page"
);
await expect(page.getByTestId("vertical-tab-basics")).toContainText("Basics"); //fix the race condition
await expect(page.getByTestId("vertical-tab-basics")).toHaveAttribute("aria-current", "page");
await page.getByTestId("vertical-tab-event_advanced_tab_title").click();
const insertQuestion = async (questionName: string) => {
const element = page.locator('[data-testid="add-field"]');
@@ -79,11 +79,8 @@ test.describe("Managed Event Types", () => {
const { adminUser, managedEvent } = await setupManagedEvent({ users });
await adminUser.apiLogin();
await page.goto(`/event-types/${managedEvent.id}?tabName=setup`);
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toHaveAttribute(
"aria-current",
"page"
); // fix the race condition
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toContainText("Event Setup"); //fix the race condition
await expect(page.getByTestId("vertical-tab-basics")).toHaveAttribute("aria-current", "page"); // fix the race condition
await expect(page.getByTestId("vertical-tab-basics")).toContainText("Basics"); //fix the race condition
await page.locator("#location-select").click();
const optionText = await getByKey(page, "organizer_default_conferencing_app");
await expect(optionText).toBeVisible();
+1 -1
View File
@@ -21,7 +21,7 @@ test.describe("Onboarding", () => {
// tests whether the user makes it to /getting-started
// after login with completedOnboarding false
await page.waitForURL("/getting-started");
await expect(page.locator('text="Next Step"')).toBeVisible(); // Fix race condition
await expect(page.locator('text="Connect your calendar"')).toBeVisible(); // Fix race condition
await test.step("step 1 - User Settings", async () => {
// Check required fields
@@ -780,8 +780,8 @@ const markPhoneNumberAsRequiredAndEmailAsOptional = async (page: Page, eventId:
// Make email as not required
await page.locator('[data-testid="field-email"] [data-testid="edit-field-action"]').click();
const emailRequiredFiled = await page.locator('[data-testid="field-required"]');
await emailRequiredFiled.locator("> :nth-child(2)").click();
const emailRequiredFiled = await page.locator('[data-testid="field-required"]').first();
await emailRequiredFiled.click();
await page.getByTestId("field-add-save").click();
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
action: () => page.locator("[data-testid=update-eventtype]").click(),
@@ -790,12 +790,12 @@ const markPhoneNumberAsRequiredAndEmailAsOptional = async (page: Page, eventId:
const markPhoneNumberAsRequiredField = async (page: Page, eventId: number) => {
await page.goto(`/event-types/${eventId}?tabName=advanced`);
await expect(page.getByTestId("vertical-tab-event_setup_tab_title")).toContainText("Event Setup"); // fix the race condition
await expect(page.getByTestId("vertical-tab-basics")).toContainText("Basics"); // fix the race condition
await page.locator('[data-testid="field-attendeePhoneNumber"] [data-testid="toggle-field"]').click();
await page.locator('[data-testid="field-attendeePhoneNumber"] [data-testid="edit-field-action"]').click();
const phoneRequiredFiled = await page.locator('[data-testid="field-required"]');
await phoneRequiredFiled.locator("> :nth-child(1)").click();
const phoneRequiredFiled = await page.locator('[data-testid="field-required"]').first();
await phoneRequiredFiled.click();
await page.getByTestId("field-add-save").click();
await submitAndWaitForResponse(page, "/api/trpc/eventTypes/update?batch=1", {
action: () => page.locator("[data-testid=update-eventtype]").click(),
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "يمكنك ربط رزنامتك من <1>هنا</1>.",
"default_calendar_selected": "الرزنامة الافتراضية",
"hide_from_profile": "إخفاء من الملف الشخصي",
"event_setup_tab_title": "إعداد الحدث",
"basics": "إعداد الحدث",
"availability_not_found_in_schedule_error": "لا يوجد مواعيد متاحة",
"event_limit_tab_title": "الحدود",
"event_limit_tab_description": "ما تواتر مرات الحجز",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Təqviminizi <1>buradan</1> əlaqələndirə bilərsiniz.",
"default_calendar_selected": "Varsayılan təqvim seçildi",
"hide_from_profile": "Profildən gizlət",
"event_setup_tab_title": "Tədbir Quraşdırması",
"basics": "Tədbir Quraşdırması",
"availability_not_found_in_schedule_error": "Cədvəldə mövcudluq tapılmadı",
"event_limit_tab_title": "Limitlər",
"event_limit_tab_description": "Nə qədər tez-tez rezervasiya edilə bilərsiniz",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Можете да свържете календара си от <1>тук</1>.",
"default_calendar_selected": "Календар по подразбиране",
"hide_from_profile": "Скрий от профила",
"event_setup_tab_title": "Настройка на събитие",
"basics": "Настройка на събитие",
"availability_not_found_in_schedule_error": "Не е намерена свободна заетост в графика",
"event_limit_tab_title": "Лимити",
"event_limit_tab_description": "Колко често можете да бъдете резервиран",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "আপনি আপনার ক্যালেন্ডার থেকে সংযুক্ত করতে পারেন <1>এখানে</1>।",
"default_calendar_selected": "ডিফল্ট ক্যালেন্ডার",
"hide_from_profile": "প্রোফাইল থেকে লুকান",
"event_setup_tab_title": "ইভেন্ট সেটআপ",
"basics": "ইভেন্ট সেটআপ",
"availability_not_found_in_schedule_error": "তফসিলের মধ্যে কোনও প্রাপ্যতা পাওয়া যায় না",
"event_limit_tab_title": "সীমা",
"event_limit_tab_description": "আপনি কতবার বুক করা যায়",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Pots connectar el teu calendari des d'<1>aquí</1>.",
"default_calendar_selected": "Calendari predeterminat",
"hide_from_profile": "Amaga del perfil",
"event_setup_tab_title": "Configuració de l'esdeveniment",
"basics": "Configuració de l'esdeveniment",
"availability_not_found_in_schedule_error": "No s'ha trobat disponibilitat a l'agenda",
"event_limit_tab_title": "Límits",
"event_limit_tab_description": "Amb quina freqüència et poden reservar",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Svůj kalendář můžete připojit <1>zde</1>.",
"default_calendar_selected": "Výchozí kalendář",
"hide_from_profile": "Nezobrazovat v profilu",
"event_setup_tab_title": "Nastavení události",
"basics": "Nastavení události",
"availability_not_found_in_schedule_error": "V rozvrhu nebyla nalezena žádná dostupnost",
"event_limit_tab_title": "Omezení",
"event_limit_tab_description": "Jak často lze u vás provést rezervaci",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Du kan forbinde din kalender fra <1>her</1>.",
"default_calendar_selected": "Standard kalender",
"hide_from_profile": "Skjul fra profil",
"event_setup_tab_title": "Opsætning af Begivenheder",
"basics": "Opsætning af Begivenheder",
"availability_not_found_in_schedule_error": "Ingen tilgængelighed fundet i tidsplanen",
"event_limit_tab_title": "Grænser",
"event_limit_tab_description": "Hvor ofte du kan bookes",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Sie können Ihren Kalender von <1>hier</1> verbinden.",
"default_calendar_selected": "Standardkalender",
"hide_from_profile": "Im Profil ausblenden",
"event_setup_tab_title": "Termin-Einrichtung",
"basics": "Termin-Einrichtung",
"availability_not_found_in_schedule_error": "Keine Verfügbarkeit im Zeitplan gefunden",
"event_limit_tab_title": "Limits",
"event_limit_tab_description": "Wie oft können Sie gebucht werden",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Μπορείτε να συνδέσετε το ημερολόγιό σας από <1>εδώ</1>.",
"default_calendar_selected": "Προεπιλεγμένο ημερολόγιο",
"hide_from_profile": "Απόκρυψη από το προφίλ",
"event_setup_tab_title": "Ρύθμιση εκδήλωσης",
"basics": "Ρύθμιση εκδήλωσης",
"availability_not_found_in_schedule_error": "Δεν βρέθηκε διαθεσιμότητα στο πρόγραμμα",
"event_limit_tab_title": "Όρια",
"event_limit_tab_description": "Πόσο συχνά μπορείτε να κάνετε κράτηση",
+18 -13
View File
@@ -278,6 +278,7 @@
"number": "Number",
"checkbox": "Checkbox",
"is_required": "Is required",
"make_field_required": "Make this field required",
"required": "Required",
"optional": "Optional",
"input_type": "Input type",
@@ -354,7 +355,7 @@
"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",
"few_sentences_about_yourself": "A few sentences about yourself. This will appear on your personal url page.",
"few_sentences_about_yourself": "A few sentences about yourself. This will appear on your scheduling link.",
"nearly_there": "Nearly there!",
"nearly_there_instructions": "Last thing, a brief description about you and a photo really helps you get bookings and let people know who they're booking with.",
"set_availability_instructions": "Define ranges of time when you are available on a recurring basis. You can create more of these later and assign them to different calendars.",
@@ -367,7 +368,7 @@
"continue_with": "Continue with {{appName}}",
"connect_your_calendar": "Connect your calendar",
"connect_your_video_app": "Connect your video apps",
"connect_your_video_app_instructions": "Connect your video apps to use them on your event types.",
"connect_your_video_app_instructions": "Connect your preferred video conferencing app to use it for your meetings.",
"connect_your_calendar_instructions": "Connect your calendar to automatically check for busy times and new events as they're scheduled.",
"set_up_later": "Set up later",
"current_time": "Current time",
@@ -931,7 +932,7 @@
"add_attendees": "Add attendees",
"show_advanced_settings": "Show advanced settings",
"event_name": "Event Name",
"event_name_in_calendar": "With event name",
"event_name_in_calendar": "Calendar event name",
"event_name_tooltip": "The name that will appear in calendars",
"meeting_with_user": "{Event type title} between {Organiser} & {Scheduler}",
"additional_inputs": "Additional Inputs",
@@ -947,7 +948,7 @@
"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 the integrations and a confirmation mail is sent.",
"requires_confirmation_description": "The booking needs to be manually confirmed before it is pushed to your calendar and a confirmation is sent.",
"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",
@@ -998,7 +999,7 @@
"quick_chat": "Quick Chat",
"add_new_team_event_type": "Add a new team event type",
"add_new_event_type": "Add a new event type",
"new_event_type_to_book_description": "Create a new event type for people to book times with.",
"new_event_type_to_book_description": "Set up event types to offer different types of meetings.",
"length": "Length",
"minimum_booking_notice": "Minimum Notice",
"offset_toggle": "Offset start times",
@@ -1023,6 +1024,7 @@
"category_apps": "{{category}} apps",
"app_store": "App Store",
"app_store_description": "Connecting people, technology and the workplace.",
"connect_your_video": "Connect your video conferencing app",
"settings": "Settings",
"event_type_moved_successfully": "Event type has been moved successfully",
"next_step_text": "Next Step",
@@ -1238,7 +1240,7 @@
"make_team_private_description": "Your team members won't be able to see other team members when this is turned on.",
"you_cannot_see_team_members": "You cannot see all the team members of a private team.",
"you_cannot_see_teams_of_org": "You cannot see teams of a private organization.",
"allow_booker_to_select_duration": "Allow booker to select duration",
"allow_booker_to_select_duration": "Allow booker to select from multiple durations",
"impersonate_user_tip": "All uses of this feature is audited.",
"impersonating_user_warning": "Impersonating username \"{{user}}\".",
"impersonating_stop_instructions": "Click here to stop",
@@ -1494,7 +1496,7 @@
"connect_your_calendar_and_link": "You can connect your calendar from <1>here</1>.",
"default_calendar_selected": "Default calendar",
"hide_from_profile": "Hide from profile",
"event_setup_tab_title": "Event Setup",
"basics": "Basics",
"availability_not_found_in_schedule_error": "No availability found in schedule",
"event_limit_tab_title": "Limits",
"event_limit_tab_description": "How often you can be booked",
@@ -1524,7 +1526,8 @@
"settings_updated_successfully": "Settings updated successfully",
"error_updating_settings": "Error updating settings",
"personal_cal_url": "My personal {{appName}} URL",
"bio_hint": "A few sentences about yourself. this will appear on your personal url page.",
"bio_hint": "A few sentences about yourself. this will appear on your scheduling link.",
"finish_and_start": "Finish setup and get started",
"user_has_no_bio": "This user has not added a bio yet.",
"bio": "Bio",
"delete_account_modal_title": "Delete Account",
@@ -1580,8 +1583,10 @@
"we_just_need_basic_info": "We just need some basic info to get your profile setup.",
"skip": "Skip",
"do_this_later": "Do this later",
"set_availability_getting_started_subtitle_1": "Define ranges of time when you are available",
"set_availability_getting_started_subtitle_2": "You can customise all of this later in the availability page.",
"set_availability_getting_started_subtitle_1": "Define ranges of time when you are available.",
"set_availability_getting_started_subtitle_2": "Customize it later in the availability page.",
"connect_calendar_first": "Connect a calendar first",
"complete_profile": "Complete your profile",
"connect_calendars_from_app_store": "You can add more calendars from the app store",
"connect_conference_apps": "Connect conference apps",
"connect_calendar_apps": "Connect calendar apps",
@@ -2992,8 +2997,8 @@
"edit_team_member_weights": "Edit Weights",
"weights_updated_successfully": "Weights updated successfully",
"require_confirmation_for_free_email": "Only require confirmation for free email providers (Ex. @gmail.com, @outlook.com)",
"exclude_emails_that_contain": "Exclude emails that contain ...",
"require_emails_that_contain": "Require emails that contain ...",
"exclude_emails_that_contain": "Exclude emails that contain",
"require_emails_that_contain": "Require emails that contain",
"exclude_emails_match_found_error_message": "Please enter a valid work email address",
"require_emails_no_match_found_error_message": "You are not allowed to book with this email domain. Please contact the owner of this link.",
"search_columns": "Search columns",
@@ -3128,7 +3133,7 @@
"inactive_team_plan_description": "Your team plan is inactive. Check your subcription or reach out to customer support",
"limited_access_trial_mode": "Limited access during trial. Feature available after trial ends.",
"referral_program": "Referral Program",
"referral_text": "Earn 20% referral",
"referral_text": "Refer and earn",
"dub_disabled_error_message": "You need a Dub API Key and Program Id to use this page.",
"uid": "UID",
"link": "Link",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Puedes conectar tu calendario desde <1>aquí</1>.",
"default_calendar_selected": "Calendario predeterminado",
"hide_from_profile": "Ocultar del perfil",
"event_setup_tab_title": "Configuración del evento",
"basics": "Configuración del evento",
"availability_not_found_in_schedule_error": "No se encontró disponibilidad en el horario",
"event_limit_tab_title": "Límites",
"event_limit_tab_description": "Con qué frecuencia puedes ser reservado",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Puede conectar su calendario desde <1>aquí</1>.",
"default_calendar_selected": "Calendario predeterminado",
"hide_from_profile": "Ocultar del perfil",
"event_setup_tab_title": "Configuración del evento",
"basics": "Configuración del evento",
"availability_not_found_in_schedule_error": "No se encontró disponibilidad en el horario",
"event_limit_tab_title": "Límites",
"event_limit_tab_description": "Con qué frecuencia se puede reservar",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Saate oma kalendri ühendada <1>siit</1>.",
"default_calendar_selected": "Vaikekalender",
"hide_from_profile": "Peida profiilist",
"event_setup_tab_title": "Sündmuse seadistamine",
"basics": "Sündmuse seadistamine",
"availability_not_found_in_schedule_error": "Ajakavas ei leitud saadavust",
"event_limit_tab_title": "Piirangud",
"event_limit_tab_description": "Kui sageli saate broneerida",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Zure egutegia <1>hemendik</1> konekta dezakezu.",
"default_calendar_selected": "Egutegi lehenetsia",
"hide_from_profile": "Ezkutatu profiletik",
"event_setup_tab_title": "Gertaeraren konfigurazioa",
"basics": "Gertaeraren konfigurazioa",
"availability_not_found_in_schedule_error": "Ez da eskuragarritasunik aurkitu ordutegian",
"event_limit_tab_title": "Mugak",
"event_limit_tab_description": "Zenbatetan erreserbatu zaitzaketen",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Voit yhdistää kalenterisi <1>täältä</1>.",
"default_calendar_selected": "Oletuskalenteri valittu",
"hide_from_profile": "Piilota profiilista",
"event_setup_tab_title": "Tapahtuman asetukset",
"basics": "Tapahtuman asetukset",
"availability_not_found_in_schedule_error": "Aikataulusta ei löytynyt vapaita aikoja",
"event_limit_tab_title": "Rajoitukset",
"event_limit_tab_description": "Kuinka usein sinut voidaan varata",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Vous pouvez connecter votre calendrier depuis <1>ici</1>.",
"default_calendar_selected": "Calendrier par défaut",
"hide_from_profile": "Masquer du profil",
"event_setup_tab_title": "Configuration",
"basics": "Configuration",
"availability_not_found_in_schedule_error": "Aucune disponibilité trouvée dans le planning",
"event_limit_tab_title": "Limites",
"event_limit_tab_description": "Fréquence de réservation",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "ניתן לחבר את לוח השנה שלך מ<1>כאן</1>.",
"default_calendar_selected": "לוח השנה המוגדר כברירת מחדל",
"hide_from_profile": "הסתר מהפרופיל",
"event_setup_tab_title": "הגדרת ארוע",
"basics": "הגדרת ארוע",
"availability_not_found_in_schedule_error": "לא נמצא חלון זמינות בלוח הזמנים",
"event_limit_tab_title": "מגבלות",
"event_limit_tab_description": "באיזו תדירות ניתן להזמין אותך",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Naptárát <1>innen</1> csatlakoztathatja.",
"default_calendar_selected": "Alapértelmezett naptár",
"hide_from_profile": "Elrejtés a profilból",
"event_setup_tab_title": "Esemény beállítása",
"basics": "Esemény beállítása",
"availability_not_found_in_schedule_error": "Az ütemezésben nem található elérhetőség",
"event_limit_tab_title": "Korlátok",
"event_limit_tab_description": "Milyen gyakran vagy foglalható",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Puoi collegare il tuo calendario <1>qui</1>.",
"default_calendar_selected": "Calendario predefinito",
"hide_from_profile": "Nascondi nel profilo",
"event_setup_tab_title": "Impostazione evento",
"basics": "Impostazione evento",
"availability_not_found_in_schedule_error": "Nessuna disponibilità trovata nel programma",
"event_limit_tab_title": "Limiti",
"event_limit_tab_description": "Con quale frequenza è possibile fare una prenotazione",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "<1>こちら</1>からカレンダーを接続できます。",
"default_calendar_selected": "デフォルトのカレンダー",
"hide_from_profile": "プロファイルから隠す",
"event_setup_tab_title": "イベント設定",
"basics": "イベント設定",
"availability_not_found_in_schedule_error": "スケジュールに利用可能な時間が見つかりません",
"event_limit_tab_title": "上限",
"event_limit_tab_description": "予約できる頻度",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "អ្នកអាចភ្ជាប់ប្រតិទិនរបស់អ្នកពី <1>ទីនេះ</1>។",
"default_calendar_selected": "ប្រតិទិនលំនាំដើម",
"hide_from_profile": "លាក់ពីប្រវត្តិរូប",
"event_setup_tab_title": "ការកំណត់ព្រឹត្តិការណ៍",
"basics": "ការកំណត់ព្រឹត្តិការណ៍",
"availability_not_found_in_schedule_error": "មិនមានភាពទំនេរដែលបានរកឃើញនៅក្នុងកាលវិភាគ",
"event_limit_tab_title": "ដែនកំណត់",
"event_limit_tab_description": "ភាពញឹកញាប់ដែលអ្នកអាចត្រូវបានកក់",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "캘린더는 <1>여기</1>에서 연결할 수 있습니다.",
"default_calendar_selected": "기본 캘린더",
"hide_from_profile": "프로필에서 숨기기",
"event_setup_tab_title": "이벤트 설정",
"basics": "이벤트 설정",
"availability_not_found_in_schedule_error": "일정에서 사용 가능 시간을 찾을 수 없습니다",
"event_limit_tab_title": "한도",
"event_limit_tab_description": "예약 가능 횟수",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "U kunt uw agenda koppelen vanaf <1>hier</1>.",
"default_calendar_selected": "Standaardagenda",
"hide_from_profile": "In profiel verbergen",
"event_setup_tab_title": "Configuratie gebeurtenis",
"basics": "Configuratie gebeurtenis",
"availability_not_found_in_schedule_error": "Geen beschikbaarheid gevonden in het schema",
"event_limit_tab_title": "Grenswaarden",
"event_limit_tab_description": "Hoe vaak u geboekt kunt worden",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Du kan koble til kalenderen din <1>her</1>.",
"default_calendar_selected": "Standard kalender",
"hide_from_profile": "Skjul fra profilen",
"event_setup_tab_title": "Hendelsesoppsett",
"basics": "Hendelsesoppsett",
"availability_not_found_in_schedule_error": "Ingen tilgjengelighet funnet i timeplanen",
"event_limit_tab_title": "Grenser",
"event_limit_tab_description": "Hvor ofte du kan bookes",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Możesz podłączyć swój kalendarz <1>tutaj</1>.",
"default_calendar_selected": "Domyślny kalendarz",
"hide_from_profile": "Ukryj w profilu",
"event_setup_tab_title": "Konfiguracja wydarzenia",
"basics": "Konfiguracja wydarzenia",
"availability_not_found_in_schedule_error": "Brak dostępności w harmonogramie",
"event_limit_tab_title": "Limity",
"event_limit_tab_description": "Jak często można rezerwować Twoje usługi",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Você pode conectar seu calendário por <1>aqui</1>.",
"default_calendar_selected": "Calendário padrão",
"hide_from_profile": "Ocultar do perfil",
"event_setup_tab_title": "Configuração de eventos",
"basics": "Configuração de eventos",
"availability_not_found_in_schedule_error": "Nenhuma disponibilidade encontrada na programação",
"event_limit_tab_title": "Limites",
"event_limit_tab_description": "Com que frequência você pode receber reserva",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Pode associar ao seu calendário a partir de <1>aqui</1>.",
"default_calendar_selected": "Calendário predefinido",
"hide_from_profile": "Ocultar do perfil",
"event_setup_tab_title": "Configuração do evento",
"basics": "Configuração do evento",
"availability_not_found_in_schedule_error": "Não foi encontrada nenhuma disponibilidade na agenda",
"event_limit_tab_title": "Limites",
"event_limit_tab_description": "Com que frequência pode ser reservado",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Vă puteți conecta calendarul de <1>aici</1>.",
"default_calendar_selected": "Calendar implicit",
"hide_from_profile": "Ascundeți din profil",
"event_setup_tab_title": "Configurare eveniment",
"basics": "Configurare eveniment",
"availability_not_found_in_schedule_error": "Nu s-a găsit disponibilitate în program",
"event_limit_tab_title": "Limite",
"event_limit_tab_description": "Cât de des puteți fi rezervat",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Можно подключить календарь <1>отсюда</1>.",
"default_calendar_selected": "Календарь по умолчанию",
"hide_from_profile": "Скрыть в профиле",
"event_setup_tab_title": "Настройка события",
"basics": "Настройка события",
"availability_not_found_in_schedule_error": "Доступность не найдена в расписании",
"event_limit_tab_title": "Лимиты",
"event_limit_tab_description": "Как часто можно забронировать для вас событие",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Môžete pripojiť svoj kalendár z <1>tu</1>.",
"default_calendar_selected": "Predvolený kalendár",
"hide_from_profile": "Skryť z profilu",
"event_setup_tab_title": "Nastavenie udalosti",
"basics": "Nastavenie udalosti",
"availability_not_found_in_schedule_error": "V rozvrhu nebola nájdená dostupnosť",
"event_limit_tab_title": "Limity",
"event_limit_tab_description": "Ako často môžete byť rezervovaní",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Ne možete da povežete svoj kalendar <1>odavde</1>.",
"default_calendar_selected": "Podrazumevani kalendar",
"hide_from_profile": "Sakrij sa profila",
"event_setup_tab_title": "Podešavanje događaja",
"basics": "Podešavanje događaja",
"availability_not_found_in_schedule_error": "Nema dostupnosti u rasporedu",
"event_limit_tab_title": "Granice",
"event_limit_tab_description": "Koliko često možete da budete rezervisani",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Du kan ansluta din kalender från <1>här</1>.",
"default_calendar_selected": "Förvald kalender",
"hide_from_profile": "Dölj från profil",
"event_setup_tab_title": "Konfiguration av händelse",
"basics": "Konfiguration av händelse",
"availability_not_found_in_schedule_error": "Ingen tillgänglighet hittades i schemat",
"event_limit_tab_title": "Gränser",
"event_limit_tab_description": "Hur ofta du kan bokas",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Takviminizi <1>buradan</1> bağlayabilirsiniz.",
"default_calendar_selected": "Varsayılan takvim",
"hide_from_profile": "Profilde gizle",
"event_setup_tab_title": "Etkinlik Kurulumu",
"basics": "Etkinlik Kurulumu",
"availability_not_found_in_schedule_error": "Programda uygunluk bulunamadı",
"event_limit_tab_title": "Limitler",
"event_limit_tab_description": "Ne sıklıkla rezervasyon yapabilirsiniz",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Підключити календар можна <1>звідси</1>.",
"default_calendar_selected": "Календар за замовчуванням",
"hide_from_profile": "Не показувати в профілі",
"event_setup_tab_title": "Налаштування заходу",
"basics": "Налаштування заходу",
"availability_not_found_in_schedule_error": "Доступність у розкладі не знайдена",
"event_limit_tab_title": "Ліміти",
"event_limit_tab_description": "Як часто ваш час можуть бронювати",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "Bạn có thể kết nối lịch của mình từ <1>đây</1>.",
"default_calendar_selected": "Lịch mặc định",
"hide_from_profile": "Ẩn khỏi hồ sơ",
"event_setup_tab_title": "Thiết lập sự kiện",
"basics": "Thiết lập sự kiện",
"availability_not_found_in_schedule_error": "Không tìm thấy thời gian khả dụng trong lịch trình",
"event_limit_tab_title": "Giới hạn",
"event_limit_tab_description": "Bạn có thể được đặt lịch bao lần",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "您可以从<1>这里</1>连接您的日历。",
"default_calendar_selected": "默认日历",
"hide_from_profile": "从个人资料中隐藏",
"event_setup_tab_title": "活动设置",
"basics": "活动设置",
"availability_not_found_in_schedule_error": "时间表中没有可供安排的时间",
"event_limit_tab_title": "限制",
"event_limit_tab_description": "您多久可被预约一次",
@@ -1489,7 +1489,7 @@
"connect_your_calendar_and_link": "您可以從<1>這裡</1>連結行事曆。",
"default_calendar_selected": "預設行事曆",
"hide_from_profile": "從個人資料隱藏",
"event_setup_tab_title": "活動設定",
"basics": "活動設定",
"availability_not_found_in_schedule_error": "在日程中找不到可用時間",
"event_limit_tab_title": "限制",
"event_limit_tab_description": "您的可預約頻率",
@@ -64,11 +64,9 @@ export default function CreateEventTypeForm({
required
addOnLeading={
!isPlatform ? (
<Tooltip content={!isManagedEventType ? pageSlug : t("username_placeholder")}>
<span className="max-w-24 md:max-w-56">
{`/${!isManagedEventType ? pageSlug : t("username_placeholder")}/`}
</span>
</Tooltip>
<span className="max-w-24 md:max-w-56">
{`/${!isManagedEventType ? pageSlug : t("username_placeholder")}/`}
</span>
) : undefined
}
containerClassName="[&>div]:gap-0"
@@ -115,6 +113,7 @@ export default function CreateEventTypeForm({
<TextAreaField {...register("description")} placeholder={t("quick_video_meeting")} />
) : (
<Editor
label={t("description")}
getText={() => md.render(form.getValues("description") || "")}
setText={(value: string) => form.setValue("description", turndown(value))}
excludedToolbarItems={["blockType", "link"]}
@@ -145,7 +144,7 @@ export default function CreateEventTypeForm({
message: t("duration_max_error", { max: MAX_EVENT_DURATION_MINUTES }),
},
})}
addOnSuffix={t("minutes")}
addOnSuffix={t("minutes").toLowerCase()}
/>
</div>
</>
@@ -116,19 +116,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
)}>
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Event type title}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("event_name_info")}
@@ -136,19 +136,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
</div>
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Event duration}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("event_duration_info")}
@@ -156,19 +156,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
</div>
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Organiser}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("your_full_name")}
@@ -176,19 +176,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
</div>
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Organiser first name}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("organizer_first_name")}
@@ -196,19 +196,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
</div>
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Scheduler}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("scheduler_full_name")}
@@ -216,19 +216,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
</div>
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Scheduler first name}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("scheduler_first_name")}
@@ -237,19 +237,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
{isNameFieldSplit && (
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Scheduler last name}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("scheduler_last_name")}
@@ -258,19 +258,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
)}
<div
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.variableItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.variableItem?.variableName
)}>
{`{Location}`}
</p>
<p
className={classNames(
"text-emphasis",
"text-emphasis min-w-0 flex-1",
customClassNames?.availableVariables?.variableItem?.variableDescription
)}>
{t("location_info")}
@@ -291,19 +291,19 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
<div
key={index}
className={classNames(
"mb-2.5 flex font-normal",
"mb-2.5 flex items-start font-normal",
customClassNames?.availableVariables?.bookingFieldItem?.container
)}>
<p
className={classNames(
"text-subtle ml-1 mr-5 w-32",
"text-subtle ml-1 mr-5 w-40 flex-shrink-0",
customClassNames?.availableVariables?.bookingFieldItem?.fieldName
)}>
{`{${bookingfield}}`}
</p>
<p
className={classNames(
"text-emphasis capitalize",
"text-emphasis min-w-0 flex-1 capitalize",
customClassNames?.availableVariables?.bookingFieldItem?.fieldValue
)}>
{event.bookingFields?.[bookingfield]?.toString()}
@@ -234,36 +234,38 @@ export default function RequiresConfirmationController({
id="notice"
value="notice"
/>
<CheckboxField
checked={requiresConfirmationWillBlockSlot}
descriptionAsLabel
description={t("requires_confirmation_will_block_slot_description")}
className={customClassNames?.conditionalConfirmationRadio?.checkbox}
descriptionClassName={
customClassNames?.conditionalConfirmationRadio?.checkboxDescription
}
onChange={(e) => {
// We set should dirty to properly detect when we can submit the form
formMethods.setValue("requiresConfirmationWillBlockSlot", e.target.checked, {
shouldDirty: true,
});
}}
/>
<CheckboxField
checked={requiresConfirmationForFreeEmail}
descriptionAsLabel
description={t("require_confirmation_for_free_email")}
className={customClassNames?.conditionalConfirmationRadio?.checkbox}
descriptionClassName={
customClassNames?.conditionalConfirmationRadio?.checkboxDescription
}
onChange={(e) => {
// We set should dirty to properly detect when we can submit the form
formMethods.setValue("requiresConfirmationForFreeEmail", e.target.checked, {
shouldDirty: true,
});
}}
/>
<div className="-ml-1 space-y-2">
<CheckboxField
checked={requiresConfirmationWillBlockSlot}
descriptionAsLabel
description={t("requires_confirmation_will_block_slot_description")}
className={customClassNames?.conditionalConfirmationRadio?.checkbox}
descriptionClassName={
customClassNames?.conditionalConfirmationRadio?.checkboxDescription
}
onChange={(e) => {
// We set should dirty to properly detect when we can submit the form
formMethods.setValue("requiresConfirmationWillBlockSlot", e.target.checked, {
shouldDirty: true,
});
}}
/>
<CheckboxField
checked={requiresConfirmationForFreeEmail}
descriptionAsLabel
description={t("require_confirmation_for_free_email")}
className={customClassNames?.conditionalConfirmationRadio?.checkbox}
descriptionClassName={
customClassNames?.conditionalConfirmationRadio?.checkboxDescription
}
onChange={(e) => {
// We set should dirty to properly detect when we can submit the form
formMethods.setValue("requiresConfirmationForFreeEmail", e.target.checked, {
shouldDirty: true,
});
}}
/>
</div>
</>
)}
</div>
+52 -42
View File
@@ -24,7 +24,6 @@ import {
Input,
InputField,
Label,
BooleanToggleGroupField,
} from "@calcom/ui/components/form";
import { Icon } from "@calcom/ui/components/icon";
import { showToast } from "@calcom/ui/components/toast";
@@ -673,26 +672,33 @@ function FieldEditDialog({
/>
)}
<Controller
name="required"
control={fieldForm.control}
render={({ field: { value, onChange } }) => {
const isRequired = shouldConsiderRequired
? shouldConsiderRequired(fieldForm.getValues())
: value;
return (
<BooleanToggleGroupField
data-testid="field-required"
disabled={fieldForm.getValues("editable") === "system"}
value={isRequired}
onValueChange={(val) => {
onChange(val);
}}
label={t("required")}
/>
);
}}
/>
<div className="mt-6">
<Controller
name="required"
control={fieldForm.control}
render={({ field: { value, onChange } }) => {
let isRequired = shouldConsiderRequired
? shouldConsiderRequired(fieldForm.getValues())
: value;
//by default question should be required
if (isRequired === undefined) {
isRequired = true;
onChange(isRequired);
}
return (
<CheckboxField
data-testid="field-required"
disabled={fieldForm.getValues("editable") === "system"}
checked={isRequired}
onChange={(e) => {
onChange(e.target.checked);
}}
description={t("make_field_required")}
/>
);
}}
/>
</div>
</>
);
}
@@ -880,10 +886,12 @@ function VariantFields({
label={t("identifier")}
/>
<CheckboxField
description={t("disable_input_if_prefilled")}
{...fieldForm.register("disableOnPrefill", { setValueAs: Boolean })}
/>
<div className="mt-2">
<CheckboxField
description={t("disable_input_if_prefilled")}
{...fieldForm.register("disableOnPrefill", { setValueAs: Boolean })}
/>
</div>
<ul
className={classNames(
@@ -921,23 +929,25 @@ function VariantFields({
placeholder={t(appUiFieldConfig?.defaultPlaceholder || "")}
/>
<Controller
name={`${rhfVariantFieldPrefix}.required`}
control={fieldForm.control}
render={({ field: { onChange } }) => {
return (
<BooleanToggleGroupField
data-testid="field-required"
disabled={!appUiFieldConfig?.canChangeRequirability}
value={f.required}
onValueChange={(val) => {
onChange(val);
}}
label={t("required")}
/>
);
}}
/>
<div className="mt-6">
<Controller
name={`${rhfVariantFieldPrefix}.required`}
control={fieldForm.control}
render={({ field: { onChange } }) => {
return (
<CheckboxField
data-testid="field-required"
disabled={!appUiFieldConfig?.canChangeRequirability}
checked={f.required}
onChange={(e) => {
onChange(e.target.checked);
}}
description={t("make_field_required")}
/>
);
}}
/>
</div>
</li>
);
})}
+16 -9
View File
@@ -97,15 +97,20 @@ export const pageObject = {
},
dialog: {
isFieldShowingAsRequired: ({ dialog }: { dialog: TestingLibraryElement }) => {
return (
within(dialog.getByTestId("field-required")).getByText("Yes").getAttribute("aria-checked") === "true"
);
const checkbox = dialog.getByTestId("field-required") as HTMLInputElement;
return checkbox.checked;
},
makeFieldOptional: ({ dialog }: { dialog: TestingLibraryElement }) => {
fireEvent.click(within(dialog.getByTestId("field-required")).getByText("No"));
const checkbox = dialog.getByTestId("field-required") as HTMLInputElement;
if (checkbox.checked) {
fireEvent.click(checkbox);
}
},
makeFieldRequired: ({ dialog }: { dialog: TestingLibraryElement }) => {
fireEvent.click(within(dialog.getByTestId("field-required")).getByText("Yes"));
const checkbox = dialog.getByTestId("field-required") as HTMLInputElement;
if (!checkbox.checked) {
fireEvent.click(checkbox);
}
},
queryIdentifierInput: ({ dialog }: { dialog: TestingLibraryElement }) => {
return dialog.getByLabelText("identifier");
@@ -249,10 +254,8 @@ export const expectScenario = {
expect(identifierInput.disabled).toBe(true);
},
toHaveRequirablityToggleDisabled: ({ dialog }: { dialog: TestingLibraryElement }) => {
const no = within(dialog.getByTestId("field-required")).getByText("No") as HTMLButtonElement;
const yes = within(dialog.getByTestId("field-required")).getByText("Yes") as HTMLButtonElement;
expect(no.disabled).toBe(true);
expect(yes.disabled).toBe(true);
const checkbox = dialog.getByTestId("field-required") as HTMLInputElement;
expect(checkbox.disabled).toBe(true);
},
toHaveLabelChangeAllowed: ({ dialog }: { dialog: TestingLibraryElement }) => {
const labelInput = dialog.getByLabelText("label");
@@ -268,6 +271,10 @@ export const expectScenario = {
const field = getFieldInTheList({ identifier });
expect(field.getByText(sourceLabel)).not.toBeNull();
},
toNotHaveOptionalBadge: ({ identifier }: { identifier: string }) => {
const field = getFieldInTheList({ identifier });
expect(field.queryByTestId("optional")).toBeNull();
},
toHaveRequiredBadge: ({ identifier }: { identifier: string }) => {
const field = getFieldInTheList({ identifier });
expect(field.getByText("required")).not.toBeNull();
@@ -149,13 +149,13 @@ function getNavigation({ length, multipleDuration, t, tabs, url, onClick, curren
const tabsNavigation: VerticalTabItemProps[] = [];
tabs.includes("setup") &&
tabsNavigation.push({
name: t("event_setup_tab_title"),
name: t("basics"),
onClick: () => onClick("setup"),
isActive: currentTab === "setup",
href: `${url}?tabName=setup`,
icon: "link",
info: `${duration} ${t("minute_timeUnit")}`, // TODO: Get this from props
"data-testid": `event_setup_tab_title`,
"data-testid": `basics`,
});
tabs.includes("limits") &&
tabsNavigation.push({
@@ -195,11 +195,11 @@ function getNavigation({
return [
{
name: t("event_setup_tab_title"),
name: t("basics"),
href: `/event-types/${id}?tabName=setup`,
icon: "link",
info: `${duration} ${t("minute_timeUnit")}`, // TODO: Get this from props
"data-testid": `event_setup_tab_title`,
"data-testid": `basics`,
},
{
name: t("event_limit_tab_title"),
+3 -2
View File
@@ -61,8 +61,9 @@ export const Editor = (props: TextEditorProps) => {
const plainText = props.plainText ?? false;
return (
<div className="editor rounded-md">
{props.label && <label className="mb-1 block text-sm font-medium leading-6">{props.label}</label>}
<LexicalComposer initialConfig={{ ...editorConfig }}>
<div className="editor-container hover:border-emphasis focus-within:ring-brand-default !rounded-lg p-0 transition focus-within:ring-2">
<div className="editor-container hover:border-emphasis focus-within:ring-brand-default !rounded-lg p-0 transition focus-within:ring-2 focus-within:ring-offset-0">
<ToolbarPlugin
getText={props.getText}
setText={props.setText}
@@ -82,7 +83,7 @@ export const Editor = (props: TextEditorProps) => {
<ContentEditable
readOnly={!editable}
style={{ height: props.height }}
className="editor-input"
className="editor-input focus:outline-none"
data-testid="editor-input"
/>
}
+1
View File
@@ -15,4 +15,5 @@ export type TextEditorProps = {
setFirstRender?: Dispatch<SetStateAction<boolean>>;
editable?: boolean;
plainText?: boolean;
label?: string;
};
@@ -75,8 +75,8 @@ export const Switch = (
<Label.Root
htmlFor={id}
className={cx(
"text-emphasis align-text-top font-medium",
size === "sm" ? "m-1 text-xs" : "m-2 text-sm",
"text-emphasis font-medium",
size === "sm" ? "m-1 text-xs" : "ml-2 mt-1 text-sm",
primitiveProps.disabled ? "cursor-not-allowed opacity-25" : "cursor-pointer",
labelOnLeading && "flex-1"
)}>