fix: ux audit changes (#26875)
* fix: ux audit changes
* fix: remove locale-insensitive toLowerCase() on translation
Remove .toLowerCase() call on t('minutes') translation as it is
locale-insensitive and can corrupt translations (e.g., Turkish
dotted/dotless 'i'). The translation itself should provide the
desired casing.
Addresses Cubic AI review feedback with confidence 9/10.
Co-Authored-By: unknown <>
* fix: redirect url tool tip not working
* fix: type check
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
unknown
Devin AI
parent
b0835e8ae3
commit
7226f1e4c0
@@ -159,8 +159,8 @@ export default function RoutingForms({ appUrl }: { appUrl: string }) {
|
||||
subtitle={t("routing_forms_description")}>
|
||||
<UpgradeTip
|
||||
plan="team"
|
||||
title={t("teams_plan_required")}
|
||||
description={t("routing_forms_are_a_great_way")}
|
||||
title={t("routing_that_grows_with_you")}
|
||||
description={t("routing_forms_upgrade_description")}
|
||||
features={features}
|
||||
background="/tips/routing-forms"
|
||||
isParentLoading={<SkeletonLoaderTeamList />}
|
||||
@@ -168,7 +168,7 @@ export default function RoutingForms({ appUrl }: { appUrl: string }) {
|
||||
<div className="stack-y-2 rtl:space-x-reverse sm:space-x-2">
|
||||
<ButtonGroup>
|
||||
<Button color="primary" href={`${WEBAPP_URL}/settings/teams/new`}>
|
||||
{t("upgrade")}
|
||||
{t("get_started")}
|
||||
</Button>
|
||||
<Button color="minimal" href="https://cal.com/routing" target="_blank">
|
||||
{t("learn_more")}
|
||||
|
||||
@@ -169,8 +169,8 @@ export function CalendarListContainer({
|
||||
})}
|
||||
description={t(`no_category_apps_description_calendar`)}
|
||||
buttonRaw={
|
||||
<Button color="secondary" data-testid="connect-calendar-apps" href="/apps/categories/calendar">
|
||||
{t(`connect_calendar_apps`)}
|
||||
<Button EndIcon="external-link" color="secondary" data-testid="connect-calendar-apps" href="/apps/categories/calendar">
|
||||
{t("connect_your_first_calendar")}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -173,10 +173,7 @@ export const FormActionsDropdown = ({
|
||||
type="button"
|
||||
variant="icon"
|
||||
color="secondary"
|
||||
className={classNames(
|
||||
disabled && "opacity-30",
|
||||
"ltr:radix-state-open:rounded-r-(--btn-group-radius) rtl:radix-state-open:rounded-l-(--btn-group-radius)"
|
||||
)}
|
||||
className={classNames(disabled && "opacity-30")}
|
||||
StartIcon="ellipsis"
|
||||
/>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
@@ -173,7 +173,8 @@ export function DataTable<TData>({
|
||||
width: `var(--header-${kebabCase(header?.id)}-size)`,
|
||||
}}
|
||||
className={classNames(
|
||||
"relative flex shrink-0 items-center",
|
||||
"relative flex items-center",
|
||||
column.columnDef.meta?.autoWidth ? "grow" : "shrink-0",
|
||||
"bg-cal-muted",
|
||||
column.getIsPinned() && "top-0 z-20 sm:sticky"
|
||||
)}>
|
||||
|
||||
@@ -143,7 +143,7 @@ export const AddActionDialog = (props: IAddActionDialog) => {
|
||||
return (
|
||||
<Dialog open={isOpenDialog} onOpenChange={setIsOpenDialog}>
|
||||
<DialogContent type="creation" title={t("add_action")}>
|
||||
<div className="-mt-3 space-x-3">
|
||||
<div className="space-x-3">
|
||||
<Form
|
||||
form={form}
|
||||
handleSubmit={(values) => {
|
||||
|
||||
@@ -168,7 +168,7 @@ export function WorkflowCreationDialog({
|
||||
type="button"
|
||||
onClick={handleContinue}
|
||||
loading={createMutation.isPending || isLoading}>
|
||||
{t("continue")}
|
||||
{t("create")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
|
||||
@@ -135,7 +135,7 @@ function EventTypeSingleLayout({
|
||||
formMethods.watch("hidden") ? t("show_eventtype_on_profile") : t("hide_from_profile")
|
||||
}
|
||||
side="bottom">
|
||||
<div className="self-center rounded-md p-2">
|
||||
<div className="self-center rounded-md">
|
||||
<Switch
|
||||
id="hiddenSwitch"
|
||||
disabled={eventTypesLockedByOrg}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { Tooltip } from "@calcom/ui/components/tooltip";
|
||||
import { UpgradeTeamsBadgeWebWrapper as UpgradeTeamsBadge } from "@calcom/web/modules/billing/components/UpgradeTeamsBadgeWebWrapper";
|
||||
import { useHasTeamPlan } from "@calcom/web/modules/billing/hooks/useHasPaidPlan";
|
||||
import LocationSettingsContainer from "@calcom/web/modules/event-types/components/locations/LocationSettingsContainer";
|
||||
import { InfoBadge } from "@calcom/ui/components/badge";
|
||||
|
||||
const CalVideoSettings = ({ calVideoSettings }: { calVideoSettings?: CalVideoSettingsType }) => {
|
||||
const { t } = useLocale();
|
||||
@@ -30,7 +31,7 @@ const CalVideoSettings = ({ calVideoSettings }: { calVideoSettings?: CalVideoSet
|
||||
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",
|
||||
"cursor-pointer todesktop:py-[7px] text-default group flex w-full items-center rounded-md px-2 pt-1.5 text-sm font-medium transition",
|
||||
"[&[aria-current='page']]:!bg-transparent",
|
||||
"[&[aria-current='page']]:text-emphasis mt-0.5 text-sm"
|
||||
)}>
|
||||
@@ -169,7 +170,7 @@ const CalVideoSettings = ({ calVideoSettings }: { calVideoSettings?: CalVideoSet
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label={t("enter_redirect_url_on_exit_description")}
|
||||
label={<div className="flex gap-1 items-center">{t("redirect_url")}<InfoBadge content={t("enter_redirect_url_on_exit_description")} /></div>}
|
||||
defaultValue={calVideoSettings?.redirectUrlOnExit || ""}
|
||||
data-testid="calVideoSettings.redirectUrlOnExit"
|
||||
containerClassName="mt-4"
|
||||
|
||||
@@ -24,6 +24,7 @@ import { showToast } from "@calcom/ui/components/toast";
|
||||
import { revalidateTravelSchedules } from "@calcom/web/app/cache/travelSchedule";
|
||||
|
||||
import TravelScheduleModal from "@components/settings/TravelScheduleModal";
|
||||
import { Icon } from "@calcom/ui/components/icon";
|
||||
|
||||
export type FormValues = {
|
||||
locale: {
|
||||
@@ -317,6 +318,7 @@ const GeneralView = ({ user, travelSchedules }: GeneralViewProps) => {
|
||||
)}
|
||||
/>
|
||||
<div className="text-gray text-subtle mt-2 flex items-center text-xs">
|
||||
<Icon name="info" className="mr-2" />
|
||||
{t("timeformat_profile_hint")}
|
||||
</div>
|
||||
<Controller
|
||||
|
||||
@@ -400,7 +400,7 @@ export default function Signup({
|
||||
</p>
|
||||
)}
|
||||
{IS_CALCOM && (
|
||||
<div className="mt-4">
|
||||
<div className="mt-12">
|
||||
<SelectField
|
||||
label={t("data_region")}
|
||||
value={{
|
||||
@@ -453,7 +453,7 @@ export default function Signup({
|
||||
|
||||
{/* Form Container */}
|
||||
{displayEmailForm && (
|
||||
<div className="mt-12">
|
||||
<div className="mt-6">
|
||||
<Form
|
||||
className="flex flex-col gap-4"
|
||||
form={formMethods}
|
||||
@@ -614,10 +614,10 @@ export default function Signup({
|
||||
</div>
|
||||
)}
|
||||
{!displayEmailForm && (
|
||||
<div className="mt-12">
|
||||
<div className="mt-8 flex flex-col gap-6">
|
||||
{/* Upper Row */}
|
||||
<div className="mt-6 flex flex-col gap-2 md:flex-row">
|
||||
{isGoogleLoginEnabled ? (
|
||||
{isGoogleLoginEnabled && (
|
||||
<div className="flex flex-col gap-2 md:flex-row">
|
||||
<Button
|
||||
color="primary"
|
||||
loading={isGoogleLoading}
|
||||
@@ -664,11 +664,11 @@ export default function Signup({
|
||||
}}>
|
||||
{t("continue_with_google")}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isGoogleLoginEnabled && (
|
||||
<div className="mt-6">
|
||||
<div>
|
||||
<div className="relative flex items-center">
|
||||
<div className="border-subtle grow border-t" />
|
||||
<span className="text-subtle mx-2 shrink text-sm font-normal leading-none">
|
||||
@@ -680,7 +680,7 @@ export default function Signup({
|
||||
)}
|
||||
|
||||
{/* Lower Row */}
|
||||
<div className="mt-6 flex flex-col gap-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button
|
||||
color="secondary"
|
||||
disabled={isGoogleLoading}
|
||||
|
||||
@@ -195,7 +195,7 @@ export function AvailabilityEditSheetForm(props: Props & { data: Data; isPending
|
||||
</div>
|
||||
)}
|
||||
|
||||
<SheetBody className="mt-4 flex flex-col stack-y-4">
|
||||
<SheetBody className="mt-4 flex flex-col stack-y-8">
|
||||
<div>
|
||||
<Label className="text-emphasis">
|
||||
<>{t("timezone")}</>
|
||||
@@ -234,13 +234,13 @@ export function AvailabilityEditSheetForm(props: Props & { data: Data; isPending
|
||||
</SheetBody>
|
||||
<SheetFooter>
|
||||
<SheetClose asChild>
|
||||
<Button color="secondary" className="w-full justify-center">
|
||||
<Button color="secondary" className="justify-center">
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
</SheetClose>
|
||||
<Button
|
||||
disabled={!hasEditPermission || !data.hasDefaultSchedule}
|
||||
className="w-full justify-center"
|
||||
className="justify-center"
|
||||
type="submit"
|
||||
loading={updateMutation.isPending}
|
||||
form="availability-form">
|
||||
|
||||
@@ -23,7 +23,7 @@ export function EventScheduleItem() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Label>Availability Schedule</Label>
|
||||
<Label>{t("availability_schedule")}</Label>
|
||||
<TroubleshooterListItemHeader
|
||||
className="group rounded-md border-b"
|
||||
prefixSlot={<div className="w-4 rounded-[4px] bg-black" />}
|
||||
|
||||
@@ -192,7 +192,7 @@ export function EditForm({
|
||||
<SheetHeader>
|
||||
<SheetTitle>{t("update_profile")}</SheetTitle>
|
||||
</SheetHeader>
|
||||
<SheetBody className="bg-cal-muted border-subtle mt-6 gap-4 rounded-xl border p-4">
|
||||
<SheetBody className="bg-cal-muted border-subtle mt-6 gap-4 rounded-xl border p-4 stack-y-6">
|
||||
<div className="">
|
||||
<Controller
|
||||
control={form.control}
|
||||
@@ -217,40 +217,43 @@ export function EditForm({
|
||||
/>
|
||||
</div>
|
||||
<Divider />
|
||||
<TextField label={t("name")} {...form.register("name")} className="mb-6" />
|
||||
<TextField label={t("username")} {...form.register("username")} className="mb-6" />
|
||||
<TextAreaField label={t("about")} {...form.register("bio")} className="min-h-24 mb-6" />
|
||||
<div className="mb-6">
|
||||
<Label>{t("role")}</Label>
|
||||
{teamRoles?.length > 0 ? (
|
||||
<SelectField
|
||||
defaultValue={membershipOptions.find(
|
||||
(option) => option.value === (selectedUser?.role ?? "MEMBER")
|
||||
)}
|
||||
value={membershipOptions.find((option) => option.value === form.watch("role"))}
|
||||
options={membershipOptions}
|
||||
onChange={(option) => {
|
||||
if (option) {
|
||||
form.setValue("role", option.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ToggleGroup
|
||||
isFullWidth
|
||||
defaultValue={selectedUser?.role ?? "MEMBER"}
|
||||
value={form.watch("role")}
|
||||
options={membershipOptions}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("role", value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-6">
|
||||
<Label>{t("timezone")}</Label>
|
||||
<TimezoneSelect value={watchTimezone ?? "America/Los_Angeles"} />
|
||||
<div className="stack-y-3">
|
||||
<TextField label={t("name")} {...form.register("name")} />
|
||||
<TextField label={t("username")} {...form.register("username")} />
|
||||
<TextAreaField label={t("about")} {...form.register("bio")} />
|
||||
<div>
|
||||
<Label>{t("role")}</Label>
|
||||
{teamRoles?.length > 0 ? (
|
||||
<SelectField
|
||||
defaultValue={membershipOptions.find(
|
||||
(option) => option.value === (selectedUser?.role ?? "MEMBER")
|
||||
)}
|
||||
value={membershipOptions.find((option) => option.value === form.watch("role"))}
|
||||
options={membershipOptions}
|
||||
onChange={(option) => {
|
||||
if (option) {
|
||||
form.setValue("role", option.value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ToggleGroup
|
||||
isFullWidth
|
||||
defaultValue={selectedUser?.role ?? "MEMBER"}
|
||||
value={form.watch("role")}
|
||||
options={membershipOptions}
|
||||
onValueChange={(value) => {
|
||||
form.setValue("role", value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Label>{t("timezone")}</Label>
|
||||
<TimezoneSelect value={watchTimezone ?? "America/Los_Angeles"} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{canEditAttributesForUser && (
|
||||
<>
|
||||
<Divider />
|
||||
@@ -262,14 +265,14 @@ export function EditForm({
|
||||
<Button
|
||||
color="secondary"
|
||||
type="button"
|
||||
className="justify-center md:w-1/5"
|
||||
className="justify-center"
|
||||
onClick={() => {
|
||||
setEditMode(false);
|
||||
}}>
|
||||
{t("cancel")}
|
||||
</Button>
|
||||
|
||||
<Button type="submit" className="w-full justify-center">
|
||||
<Button type="submit" className="justify-center">
|
||||
{t("update")}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
@@ -299,9 +302,9 @@ function AttributesList(props: { selectedUserId: number }) {
|
||||
const attribute = attributes?.find((attr) => attr.id === attributeId);
|
||||
return attribute
|
||||
? attribute.options.map((option) => ({
|
||||
value: option.id,
|
||||
label: option.value,
|
||||
}))
|
||||
value: option.id,
|
||||
label: option.value,
|
||||
}))
|
||||
: [];
|
||||
};
|
||||
|
||||
@@ -403,17 +406,17 @@ function AttributesList(props: { selectedUserId: number }) {
|
||||
const updatedOptions =
|
||||
attr.type === "MULTI_SELECT"
|
||||
? valueAsArray.map((v) => ({
|
||||
label: v.label,
|
||||
value: v.value,
|
||||
weight: v.weight || 100,
|
||||
}))
|
||||
label: v.label,
|
||||
value: v.value,
|
||||
weight: v.weight || 100,
|
||||
}))
|
||||
: [
|
||||
{
|
||||
label: valueAsArray[0].label,
|
||||
value: valueAsArray[0].value,
|
||||
weight: valueAsArray[0].weight || 100,
|
||||
},
|
||||
];
|
||||
{
|
||||
label: valueAsArray[0].label,
|
||||
value: valueAsArray[0].value,
|
||||
weight: valueAsArray[0].weight || 100,
|
||||
},
|
||||
];
|
||||
|
||||
field.onChange({
|
||||
id: attr.id,
|
||||
|
||||
@@ -1296,7 +1296,7 @@
|
||||
"apps_description": "Here you can find a list of your apps",
|
||||
"apps_listing": "App listing",
|
||||
"category_apps": "{{category}} apps",
|
||||
"app_store": "App Store",
|
||||
"app_store": "App store",
|
||||
"app_store_description": "Connecting people, technology and the workplace.",
|
||||
"connect_your_video": "Connect your video conferencing app",
|
||||
"settings": "Settings",
|
||||
@@ -1850,6 +1850,7 @@
|
||||
"apply_to_all_teams": "Apply to all team and user event types",
|
||||
"which_team_apply": "Which team will this apply to?",
|
||||
"no_workflows_description": "Workflows enable simple automation to send notifications & reminders enabling you to build processes around your events.",
|
||||
"no_workflows_description_v2": "Automate event reminders and notifications",
|
||||
"timeformat_profile_hint": "This is an internal setting and will not affect how times are displayed on public booking pages for you or anyone booking you.",
|
||||
"create_workflow": "Create a workflow",
|
||||
"do_this": "Do this",
|
||||
@@ -2050,8 +2051,8 @@
|
||||
"exchange_version_2015": "2015",
|
||||
"exchange_version_2016": "2016",
|
||||
"routing": "Routing",
|
||||
"routing_forms_description": "Create forms to direct attendees to the correct destinations",
|
||||
"routing_forms_send_email_owner": "Send Email to Owner",
|
||||
"routing_forms_description": "Create forms to direct attendees to the correct hosts",
|
||||
"routing_forms_send_email_owner": "Send email to owner",
|
||||
"routing_forms_send_email_owner_description": "Sends an email to the owner when the form is submitted",
|
||||
"routing_forms_send_email_to": "Send Email to",
|
||||
"add_new_form": "Add new form",
|
||||
@@ -2469,6 +2470,7 @@
|
||||
"no_entries_description": "Add an email/domain to get started.",
|
||||
"duplicate_email": "Email is duplicate",
|
||||
"enter_redirect_url_on_exit_description": "Enter a redirect URL to which the attendee will be sent once they leave the meeting.",
|
||||
"redirect_url": "Redirect URL",
|
||||
"booking_with_payment_cancelled": "Paying for this event is no longer possible",
|
||||
"booking_with_payment_cancelled_already_paid": "A refund for this booking payment is on its way.",
|
||||
"booking_with_payment_cancelled_refunded": "This booking payment has been refunded.",
|
||||
@@ -3130,7 +3132,7 @@
|
||||
"organization_price_per_user_month": "$37 per user per month",
|
||||
"privacy_organization_description": "Manage privacy settings for your organization",
|
||||
"privacy": "Privacy",
|
||||
"privacy_and_security": "Privacy & Security",
|
||||
"privacy_and_security": "Privacy & security",
|
||||
"team_will_be_under_org": "New teams will be under your organization",
|
||||
"add_group_name": "Add group name",
|
||||
"group_name": "Group name",
|
||||
@@ -4533,6 +4535,10 @@
|
||||
"enabled_via_auto_opt_in": "Enabled via auto opt-in",
|
||||
"account_already_exists_please_login": "An account with this email already exists. Please log in to accept the invitation.",
|
||||
"unverified_email_oauth_error": "Please verify your email address before signing in with Google or SAML. Sign in with your password to resend the verification email.",
|
||||
"availability_schedule": "Availability schedule",
|
||||
"connect_your_first_calendar": "Connect your first calendar",
|
||||
"routing_that_grows_with_you": "Routing that grows with you",
|
||||
"routing_forms_upgrade_description": "Create simple forms that guide bookings to the right person, team, or event. Start solo, then seamlessly route meetings as more people or use cases come into play. Available on the Teams plan.",
|
||||
"pbac_resource_feature_opt_in": "Feature Opt-In",
|
||||
"pbac_desc_view_feature_opt_in": "View feature opt-in settings",
|
||||
"pbac_desc_update_feature_opt_in": "Manage feature opt-in settings",
|
||||
|
||||
@@ -305,7 +305,7 @@ export const MultiOptionInput = <TFieldValues extends FieldValues>({
|
||||
color={addOptionButtonColor}
|
||||
StartIcon="plus"
|
||||
onClick={addOption}
|
||||
className="mt-4 border-none"
|
||||
className="border-none"
|
||||
disabled={disabled}>
|
||||
{addOptionLabel}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user