fix: Bunch of fixes and minor changes throughout the app (#23356)
* Bunch of fixes and minor changes throughout the app * remove logs * fix: e2e * fix: e2e * fix: more e2e and design * revert insights upgrade change
This commit is contained in:
@@ -11,6 +11,7 @@ export const TeamsCTA = () => {
|
||||
data-testid="new-team-btn"
|
||||
variant="fab"
|
||||
StartIcon="plus"
|
||||
size="sm"
|
||||
type="button"
|
||||
href={`${WEBAPP_URL}/settings/teams/new?returnTo=${WEBAPP_URL}/teams`}>
|
||||
{t("new")}
|
||||
|
||||
+8
@@ -438,6 +438,7 @@ const TeamListCollapsible = ({ teamFeatures }: { teamFeatures?: Record<number, T
|
||||
name={t("profile")}
|
||||
href={`/settings/teams/${team.id}/profile`}
|
||||
textClassNames="px-3 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
disableChevron
|
||||
/>
|
||||
)}
|
||||
@@ -445,6 +446,7 @@ const TeamListCollapsible = ({ teamFeatures }: { teamFeatures?: Record<number, T
|
||||
name={t("members")}
|
||||
href={`/settings/teams/${team.id}/members`}
|
||||
textClassNames="px-3 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
disableChevron
|
||||
/>
|
||||
{/* Show roles only for sub-teams with PBAC-enabled parent */}
|
||||
@@ -465,6 +467,7 @@ const TeamListCollapsible = ({ teamFeatures }: { teamFeatures?: Record<number, T
|
||||
name={t("appearance")}
|
||||
href={`/settings/teams/${team.id}/appearance`}
|
||||
textClassNames="px-3 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
disableChevron
|
||||
/>
|
||||
{/* Hide if there is a parent ID */}
|
||||
@@ -474,6 +477,7 @@ const TeamListCollapsible = ({ teamFeatures }: { teamFeatures?: Record<number, T
|
||||
name={t("billing")}
|
||||
href={`/settings/teams/${team.id}/billing`}
|
||||
textClassNames="px-3 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
disableChevron
|
||||
/>
|
||||
</>
|
||||
@@ -482,6 +486,7 @@ const TeamListCollapsible = ({ teamFeatures }: { teamFeatures?: Record<number, T
|
||||
name={t("settings")}
|
||||
href={`/settings/teams/${team.id}/settings`}
|
||||
textClassNames="px-3 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
disableChevron
|
||||
/>
|
||||
</>
|
||||
@@ -643,6 +648,7 @@ const SettingsSidebarContainer = ({
|
||||
name={t("add_a_team")}
|
||||
href={`${WEBAPP_URL}/settings/teams/new`}
|
||||
textClassNames="px-3 items-center mt-2 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
icon="plus"
|
||||
disableChevron
|
||||
/>
|
||||
@@ -744,12 +750,14 @@ const SettingsSidebarContainer = ({
|
||||
name={t("profile")}
|
||||
href={`/settings/organizations/teams/other/${otherTeam.id}/profile`}
|
||||
textClassNames="px-3 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
disableChevron
|
||||
/>
|
||||
<VerticalTabItem
|
||||
name={t("members")}
|
||||
href={`/settings/organizations/teams/other/${otherTeam.id}/members`}
|
||||
textClassNames="px-3 text-emphasis font-medium text-sm"
|
||||
className="me-5 h-7 w-auto !px-2"
|
||||
disableChevron
|
||||
/>
|
||||
<>
|
||||
|
||||
@@ -81,7 +81,7 @@ describe("EditLocationDialog", () => {
|
||||
},
|
||||
{
|
||||
value: "integrations:daily",
|
||||
label: "Cal Video (Global)",
|
||||
label: "Cal Video (Default)",
|
||||
disabled: false,
|
||||
icon: "/app-store/dailyvideo/icon.svg",
|
||||
slug: "daily-video",
|
||||
|
||||
@@ -426,6 +426,7 @@ export default function Signup({
|
||||
id="signup-email"
|
||||
{...register("email")}
|
||||
label={t("email")}
|
||||
placeholder="john@doe.com"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
disabled={prepopulateFormValues?.email}
|
||||
@@ -522,8 +523,8 @@ export default function Signup({
|
||||
usernameTaken
|
||||
}>
|
||||
{premiumUsername && !usernameTaken
|
||||
? `${t("create_account")} (${getPremiumPlanPriceValue()})`
|
||||
: t("create_account")}
|
||||
? `${t("get_started")} (${getPremiumPlanPriceValue()})`
|
||||
: t("get_started")}
|
||||
</Button>
|
||||
)}
|
||||
</Form>
|
||||
|
||||
@@ -239,7 +239,7 @@ test.describe("Event Types tests", () => {
|
||||
await gotoFirstEventType(page);
|
||||
|
||||
await page.getByTestId("location-select").click();
|
||||
await page.locator(`text="Cal Video (Global)"`).click();
|
||||
await page.locator(`text="Cal Video (Default)"`).click();
|
||||
|
||||
await saveEventType(page);
|
||||
await gotoBookingPage(page);
|
||||
@@ -282,7 +282,7 @@ test.describe("Event Types tests", () => {
|
||||
await selectAttendeePhoneNumber(page);
|
||||
|
||||
// Add Cal Video location
|
||||
await addAnotherLocation(page, "Cal Video (Global)");
|
||||
await addAnotherLocation(page, "Cal Video (Default)");
|
||||
|
||||
await saveEventType(page);
|
||||
|
||||
@@ -496,6 +496,9 @@ test.describe("Event Types tests", () => {
|
||||
});
|
||||
await test.step("should open first eventType and check Interface Language", async () => {
|
||||
await gotoFirstEventType(page);
|
||||
// Go to Advanced tab
|
||||
await page.click("[data-testid=vertical-tab-event_advanced_tab_title]");
|
||||
await page.click("[data-testid=event-interface-language-toggle]");
|
||||
const interfaceLanguageValue = page
|
||||
.getByTestId("event-interface-language")
|
||||
.locator('div[class$="-singleValue"]');
|
||||
@@ -518,6 +521,9 @@ test.describe("Event Types tests", () => {
|
||||
|
||||
await test.step("should open first eventType and change Interface Language to Deutsche", async () => {
|
||||
await gotoFirstEventType(page);
|
||||
// Go to Advanced tab and enable offerSeats
|
||||
await page.click("[data-testid=vertical-tab-event_advanced_tab_title]");
|
||||
await page.click("[data-testid=event-interface-language-toggle]");
|
||||
await page.getByTestId("event-interface-language").click();
|
||||
await page.locator(`text="Deutsch"`).click();
|
||||
await saveEventType(page);
|
||||
@@ -574,6 +580,9 @@ test.describe("Event Types tests", () => {
|
||||
await page.goto("/event-types");
|
||||
await page.waitForSelector('[data-testid="event-types"]');
|
||||
await gotoFirstEventType(page);
|
||||
// Go to Advanced tab and enable offerSeats
|
||||
await page.click("[data-testid=vertical-tab-event_advanced_tab_title]");
|
||||
await page.click("[data-testid=event-interface-language-toggle]");
|
||||
await page.getByTestId("event-interface-language").click();
|
||||
await page.getByTestId("select-option-es").click();
|
||||
await saveEventType(page);
|
||||
|
||||
@@ -198,7 +198,7 @@ export async function expectSegmentCleared(page: Page) {
|
||||
// Check that no segment is selected (button shows default text)
|
||||
const segmentSelect = page.getByTestId("filter-segment-select");
|
||||
const buttonText = await segmentSelect.textContent();
|
||||
expect(buttonText?.trim()).toEqual("Segment");
|
||||
expect(buttonText?.trim()).toEqual("Saved filters");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -199,6 +199,7 @@ export function createBookingPageFixture(page: Page) {
|
||||
await expect(eventTypePage.getByTestId("time")).toHaveCount(count);
|
||||
},
|
||||
getAITranslationToggleDisabled: async () => {
|
||||
await page.click("[data-testid=vertical-tab-event_advanced_tab_title]");
|
||||
await page.waitForSelector('[data-testid="ai_translation_toggle"]', {
|
||||
timeout: 5000,
|
||||
state: "attached",
|
||||
@@ -207,6 +208,7 @@ export function createBookingPageFixture(page: Page) {
|
||||
return (await toggle.getAttribute("disabled")) !== null;
|
||||
},
|
||||
toggleAITranslation: async () => {
|
||||
await page.click("[data-testid=vertical-tab-event_advanced_tab_title]");
|
||||
await page.getByTestId("ai_translation_toggle").click();
|
||||
},
|
||||
updateEventTypeDescription: async (description: string) => {
|
||||
|
||||
@@ -81,10 +81,13 @@ test.describe("Managed Event Types", () => {
|
||||
await page.goto(`/event-types/${managedEvent.id}?tabName=setup`);
|
||||
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();
|
||||
await optionText.click();
|
||||
const targetText = (await localize("en"))("organizer_default_conferencing_app");
|
||||
const options = page.locator('[data-testid="location-select-item-conferencing"]');
|
||||
const targetOption = options.locator(`text=${targetText}`);
|
||||
await expect(targetOption).toBeVisible();
|
||||
await targetOption.click();
|
||||
await saveAndWaitForResponse(page);
|
||||
|
||||
await page.getByTestId("vertical-tab-assignment").click();
|
||||
@@ -190,7 +193,7 @@ test.describe("Managed Event Types", () => {
|
||||
});
|
||||
|
||||
const MANAGED_EVENT_TABS: { slug: string; locator: (page: Page) => Locator | Promise<Locator> }[] = [
|
||||
{ slug: "setup", locator: (page) => getByKey(page, "translate_description_button") },
|
||||
{ slug: "setup", locator: (page) => getByKey(page, "allow_multiple_durations") },
|
||||
{
|
||||
slug: "team",
|
||||
locator: (page) => getByKey(page, "automatically_add_all_team_members"),
|
||||
|
||||
@@ -321,6 +321,7 @@
|
||||
"secret_meeting": "Secret Meeting",
|
||||
"login_instead": "Login instead",
|
||||
"create_account": "Create Account",
|
||||
"get_started": "Get started",
|
||||
"confirm_password": "Confirm password",
|
||||
"reset_your_password": "Set your new password with the instructions sent to your email address.",
|
||||
"org_banner_instructions": "Please upload image of {{width}} width and {{height}} height.",
|
||||
@@ -958,7 +959,7 @@
|
||||
"light_event_type_color": "Event Type Color (Light Theme)",
|
||||
"dark_event_type_color": "Event Type Color (Dark Theme)",
|
||||
"file_not_named": "File is not named [idOrSlug]/[user]",
|
||||
"create_team": "Create Team",
|
||||
"create_team": "Create team",
|
||||
"name": "Name",
|
||||
"nameless_team": "Nameless Team",
|
||||
"oauth_clients": "OAuth Clients",
|
||||
@@ -1019,6 +1020,7 @@
|
||||
"attendees": "Attendees",
|
||||
"add_attendees": "Add attendees",
|
||||
"show_advanced_settings": "Show advanced settings",
|
||||
"hide_advanced_settings": "Hide advanced settings",
|
||||
"event_name": "Event Name",
|
||||
"event_name_in_calendar": "Calendar event name",
|
||||
"event_name_tooltip": "The name that will appear in calendars",
|
||||
@@ -1231,7 +1233,7 @@
|
||||
"contact_sales": "Contact Sales",
|
||||
"error_404": "Error 404",
|
||||
"default": "Default",
|
||||
"set_to_default": "Set to Default",
|
||||
"set_to_default": "Set as Default",
|
||||
"new_schedule_btn": "New schedule",
|
||||
"add_new_schedule": "Add a new schedule",
|
||||
"add_new_calendar": "Add a new calendar",
|
||||
@@ -1329,7 +1331,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 from multiple durations",
|
||||
"allow_multiple_durations": "Allow 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",
|
||||
@@ -2689,7 +2691,7 @@
|
||||
"enterprise": "Enterprise",
|
||||
"enterprise_description": "Upgrade to Enterprise to create your Organization",
|
||||
"create_your_org": "Create your Organization",
|
||||
"create_org": "Create Organization",
|
||||
"create_org": "Create organization",
|
||||
"create_your_org_description": "Upgrade to Organizations and receive a subdomain, unified billing, Insights, extensive whitelabeling and more",
|
||||
"create_your_enterprise_description": "Upgrade to Enterprise and get access to Active Directory Sync, SCIM Automatic User provisioning, Cal.ai Voice Agents, Admin APIs and more!",
|
||||
"other_payment_app_enabled": "You can only enable one payment app per event type",
|
||||
@@ -2923,6 +2925,7 @@
|
||||
"proceeding_agreement": "By proceeding, you agree to our",
|
||||
"terms": "Terms",
|
||||
"always_show_x_days": "Always {{x}} days available",
|
||||
"always_show_x_days_description": "Automatically moves the {{x}}-day booking window forward each day, ensuring your calendar always shows the next {{x}} days of available slots.",
|
||||
"team_subscription_cancelled_successfully": "Team subscription cancelled successfully",
|
||||
"team_subscription_cancellation_error": "Error while cancelling the team subscription",
|
||||
"unable_to_subscribe_to_the_platform": "An error occurred while trying to subscribe to the platform plan, please try again later",
|
||||
@@ -3144,7 +3147,8 @@
|
||||
"filter_operator_ends_with": "Ends with",
|
||||
"filter_operator_is_empty": "Is empty",
|
||||
"filter_operator_not_empty": "Not empty",
|
||||
"translate_description_button": "Translate title/description to the visitor's browser language using AI",
|
||||
"translate_description_button": "Auto translate title and description",
|
||||
"translate_description_button_description": "Automatically translate titles and descriptions to the visitor’s browser language using AI.",
|
||||
"rr_distribution_method": "Distribution",
|
||||
"rr_distribution_method_description": "Allows for optimising distribution for maximum availability or to aim for a more balanced assignment.",
|
||||
"rr_distribution_method_availability_title": "Maximize availability",
|
||||
@@ -3310,6 +3314,7 @@
|
||||
"seats_doesnt_support_recurring": "Seats feature doesn't support recurring event. Disable seats feature to make it recurring.",
|
||||
"recurring_event_seats_error": "Recurring event doesn't support seats feature. Disable seats feature or make the event non-recurring.",
|
||||
"segment": "Segment",
|
||||
"saved_filters": "Saved filters",
|
||||
"rename": "Rename",
|
||||
"rename_segment": "Rename Segment",
|
||||
"delete_segment": "Delete Segment",
|
||||
@@ -3339,6 +3344,7 @@
|
||||
"picklist": "Picklist",
|
||||
"most_cancelled_bookings": "Most Cancelled",
|
||||
"interface_language": "Interface Language",
|
||||
"interface_language_description": "Set your preferred language for the booking interface",
|
||||
"visitors_browser_language": "Visitor's browser language",
|
||||
"name_or_email": "Name or Email",
|
||||
"salesforce_round_robin_skip_fallback_to_lead_owner": "If no contact is found, fallback to lead owner if it exists",
|
||||
@@ -3571,8 +3577,8 @@
|
||||
"rr_load_balancing_disabled_with_groups": "Load Balancing is not available with Round Robin Groups",
|
||||
"round_robin_settings_description": "Customize the default round robin settings for this team",
|
||||
"round_robin_settings_updated_successfully": "Round Robin settings updated successfully",
|
||||
"booking_creation_time": "Booking Creation Time",
|
||||
"meeting_start_time": "Meeting Start Time",
|
||||
"booking_creation_time": "Booking creation time",
|
||||
"meeting_start_time": "Meeting start time",
|
||||
"members_affected_by_disabling_delegation_credential": "Affected members",
|
||||
"no_members_affected_by_disabling_delegation_credential": "No members affected by disabling delegation credential",
|
||||
"download_expense_log": "Download Expense Log",
|
||||
|
||||
@@ -68,7 +68,7 @@ function getApps(credentials: CredentialDataWithTeamName[], filterOnCredentials?
|
||||
delegatedToId: null,
|
||||
delegationCredentialId: null,
|
||||
team: {
|
||||
name: "Global",
|
||||
name: "Default",
|
||||
},
|
||||
};
|
||||
logger.debug(
|
||||
|
||||
@@ -123,7 +123,7 @@ function CategoryTab({ selectedCategory, categories, searchText, onCategoryChang
|
||||
selectedCategory === cat ? "bg-emphasis text-default" : "bg-muted text-emphasis",
|
||||
"hover:bg-emphasis rounded-md px-4 py-2.5 text-sm font-medium transition hover:cursor-pointer"
|
||||
)}>
|
||||
{cat[0].toUpperCase() + cat.slice(1)}
|
||||
{cat === "crm" ? cat.toUpperCase() : cat[0].toUpperCase() + cat.slice(1)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -19,6 +19,7 @@ import { Badge } from "@calcom/ui/components/badge";
|
||||
import { Button } from "@calcom/ui/components/button";
|
||||
import type { ButtonProps } from "@calcom/ui/components/button";
|
||||
import { showToast } from "@calcom/ui/components/toast";
|
||||
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
||||
|
||||
interface AppCardProps {
|
||||
app: App;
|
||||
@@ -119,14 +120,14 @@ export function AppCard({ app, credentials, searchText, userAdminTeams }: AppCar
|
||||
</div> */}
|
||||
<p
|
||||
className="text-default mt-2 flex-grow text-sm"
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{ __html: markdownToSafeHTML(app.description) }}
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
display: "-webkit-box",
|
||||
WebkitBoxOrient: "vertical",
|
||||
WebkitLineClamp: "3",
|
||||
}}>
|
||||
{app.description}
|
||||
</p>
|
||||
}}/>
|
||||
|
||||
<div className="mt-5 flex max-w-full flex-row justify-between gap-2">
|
||||
<Button
|
||||
|
||||
@@ -74,15 +74,15 @@ function ColumnVisibilityButtonComponent<TData>(
|
||||
})}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
<CommandSeparator />
|
||||
<CommandSeparator className="mb-0" />
|
||||
<CommandGroup>
|
||||
<CommandItem
|
||||
onSelect={() => {
|
||||
allColumns.forEach((column) => column.toggleVisibility(true));
|
||||
}}
|
||||
className={classNames(
|
||||
"w-full justify-center text-center",
|
||||
buttonClasses({ color: "secondary" })
|
||||
buttonClasses({ color: "secondary" }),
|
||||
"w-full justify-center text-center cursor-pointer mt-0"
|
||||
)}>
|
||||
{t("show_all_columns")}
|
||||
</CommandItem>
|
||||
|
||||
@@ -155,11 +155,11 @@ export function FilterSegmentSelect() {
|
||||
StartIcon="list-filter"
|
||||
EndIcon="chevron-down"
|
||||
data-testid="filter-segment-select">
|
||||
{selectedSegment?.name || t("segment")}
|
||||
{selectedSegment?.name || t("saved_filters")}
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuPortal>
|
||||
<DropdownMenuContent align="start" className="w-60" data-testid="filter-segment-select-content">
|
||||
<DropdownMenuContent align="end" className="w-60" data-testid="filter-segment-select-content">
|
||||
{segmentGroups.length === 0 && <p className="text-subtle px-3 py-1">{t("no_segments")}</p>}
|
||||
|
||||
{segmentGroups.map((group, index) => (
|
||||
|
||||
@@ -45,7 +45,7 @@ const MakeTeamPrivateSwitch = ({
|
||||
setTeamPrivate(checked);
|
||||
mutation.mutate({ id: teamId, isPrivate: checked });
|
||||
}}
|
||||
switchContainerClassName="my-6"
|
||||
switchContainerClassName="mt-6"
|
||||
data-testid="make-team-private-check"
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -229,7 +229,7 @@ export default function WorkflowListPage({ workflows }: Props) {
|
||||
<div>
|
||||
<div className="hidden md:block">
|
||||
{workflow.team?.name && (
|
||||
<Badge className="mr-4 mt-1 p-[1px] px-2" variant="gray">
|
||||
<Badge className="mr-4 mt-1 mb-2 p-[1px] px-2" variant="gray">
|
||||
<Avatar
|
||||
alt={workflow.team?.name || ""}
|
||||
href={
|
||||
|
||||
@@ -11,132 +11,159 @@ import { TextField } from "@calcom/ui/components/form";
|
||||
import { SettingsToggle } from "@calcom/ui/components/form";
|
||||
|
||||
import LocationSettingsContainer from "./LocationSettingsContainer";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
import { useState } from "react";
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
|
||||
const CalVideoSettings = ({ calVideoSettings }: { calVideoSettings?: CalVideoSettingsType }) => {
|
||||
const { t } = useLocale();
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const isPlatform = useIsPlatform();
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
const [parent] = useAutoAnimate<HTMLDivElement>();
|
||||
return (
|
||||
<LocationSettingsContainer>
|
||||
<Controller
|
||||
name="calVideoSettings.disableRecordingForGuests"
|
||||
defaultValue={!!calVideoSettings?.disableRecordingForGuests}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_recording_for_guests")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
<>
|
||||
<Tooltip content="expandable" side="right" className="lg:hidden">
|
||||
<button
|
||||
aria-expanded={isExpanded}
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className={classNames(
|
||||
"todesktop:py-[7px] text-default group flex w-full items-center rounded-md px-2 py-1.5 text-sm font-medium transition",
|
||||
"[&[aria-current='page']]:!bg-transparent",
|
||||
"[&[aria-current='page']]:text-emphasis mt-0.5 text-sm",
|
||||
)}>
|
||||
<span className="hidden w-full justify-between truncate text-ellipsis lg:flex">
|
||||
{!isExpanded ? t("show_advanced_settings") : t("hide_advanced_settings")}
|
||||
</span>
|
||||
<Icon name={isExpanded ? "chevron-up" : "chevron-down"} className="ml-auto h-4 w-4" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<div ref={parent}>
|
||||
{isExpanded && (
|
||||
<LocationSettingsContainer>
|
||||
<Controller
|
||||
name="calVideoSettings.disableRecordingForGuests"
|
||||
defaultValue={!!calVideoSettings?.disableRecordingForGuests}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_recording_for_guests")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="calVideoSettings.disableRecordingForOrganizer"
|
||||
defaultValue={!!calVideoSettings?.disableRecordingForOrganizer}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_recording_for_organizer")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
<Controller
|
||||
name="calVideoSettings.disableRecordingForOrganizer"
|
||||
defaultValue={!!calVideoSettings?.disableRecordingForOrganizer}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_recording_for_organizer")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="calVideoSettings.enableAutomaticRecordingForOrganizer"
|
||||
defaultValue={!!calVideoSettings?.enableAutomaticRecordingForOrganizer}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("enable_automatic_recording")}
|
||||
labelClassName="text-sm"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="calVideoSettings.enableAutomaticRecordingForOrganizer"
|
||||
defaultValue={!!calVideoSettings?.enableAutomaticRecordingForOrganizer}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("enable_automatic_recording")}
|
||||
labelClassName="text-sm"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
|
||||
<Controller
|
||||
name="calVideoSettings.enableAutomaticTranscription"
|
||||
defaultValue={!!calVideoSettings?.enableAutomaticTranscription}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("enable_automatic_transcription")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
<Controller
|
||||
name="calVideoSettings.enableAutomaticTranscription"
|
||||
defaultValue={!!calVideoSettings?.enableAutomaticTranscription}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("enable_automatic_transcription")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="calVideoSettings.disableTranscriptionForGuests"
|
||||
defaultValue={!!calVideoSettings?.disableTranscriptionForGuests}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_transcription_for_guests")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="calVideoSettings.disableTranscriptionForGuests"
|
||||
defaultValue={!!calVideoSettings?.disableTranscriptionForGuests}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_transcription_for_guests")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="calVideoSettings.disableTranscriptionForOrganizer"
|
||||
defaultValue={!!calVideoSettings?.disableTranscriptionForOrganizer}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_transcription_for_organizer")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
)}
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="calVideoSettings.disableTranscriptionForOrganizer"
|
||||
defaultValue={!!calVideoSettings?.disableTranscriptionForOrganizer}
|
||||
render={({ field: { onChange, value } }) => {
|
||||
return (
|
||||
<SettingsToggle
|
||||
title={t("disable_transcription_for_organizer")}
|
||||
labelClassName="text-sm leading-6 whitespace-normal break-words"
|
||||
checked={value}
|
||||
onCheckedChange={onChange}
|
||||
Badge={<UpgradeTeamsBadge checkForActiveStatus />}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
|
||||
<TextField
|
||||
label={t("enter_redirect_url_on_exit_description")}
|
||||
defaultValue={calVideoSettings?.redirectUrlOnExit || ""}
|
||||
data-testid="calVideoSettings.redirectUrlOnExit"
|
||||
containerClassName="mt-4"
|
||||
className="leading-6"
|
||||
{...formMethods.register("calVideoSettings.redirectUrlOnExit", {
|
||||
setValueAs: (v) => (!v || v.trim() === "" ? null : v),
|
||||
})}
|
||||
/>
|
||||
<ErrorMessage
|
||||
errors={formMethods.formState.errors?.calVideoSettings}
|
||||
name="redirectUrlOnExit"
|
||||
className={classNames("text-error text-sm")}
|
||||
as="div"
|
||||
id="calVideoSettings.redirectUrlOnExit-error"
|
||||
/>
|
||||
</LocationSettingsContainer>
|
||||
<TextField
|
||||
label={t("enter_redirect_url_on_exit_description")}
|
||||
defaultValue={calVideoSettings?.redirectUrlOnExit || ""}
|
||||
data-testid="calVideoSettings.redirectUrlOnExit"
|
||||
containerClassName="mt-4"
|
||||
className="leading-6"
|
||||
{...formMethods.register("calVideoSettings.redirectUrlOnExit", {
|
||||
setValueAs: (v) => (!v || v.trim() === "" ? null : v),
|
||||
})}
|
||||
/>
|
||||
<ErrorMessage
|
||||
errors={formMethods.formState.errors?.calVideoSettings}
|
||||
name="redirectUrlOnExit"
|
||||
className={classNames("text-error text-sm")}
|
||||
as="div"
|
||||
id="calVideoSettings.redirectUrlOnExit-error"
|
||||
/>
|
||||
</LocationSettingsContainer>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ import {
|
||||
CheckboxField,
|
||||
Switch,
|
||||
SettingsToggle,
|
||||
Select,
|
||||
} from "@calcom/ui/components/form";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
|
||||
@@ -120,6 +121,7 @@ export type EventAdvancedBaseProps = Pick<EventTypeSetupProps, "eventType" | "te
|
||||
>;
|
||||
isUserLoading?: boolean;
|
||||
showToast: (message: string, variant: "success" | "warning" | "error") => void;
|
||||
orgId: number | null;
|
||||
customClassNames?: EventAdvancedTabCustomClassNames;
|
||||
};
|
||||
|
||||
@@ -130,6 +132,7 @@ export type EventAdvancedTabProps = EventAdvancedBaseProps & {
|
||||
error: unknown;
|
||||
};
|
||||
showBookerLayoutSelector: boolean;
|
||||
localeOptions?: { value: string; label: string }[];
|
||||
verifiedEmails?: string[];
|
||||
};
|
||||
|
||||
@@ -253,6 +256,11 @@ const destinationCalendarComponents = {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!showConnectedCalendarSettings && (
|
||||
<p className="text-emphasis mb-2 block text-sm font-medium leading-none">
|
||||
{t("add_to_calendar")}
|
||||
</p>
|
||||
)}
|
||||
{!useEventTypeDestinationCalendarEmail &&
|
||||
verifiedSecondaryEmails.length > 0 &&
|
||||
!isTeamEventType && (
|
||||
@@ -411,6 +419,8 @@ export const EventAdvancedTab = ({
|
||||
showBookerLayoutSelector,
|
||||
customClassNames,
|
||||
verifiedEmails,
|
||||
orgId,
|
||||
localeOptions,
|
||||
}: EventAdvancedTabProps) => {
|
||||
const isPlatform = useIsPlatform();
|
||||
const platformContext = useAtomsContext();
|
||||
@@ -423,6 +433,9 @@ export const EventAdvancedTab = ({
|
||||
!!formMethods.getValues("multiplePrivateLinks") &&
|
||||
formMethods.getValues("multiplePrivateLinks")?.length !== 0
|
||||
);
|
||||
const [interfaceLanguageVisible, setInterfaceLanguageVisible] = useState(
|
||||
!!formMethods.getValues("interfaceLanguage")
|
||||
);
|
||||
const [redirectUrlVisible, setRedirectUrlVisible] = useState(!!formMethods.getValues("successRedirectUrl"));
|
||||
|
||||
const bookingFields: Prisma.JsonObject = {};
|
||||
@@ -457,6 +470,10 @@ export const EventAdvancedTab = ({
|
||||
formMethods.getValues("metadata")?.apps?.stripe?.paymentOption === "HOLD";
|
||||
|
||||
const isRecurringEvent = !!formMethods.getValues("recurringEvent");
|
||||
const interfaceLanguageOptions =
|
||||
localeOptions && localeOptions.length > 0
|
||||
? [{ label: t("visitors_browser_language"), value: "" }, ...localeOptions]
|
||||
: [];
|
||||
|
||||
const isRoundRobinEventType =
|
||||
eventType.schedulingType && eventType.schedulingType === SchedulingType.ROUND_ROBIN;
|
||||
@@ -481,11 +498,12 @@ export const EventAdvancedTab = ({
|
||||
);
|
||||
};
|
||||
|
||||
const { isChildrenManagedEventType, isManagedEventType, shouldLockDisableProps } = useLockedFieldsManager({
|
||||
eventType,
|
||||
translate: t,
|
||||
formMethods,
|
||||
});
|
||||
const { isChildrenManagedEventType, isManagedEventType, shouldLockDisableProps, shouldLockIndicator } =
|
||||
useLockedFieldsManager({
|
||||
eventType,
|
||||
translate: t,
|
||||
formMethods,
|
||||
});
|
||||
const eventNamePlaceholder = getEventName({
|
||||
...eventNameObject,
|
||||
eventName: formMethods.watch("eventName"),
|
||||
@@ -726,6 +744,69 @@ export const EventAdvancedTab = ({
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="autoTranslateDescriptionEnabled"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<SettingsToggle
|
||||
labelClassName="text-sm"
|
||||
title={t("translate_description_button")}
|
||||
checked={value}
|
||||
onCheckedChange={(e) => onChange(e)}
|
||||
disabled={!orgId}
|
||||
tooltip={!orgId ? t("orgs_upgrade_to_enable_feature") : undefined}
|
||||
data-testid="ai_translation_toggle"
|
||||
toggleSwitchAtTheEnd={true}
|
||||
switchContainerClassName="border-subtle rounded-lg border py-6 px-4 sm:px-6"
|
||||
description={t("translate_description_button_description")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{!isPlatform && (
|
||||
<Controller
|
||||
name="interfaceLanguage"
|
||||
control={formMethods.control}
|
||||
defaultValue={eventType.interfaceLanguage ?? ""}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<SettingsToggle
|
||||
labelClassName="text-sm"
|
||||
toggleSwitchAtTheEnd={true}
|
||||
switchContainerClassName={classNames(
|
||||
"border-subtle rounded-lg border py-6 px-4 sm:px-6",
|
||||
interfaceLanguageVisible && "rounded-b-none"
|
||||
)}
|
||||
childrenClassName="lg:ml-0"
|
||||
data-testid="event-interface-language-toggle"
|
||||
title={t("interface_language")}
|
||||
description={t("interface_language_description")}
|
||||
checked={interfaceLanguageVisible}
|
||||
{...shouldLockIndicator("interfaceLanguage")}
|
||||
onCheckedChange={(e) => {
|
||||
setInterfaceLanguageVisible(e);
|
||||
if (!e) {
|
||||
// disables the setting
|
||||
formMethods.setValue("interfaceLanguage", null, { shouldDirty: true });
|
||||
} else {
|
||||
// "" is default value which means visitors browser language
|
||||
formMethods.setValue("interfaceLanguage", "", { shouldDirty: true });
|
||||
}
|
||||
}}>
|
||||
<div className="border-subtle rounded-b-lg border border-t-0 p-6">
|
||||
<Select<{ label: string; value: string }>
|
||||
data-testid="event-interface-language"
|
||||
className="capitalize"
|
||||
options={interfaceLanguageOptions}
|
||||
onChange={(option) => {
|
||||
onChange(option?.value);
|
||||
}}
|
||||
value={interfaceLanguageOptions.find((option) => option.value === value)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsToggle>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<Controller
|
||||
name="requiresBookerEmailVerification"
|
||||
render={({ field: { value, onChange } }) => (
|
||||
|
||||
@@ -31,6 +31,8 @@ import {
|
||||
} from "@calcom/ui/components/form";
|
||||
|
||||
import MaxActiveBookingsPerBookerController from "./MaxActiveBookingsPerBookerController";
|
||||
import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
|
||||
type IPeriodType = (typeof PeriodType)[keyof typeof PeriodType];
|
||||
|
||||
@@ -248,6 +250,7 @@ function RollingLimitRadioItem({
|
||||
<span className="me-2 ms-2"> {t("into_the_future")}</span>
|
||||
</div>
|
||||
<div className="-ml-6 flex flex-col py-2">
|
||||
<div className="flex items-center">
|
||||
<CheckboxField
|
||||
checked={!!rollingExcludeUnavailableDays}
|
||||
disabled={isDisabled}
|
||||
@@ -270,6 +273,15 @@ function RollingLimitRadioItem({
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<Tooltip content={t("always_show_x_days_description", {
|
||||
x: periodDaysWatch,
|
||||
})}>
|
||||
<Icon
|
||||
name="info"
|
||||
className="text-default hover:text-attention hover:bg-attention ms-1 inline h-4 w-4 rounded-md"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -72,18 +72,12 @@ export const EventSetupTab = (
|
||||
const formMethods = useFormContext<FormValues>();
|
||||
const { eventType, team, urlPrefix, hasOrgBranding, customClassNames, orgId } = props;
|
||||
|
||||
const interfaceLanguageOptions =
|
||||
props.localeOptions && props.localeOptions.length > 0
|
||||
? [{ label: t("visitors_browser_language"), value: "" }, ...props.localeOptions]
|
||||
: [];
|
||||
|
||||
const [multipleDuration, setMultipleDuration] = useState(
|
||||
formMethods.getValues("metadata")?.multipleDuration
|
||||
);
|
||||
const [firstRender, setFirstRender] = useState(true);
|
||||
|
||||
const seatsEnabled = formMethods.watch("seatsPerTimeSlotEnabled");
|
||||
const autoTranslateDescriptionEnabled = formMethods.watch("autoTranslateDescriptionEnabled");
|
||||
|
||||
const multipleDurationOptions = [
|
||||
5, 10, 15, 20, 25, 30, 45, 50, 60, 75, 80, 90, 120, 150, 180, 240, 300, 360, 420, 480,
|
||||
@@ -161,48 +155,6 @@ export const EventSetupTab = (
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{!isPlatform && (
|
||||
<div className="[&_label]:my-1 [&_label]:font-normal">
|
||||
<SettingsToggle
|
||||
title={t("translate_description_button")}
|
||||
checked={!!autoTranslateDescriptionEnabled}
|
||||
onCheckedChange={(value) => {
|
||||
formMethods.setValue("autoTranslateDescriptionEnabled", value, { shouldDirty: true });
|
||||
}}
|
||||
disabled={!orgId}
|
||||
tooltip={!orgId ? t("orgs_upgrade_to_enable_feature") : undefined}
|
||||
data-testid="ai_translation_toggle"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{!isPlatform && interfaceLanguageOptions.length > 0 && (
|
||||
<div>
|
||||
<Skeleton
|
||||
as={Label}
|
||||
loadingClassName="w-16"
|
||||
htmlFor="interfaceLanguage"
|
||||
className={customClassNames?.locationSection?.label}>
|
||||
{t("interface_language")}
|
||||
{shouldLockIndicator("interfaceLanguage")}
|
||||
</Skeleton>
|
||||
<Controller
|
||||
name="interfaceLanguage"
|
||||
control={formMethods.control}
|
||||
defaultValue={eventType.interfaceLanguage ?? ""}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<Select<{ label: string; value: string }>
|
||||
data-testid="event-interface-language"
|
||||
className="capitalize"
|
||||
options={interfaceLanguageOptions}
|
||||
onChange={(option) => {
|
||||
onChange(option?.value);
|
||||
}}
|
||||
value={interfaceLanguageOptions.find((option) => option.value === value)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<TextField
|
||||
required
|
||||
label={isPlatform ? "Slug" : t("URL")}
|
||||
@@ -362,7 +314,7 @@ export const EventSetupTab = (
|
||||
{!lengthLockedProps.disabled && (
|
||||
<div className="!mt-4 [&_label]:my-1 [&_label]:font-normal">
|
||||
<SettingsToggle
|
||||
title={t("allow_booker_to_select_duration")}
|
||||
title={t("allow_multiple_durations")}
|
||||
checked={multipleDuration !== undefined}
|
||||
disabled={seatsEnabled}
|
||||
tooltip={seatsEnabled ? t("seat_options_doesnt_multiple_durations") : undefined}
|
||||
|
||||
@@ -953,7 +953,6 @@ function VariantFields({
|
||||
onCheckedChange={(checked) => {
|
||||
fieldForm.setValue("variant", checked ? otherVariant : defaultVariant);
|
||||
}}
|
||||
classNames={{ container: "mt-2" }}
|
||||
tooltip={t("Toggle Variant")}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -51,7 +51,7 @@ export function ScheduleListItem({
|
||||
<div className="space-x-2 rtl:space-x-reverse">
|
||||
<span className="text-emphasis truncate font-medium">{schedule.name}</span>
|
||||
{schedule.isDefault && (
|
||||
<Badge variant="success" className="text-xs">
|
||||
<Badge variant="gray" className="text-xs">
|
||||
{t("default")}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { EventAdvancedBaseProps } from "@calcom/features/eventtypes/components/tabs/advanced/EventAdvancedTab";
|
||||
import { EventAdvancedTab } from "@calcom/features/eventtypes/components/tabs/advanced/EventAdvancedTab";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { localeOptions } from "@calcom/lib/i18n";
|
||||
|
||||
const EventAdvancedWebWrapper = ({ ...props }: EventAdvancedBaseProps) => {
|
||||
const connectedCalendarsQuery = trpc.viewer.calendars.connectedCalendars.useQuery();
|
||||
@@ -17,6 +18,7 @@ const EventAdvancedWebWrapper = ({ ...props }: EventAdvancedBaseProps) => {
|
||||
}}
|
||||
showBookerLayoutSelector={true}
|
||||
verifiedEmails={verifiedEmails}
|
||||
localeOptions={localeOptions}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -282,6 +282,7 @@ const EventTypeWeb = ({
|
||||
user={user}
|
||||
isUserLoading={isLoggedInUserPending}
|
||||
showToast={showToast}
|
||||
orgId={orgBranding?.id ?? null}
|
||||
/>
|
||||
),
|
||||
instant: <EventInstantTab eventType={eventType} isTeamEvent={!!team} />,
|
||||
|
||||
@@ -62,7 +62,7 @@ const VerticalTabItem = ({
|
||||
target={props.isExternalLink ? "_blank" : "_self"}
|
||||
className={classNames(
|
||||
props.textClassNames || "text-default text-sm font-medium leading-none",
|
||||
"hover:bg-subtle [&[aria-current='page']]:bg-subtle [&[aria-current='page']]:text-emphasis group-hover:text-default group flex w-full flex-row items-center rounded-md p-2 transition",
|
||||
"hover:bg-subtle [&[aria-current='page']]:bg-subtle [&[aria-current='page']]:text-emphasis group-hover:text-default group flex w-full flex-row items-center rounded-md p-2 transition ",
|
||||
props.disabled && "pointer-events-none !opacity-30",
|
||||
(isChild || !props.icon) && "ml-7",
|
||||
props.className
|
||||
|
||||
Reference in New Issue
Block a user