Fix timezone select - create two variants (#7875)
* Fix timezone select - create two variants * Remove menu is open * Timezone fixes --------- Co-authored-by: Efraín Rochín <roae.85@gmail.com>
This commit is contained in:
parent
8dd9b8d74b
commit
04c634ec4b
|
@ -1,12 +1,9 @@
|
|||
import type { FC } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import useTheme from "@calcom/lib/hooks/useTheme";
|
||||
import type { ITimezoneOption } from "@calcom/ui";
|
||||
import { TimezoneSelect } from "@calcom/ui";
|
||||
|
||||
import useMeQuery from "@lib/hooks/useMeQuery";
|
||||
|
||||
import { timeZone } from "../../lib/clock";
|
||||
|
||||
type Props = {
|
||||
|
@ -15,8 +12,6 @@ type Props = {
|
|||
|
||||
const TimeOptions: FC<Props> = ({ onSelectTimeZone }) => {
|
||||
const [selectedTimeZone, setSelectedTimeZone] = useState("");
|
||||
const query = useMeQuery();
|
||||
const userTheme = useTheme(query?.data?.theme).resolvedTheme;
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedTimeZone(timeZone());
|
||||
|
@ -28,59 +23,16 @@ const TimeOptions: FC<Props> = ({ onSelectTimeZone }) => {
|
|||
}
|
||||
}, [selectedTimeZone, onSelectTimeZone]);
|
||||
|
||||
const customStyles = {
|
||||
option: (_provided: object, state: { isSelected: boolean; isFocused: boolean }) => ({
|
||||
padding: "10px 12px !important",
|
||||
color: state.isSelected || state.isFocused ? "#101010" : "#374151",
|
||||
backgroundColor: state.isSelected ? "#E5E7EB !important" : "white",
|
||||
...(userTheme === "dark" && {
|
||||
color: state.isSelected || state.isFocused ? "white" : "#80868B",
|
||||
}),
|
||||
}),
|
||||
control: () => ({
|
||||
display: "flex",
|
||||
cursor: "pointer",
|
||||
backgroundColor: "transparent !important",
|
||||
minWidth: "5rem",
|
||||
height: "24px",
|
||||
minHeight: "24px !important",
|
||||
boxShadow: "none !important",
|
||||
}),
|
||||
singleValue: (provided: object, state: { selectProps: { menuIsOpen: boolean } }) => ({
|
||||
...provided,
|
||||
color: state.selectProps.menuIsOpen ? "#111827" : "#4B5563",
|
||||
...(userTheme === "dark" && {
|
||||
color: "#a5a5a5 !important",
|
||||
}),
|
||||
}),
|
||||
menu: (provided: object) => ({
|
||||
...provided,
|
||||
minWidth: "20rem",
|
||||
margin: "8px 0 0 -20px",
|
||||
}),
|
||||
valueContainer: (provided: object) => ({
|
||||
...provided,
|
||||
padding: "0 0 0 6px",
|
||||
}),
|
||||
dropdownIndicator: (provided: object, state: { selectProps: { menuIsOpen: boolean } }) => ({
|
||||
...provided,
|
||||
transform: state.selectProps.menuIsOpen ? "rotate(180deg)" : "",
|
||||
color: state.selectProps.menuIsOpen ? "#111827" : "#4B5563",
|
||||
marginLeft: 4,
|
||||
padding: 0,
|
||||
...(userTheme === "dark" && {
|
||||
color: "#80868B",
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
return !!selectedTimeZone ? (
|
||||
<TimezoneSelect
|
||||
id="timeZone"
|
||||
classNames={{
|
||||
singleValue: () => "dark:text-darkgray-600 text-gray-600",
|
||||
menu: () => "!w-64 max-w-[90vw]",
|
||||
}}
|
||||
variant="minimal"
|
||||
value={selectedTimeZone}
|
||||
onChange={(tz: ITimezoneOption) => setSelectedTimeZone(tz.value)}
|
||||
className="flex h-6 text-sm font-medium"
|
||||
styles={customStyles}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
|
|
@ -17,8 +17,8 @@ export function TimezoneDropdown({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="dark:focus-within:bg-darkgray-200 dark:bg-darkgray-100 dark:hover:bg-darkgray-200 -mx-[2px] !mt-3 flex w-fit max-w-[20rem] items-center rounded-[4px] px-1 py-[2px] text-sm font-medium focus-within:bg-gray-200 hover:bg-gray-100 lg:max-w-[12rem] [&_p]:focus-within:text-gray-900 dark:[&_p]:focus-within:text-white [&_svg]:focus-within:text-gray-900 dark:[&_svg]:focus-within:text-white">
|
||||
<FiGlobe className="dark:text-darkgray-600 flex h-4 w-4 text-gray-600 ltr:mr-[2px] rtl:ml-[2px]" />
|
||||
<div className="dark:focus-within:bg-darkgray-200 dark:bg-darkgray-100 dark:hover:bg-darkgray-200 !mt-3 flex w-full max-w-[20rem] items-center rounded-[4px] px-1 text-sm font-medium focus-within:bg-gray-200 hover:bg-gray-100 lg:max-w-[12rem] [&_p]:focus-within:text-gray-900 dark:[&_p]:focus-within:text-white [&_svg]:focus-within:text-gray-900 dark:[&_svg]:focus-within:text-white">
|
||||
<FiGlobe className="dark:text-darkgray-600 flex h-4 w-4 text-gray-600 ltr:mr-2 rtl:ml-2" />
|
||||
<TimeOptions onSelectTimeZone={handleSelectTimeZone} />
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -13,7 +13,12 @@ export interface ICity {
|
|||
timezone: string;
|
||||
}
|
||||
|
||||
export function TimezoneSelect({ className, components, ...props }: SelectProps) {
|
||||
export function TimezoneSelect({
|
||||
className,
|
||||
components,
|
||||
variant = "default",
|
||||
...props
|
||||
}: SelectProps & { variant?: "default" | "minimal" }) {
|
||||
const [cities, setCities] = useState<ICity[]>([]);
|
||||
const { data, isLoading } = trpc.viewer.public.cityTimezones.useQuery(undefined, {
|
||||
trpc: { context: { skipBatch: true } },
|
||||
|
@ -44,7 +49,8 @@ export function TimezoneSelect({ className, components, ...props }: SelectProps)
|
|||
formatOptionLabel={(option) => <p className="truncate">{(option as ITimezoneOption).value}</p>}
|
||||
getOptionLabel={(option) => handleOptionLabel(option as ITimezoneOption, cities)}
|
||||
classNames={{
|
||||
input: () => classNames("dark:text-darkgray-900 text-gray-900", props.classNames?.input),
|
||||
input: (state) =>
|
||||
classNames("dark:text-darkgray-900 text-gray-900", props.classNames?.input?.(state)),
|
||||
option: (state) =>
|
||||
classNames(
|
||||
"dark:bg-darkgray-100 flex cursor-pointer justify-between py-2.5 px-3 rounded-none text-gray-700 dark:text-darkgray-700",
|
||||
|
@ -55,28 +61,35 @@ export function TimezoneSelect({ className, components, ...props }: SelectProps)
|
|||
placeholder: (state) =>
|
||||
classNames("text-gray-400 text-sm dark:text-darkgray-400", state.isFocused && "hidden"),
|
||||
dropdownIndicator: () => "text-gray-600 dark:text-darkgray-400",
|
||||
control: () => classNames("", props.classNames?.control), // We remove all styling here to fit theme of booking page - no min-h also
|
||||
singleValue: () =>
|
||||
control: (state) =>
|
||||
classNames(
|
||||
variant === "default"
|
||||
? "dark:bg-darkgray-100 dark:border-darkgray-300 !min-h-9 border-gray-300 bg-white text-sm leading-4 placeholder:text-sm placeholder:font-normal focus-within:ring-2 focus-within:ring-gray-800 hover:border-gray-400 dark:focus-within:ring-darkgray-900 rounded-md border py-2 px-3"
|
||||
: "text-sm ",
|
||||
props.classNames?.control?.(state)
|
||||
), // We remove all styling here to fit theme of booking page - no min-h also
|
||||
singleValue: (state) =>
|
||||
classNames(
|
||||
"dark:text-darkgray-900 dark:placeholder:text-darkgray-500 text-black placeholder:text-gray-400",
|
||||
props.classNames?.singleValue
|
||||
props.classNames?.singleValue?.(state)
|
||||
),
|
||||
valueContainer: () =>
|
||||
valueContainer: (state) =>
|
||||
classNames(
|
||||
"dark:text-darkgray-900 dark:placeholder:text-darkgray-500 text-black placeholder:text-gray-400 flex gap-1",
|
||||
props.classNames?.valueContainer
|
||||
props.classNames?.valueContainer?.(state)
|
||||
),
|
||||
multiValue: () =>
|
||||
multiValue: (state) =>
|
||||
classNames(
|
||||
"dark:bg-darkgray-200 dark:text-darkgray-700 rounded-md bg-gray-100 text-gray-700 py-1.5 px-2 flex items-center text-sm leading-none",
|
||||
props.classNames?.multiValue
|
||||
props.classNames?.multiValue?.(state)
|
||||
),
|
||||
menu: () =>
|
||||
menu: (state) =>
|
||||
classNames(
|
||||
"dark:bg-darkgray-100 rounded-md bg-white text-sm leading-4 dark:text-white mt-1 border border-gray-200 dark:border-darkgray-200 ",
|
||||
props.classNames?.menu
|
||||
props.classNames?.menu?.(state)
|
||||
),
|
||||
menuList: () => classNames("scroll-bar scrollbar-track-w-20 rounded-md", props.classNames?.menuList),
|
||||
menuList: (state) =>
|
||||
classNames("scroll-bar scrollbar-track-w-20 rounded-md", props.classNames?.menuList?.(state)),
|
||||
indicatorsContainer: (state) =>
|
||||
classNames(
|
||||
state.selectProps.menuIsOpen
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import classNames from "classnames";
|
||||
import { components } from "react-select";
|
||||
import type { ITimezone, ITimezoneOption, Props as SelectProps } from "react-timezone-select";
|
||||
import BaseSelect, { allTimezones } from "react-timezone-select";
|
||||
|
||||
import { InputComponent } from "../components/form/select/components";
|
||||
|
||||
function TimezoneSelect({ className, ...props }: SelectProps) {
|
||||
// @TODO: remove borderRadius and haveRoundedClassName logic from theme so we use only new style
|
||||
const haveRoundedClassName = !!(className && className.indexOf("rounded-") > -1);
|
||||
const defaultBorderRadius = 2;
|
||||
|
||||
return (
|
||||
<BaseSelect
|
||||
theme={(theme) => ({
|
||||
...theme,
|
||||
...(haveRoundedClassName ? {} : { borderRadius: defaultBorderRadius }),
|
||||
colors: {
|
||||
...theme.colors,
|
||||
primary: "var(--brand-color)",
|
||||
primary50: "rgba(209 , 213, 219, var(--tw-bg-opacity))",
|
||||
primary25: "rgba(244, 245, 246, var(--tw-bg-opacity))",
|
||||
},
|
||||
})}
|
||||
styles={{
|
||||
option: (provided, state) => ({
|
||||
...provided,
|
||||
color: state.isSelected ? "var(--brand-text-color)" : "black",
|
||||
":active": {
|
||||
backgroundColor: state.isSelected ? "" : "var(--brand-color)",
|
||||
color: "var(--brand-text-color)",
|
||||
},
|
||||
}),
|
||||
}}
|
||||
timezones={{
|
||||
...allTimezones,
|
||||
"America/Asuncion": "Asuncion",
|
||||
}}
|
||||
components={{
|
||||
...components,
|
||||
IndicatorSeparator: () => null,
|
||||
Input: InputComponent,
|
||||
}}
|
||||
className={classNames("text-sm", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default TimezoneSelect;
|
||||
export type { ITimezone, ITimezoneOption };
|
Loading…
Reference in New Issue
Block a user