Files
calendar/packages/features/form/components/LocationSelect.tsx
T
853f9bc436 perf: do not import from @calcom/ui barrel file (#20184)
* Icon and IconName

* Button and ButtonGroup

* UserAvatar

* AvatarGroup

* Avatar

* WizardLayout

* Dialogs

* EmptyScreen

* showToast and TextField

* Editor

* Skeleton

* Skeleton

* TopBanner and showToast

* Button again

* more

* perf: Remove app-store reference from @calcom/ui

* more

* Fixing types

* Icon

* Fixed casing

* dropdown

* more

* Select

* more

* Badge

* List

* more

* Divider

* more

* fix

* fix type check

* refactor

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix type check

* fix

* fix

* fix

* fix

* more

* more

* more

* more

* add index file to components/command

* fix

* fix

* fix

* fix imports

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* fix build errors

* fix build errors

* fix

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2025-03-19 19:00:55 -03:00

144 lines
4.6 KiB
TypeScript

import type { GroupBase, Props, SingleValue } from "react-select";
import { components } from "react-select";
import type { EventLocationType } from "@calcom/app-store/locations";
import { useIsPlatform } from "@calcom/atoms/hooks/useIsPlatform";
import invertLogoOnDark from "@calcom/lib/invertLogoOnDark";
import { Select } from "@calcom/ui/components/form";
import { Icon } from "@calcom/ui/components/icon";
import classNames from "@calcom/ui/classNames";
export type LocationSelectCustomClassNames = {
optionIcon?: string;
optionLabel?: string;
optionWrapper?: string;
groupLabel?: string;
selectWrapper?: string;
};
export type LocationOption = {
label: string;
value: EventLocationType["type"];
icon?: string;
disabled?: boolean;
address?: string;
credentialId?: number;
teamName?: string;
customClassNames?: LocationSelectCustomClassNames;
};
export type SingleValueLocationOption = SingleValue<LocationOption>;
export type GroupOptionType = GroupBase<LocationOption>;
const OptionWithIcon = ({
icon,
label,
value,
customClassNames,
}: {
icon?: string;
label: string;
value: string;
customClassNames?: LocationSelectCustomClassNames;
}) => {
const isPlatform = useIsPlatform();
const getIconFromValue = (value: string) => {
switch (value) {
case "phone":
return <Icon name="phone" className={classNames("h-3.5 w-3.5", customClassNames?.optionIcon)} />;
case "userPhone":
return <Icon name="phone" className={classNames("h-3.5 w-3.5", customClassNames?.optionIcon)} />;
case "inPerson":
return <Icon name="map-pin" className={classNames("h-3.5 w-3.5", customClassNames?.optionIcon)} />;
case "attendeeInPerson":
return <Icon name="map-pin" className={classNames("h-3.5 w-3.5", customClassNames?.optionIcon)} />;
case "link":
return <Icon name="link" className={classNames("h-3.5 w-3.5", customClassNames?.optionIcon)} />;
case "somewhereElse":
return <Icon name="map" className={classNames("h-3.5 w-3.5", customClassNames?.optionIcon)} />;
default:
return <Icon name="video" className={classNames("h-3.5 w-3.5", customClassNames?.optionIcon)} />;
}
};
if (isPlatform) {
return (
<div className={classNames("flex items-center gap-3", customClassNames?.optionWrapper)}>
{getIconFromValue(value)}
<span className={classNames("text-sm font-medium", customClassNames?.optionLabel)}>{label}</span>
</div>
);
}
return (
<div className="flex items-center gap-3">
{icon && <img src={icon} alt="cover" className={classNames("h-3.5 w-3.5", invertLogoOnDark(icon))} />}
<span className={classNames(" text-sm font-medium")}>{label}</span>
</div>
);
};
export default function LocationSelect({
customClassNames,
...props
}: Props<LocationOption, false, GroupOptionType> & { customClassNames?: LocationSelectCustomClassNames }) {
const isPlatform = useIsPlatform();
return (
<Select<LocationOption>
name="location"
id="location-select"
data-testid="location-select"
components={{
Option: (props) => {
return (
<components.Option {...props}>
<div data-testid={`location-select-item-${props.data.value}`}>
<OptionWithIcon
icon={props.data.icon}
label={props.data.label}
value={props.data.value}
customClassNames={customClassNames}
/>
</div>
</components.Option>
);
},
SingleValue: (props) => {
return (
<components.SingleValue {...props}>
<div data-testid={`location-select-item-${props.data.value}`}>
<OptionWithIcon
icon={props.data.icon}
label={props.data.label}
value={props.data.value}
customClassNames={customClassNames}
/>
</div>
</components.SingleValue>
);
},
}}
formatOptionLabel={(e, d) => (
<div className="flex items-center gap-3">
{e.icon && !isPlatform && (
<img
src={e.icon}
alt="app-icon"
className={classNames(e.icon.includes("-dark") && "dark:invert", "h-5 w-5")}
/>
)}
<span>{e.label}</span>
</div>
)}
formatGroupLabel={(e) => (
<p className={classNames("text-default text-xs font-medium", customClassNames?.groupLabel)}>
{e.label}
</p>
)}
{...props}
/>
);
}