АРХ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: миграция простых CustomSelect-пикеров на SelectionDropdown

This commit is contained in:
DCCONSTRUCTIONS 2026-04-22 13:39:07 +03:00
parent 305357478e
commit a49e18d0e5
12 changed files with 177 additions and 191 deletions

View File

@ -23,8 +23,9 @@ import {
} from "@plane/propel/icons"; } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast"; import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { TExternalContourRequest, TNameDescriptionLoader } from "@plane/types"; import type { TExternalContourRequest, TNameDescriptionLoader } from "@plane/types";
import { ControlLink, CustomSelect, Header, Row, Tooltip } from "@plane/ui"; import { ControlLink, Header, Row, Tooltip } from "@plane/ui";
import { copyUrlToClipboard, generateWorkItemLink } from "@plane/utils"; import { copyUrlToClipboard, generateWorkItemLink } from "@plane/utils";
import { SelectionDropdown } from "@/components/common/selection-dropdown";
import { NameDescriptionUpdateStatus } from "@/components/issues/issue-update-status"; import { NameDescriptionUpdateStatus } from "@/components/issues/issue-update-status";
import { useProject } from "@/hooks/store/use-project"; import { useProject } from "@/hooks/store/use-project";
import { useProjectExternalContoursBoard } from "@/hooks/store/use-project-external-contours-board"; import { useProjectExternalContoursBoard } from "@/hooks/store/use-project-external-contours-board";
@ -228,19 +229,20 @@ export const ExternalContoursIssueActionsHeader = observer(function ExternalCont
)} )}
{currentMode && !embedIssue && ( {currentMode && !embedIssue && (
<CustomSelect <SelectionDropdown
value={currentMode} menuButton={
onChange={(value: TExternalContourPeekMode) => setPeekMode(value)}
customButton={
<Tooltip tooltipContent={t("common.toggle_peek_view_layout")}> <Tooltip tooltipContent={t("common.toggle_peek_view_layout")}>
<button type="button"> <span>
<currentMode.icon className="h-4 w-4 text-tertiary hover:text-secondary" /> <currentMode.icon className="h-4 w-4 text-tertiary hover:text-secondary" />
</button> </span>
</Tooltip> </Tooltip>
} }
> menuButtonWrapperClassName="flex items-center"
{PEEK_OPTIONS.map((mode) => ( options={PEEK_OPTIONS.map((mode) => ({
<CustomSelect.Option key={mode.key} value={mode.key}> key: mode.key,
isChecked: currentMode.key === mode.key,
onClick: () => setPeekMode(mode.key),
title: (
<div <div
className={`flex items-center gap-1.5 ${ className={`flex items-center gap-1.5 ${
currentMode.key === mode.key ? "text-secondary" : "text-placeholder hover:text-secondary" currentMode.key === mode.key ? "text-secondary" : "text-placeholder hover:text-secondary"
@ -249,9 +251,9 @@ export const ExternalContoursIssueActionsHeader = observer(function ExternalCont
<mode.icon className="-my-1 h-4 w-4 flex-shrink-0" /> <mode.icon className="-my-1 h-4 w-4 flex-shrink-0" />
{t(mode.i18n_title)} {t(mode.i18n_title)}
</div> </div>
</CustomSelect.Option> ),
))} }))}
</CustomSelect> />
)} )}
{issue?.project_id && issue.sequence_id && ( {issue?.project_id && issue.sequence_id && (

View File

@ -6,7 +6,7 @@
// plane package imports // plane package imports
import type { ChartXAxisProperty } from "@plane/types"; import type { ChartXAxisProperty } from "@plane/types";
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
type Props = { type Props = {
value?: ChartXAxisProperty; value?: ChartXAxisProperty;
@ -21,16 +21,28 @@ type Props = {
export function SelectXAxis(props: Props) { export function SelectXAxis(props: Props) {
const { value, onChange, options, hiddenOptions, allowNoValue, label } = props; const { value, onChange, options, hiddenOptions, allowNoValue, label } = props;
return ( return (
<CustomSelect value={value} label={label} onChange={onChange} maxHeight="lg"> <SelectionDropdown
{allowNoValue && <CustomSelect.Option value={null}>No value</CustomSelect.Option>} menuButton={label ?? "Select"}
{options.map((item) => { options={[
if (hiddenOptions?.includes(item.value)) return null; ...(allowNoValue
return ( ? [
<CustomSelect.Option key={item.value} value={item.value}> {
{item.label} key: "__none__",
</CustomSelect.Option> title: "No value",
); isChecked: value == null,
})} onClick: () => onChange(null),
</CustomSelect> },
]
: []),
...options
.filter((item) => !hiddenOptions?.includes(item.value))
.map((item) => ({
key: item.value,
title: item.label,
isChecked: value === item.value,
onClick: () => onChange(item.value),
})),
]}
/>
); );
} }

View File

@ -10,7 +10,7 @@ import { EEstimateSystem } from "@plane/constants";
import { ProjectIcon } from "@plane/propel/icons"; import { ProjectIcon } from "@plane/propel/icons";
import type { ChartYAxisMetric } from "@plane/types"; import type { ChartYAxisMetric } from "@plane/types";
// plane package imports // plane package imports
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
// hooks // hooks
import { useProjectEstimates } from "@/hooks/store/estimates"; import { useProjectEstimates } from "@/hooks/store/estimates";
// plane web constants // plane web constants
@ -44,27 +44,22 @@ export const SelectYAxis = observer(function SelectYAxis({ value, onChange, hidd
}; };
return ( return (
<CustomSelect <SelectionDropdown
value={value} menuButton={
label={
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<ProjectIcon className="h-3 w-3" /> <ProjectIcon className="h-3 w-3" />
<span>{options.find((v) => v.value === value)?.label ?? "Add Metric"}</span> <span>{options.find((v) => v.value === value)?.label ?? "Add Metric"}</span>
</div> </div>
} }
onChange={onChange} options={options
maxHeight="lg" .filter((item) => !hiddenOptions?.includes(item.value))
> .filter((item) => isEstimateEnabled(item.value))
{options.map((item) => { .map((item) => ({
if (hiddenOptions?.includes(item.value)) return null; key: item.value,
return ( title: item.label,
isEstimateEnabled(item.value) && ( isChecked: value === item.value,
<CustomSelect.Option key={item.value} value={item.value}> onClick: () => onChange(item.value),
{item.label} }))}
</CustomSelect.Option> />
)
);
})}
</CustomSelect>
); );
}); });

View File

@ -25,11 +25,12 @@ type Props = {
menuButtonWrapperClassName?: string; menuButtonWrapperClassName?: string;
options: TSelectionDropdownOption[]; options: TSelectionDropdownOption[];
placement?: Placement; placement?: Placement;
tabIndex?: number;
title?: ReactNode; title?: ReactNode;
}; };
export function SelectionDropdown(props: Props) { export function SelectionDropdown(props: Props) {
const { disabled = false, menuButton, menuButtonWrapperClassName, options, placement = "bottom-start", title } = props; const { disabled = false, menuButton, menuButtonWrapperClassName, options, placement = "bottom-start", tabIndex, title } = props;
const renderedOptions = options.filter((option) => option.shouldRender !== false); const renderedOptions = options.filter((option) => option.shouldRender !== false);
@ -39,6 +40,7 @@ export function SelectionDropdown(props: Props) {
menuButtonWrapperClassName={menuButtonWrapperClassName} menuButtonWrapperClassName={menuButtonWrapperClassName}
placement={placement} placement={placement}
disabled={disabled} disabled={disabled}
tabIndex={tabIndex}
> >
{({ closeDropdown }) => ( {({ closeDropdown }) => (
<div className="vertical-scrollbar relative scrollbar-sm h-full w-full overflow-y-auto px-2.5 py-2"> <div className="vertical-scrollbar relative scrollbar-sm h-full w-full overflow-y-auto px-2.5 py-2">

View File

@ -8,7 +8,7 @@ import React from "react";
import { CalendarDays } from "lucide-react"; import { CalendarDays } from "lucide-react";
// ui // ui
import { CalendarAfterIcon, CalendarBeforeIcon } from "@plane/propel/icons"; import { CalendarAfterIcon, CalendarBeforeIcon } from "@plane/propel/icons";
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
type Props = { type Props = {
title: string; title: string;
@ -42,9 +42,8 @@ const dueDateRange: DueDate[] = [
export function DateFilterSelect({ title, value, onChange }: Props) { export function DateFilterSelect({ title, value, onChange }: Props) {
return ( return (
<CustomSelect <SelectionDropdown
value={value} menuButton={
label={
<div className="flex items-center gap-2 text-11"> <div className="flex items-center gap-2 text-11">
{dueDateRange.find((item) => item.value === value)?.icon} {dueDateRange.find((item) => item.value === value)?.icon}
<span> <span>
@ -52,16 +51,18 @@ export function DateFilterSelect({ title, value, onChange }: Props) {
</span> </span>
</div> </div>
} }
onChange={onChange} menuButtonWrapperClassName="flex items-center"
> options={dueDateRange.map((option) => ({
{dueDateRange.map((option, index) => ( key: option.value,
<CustomSelect.Option key={index} value={option.value}> isChecked: value === option.value,
onClick: () => onChange(option.value),
title: (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span>{option.icon}</span> <span>{option.icon}</span>
{title} {option.name} {title} {option.name}
</div> </div>
</CustomSelect.Option> ),
))} }))}
</CustomSelect> />
); );
} }

View File

@ -9,7 +9,7 @@ import type { I_THEME_OPTION } from "@plane/constants";
import { THEME_OPTIONS } from "@plane/constants"; import { THEME_OPTIONS } from "@plane/constants";
import { useTranslation } from "@plane/i18n"; import { useTranslation } from "@plane/i18n";
// constants // constants
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
// ui // ui
type Props = { type Props = {
@ -22,70 +22,54 @@ export function ThemeSwitch(props: Props) {
// translation // translation
const { t } = useTranslation(); const { t } = useTranslation();
const renderThemeSwatch = (themeOption: I_THEME_OPTION) => (
<div
className="relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border-1"
style={{
borderColor: themeOption.icon.border,
}}
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: themeOption.icon.color1,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: themeOption.icon.border,
background: themeOption.icon.color2,
}}
/>
</div>
);
return ( return (
<CustomSelect <SelectionDropdown
value={value} placement="bottom-end"
label={ menuButton={
value ? ( value ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div {renderThemeSwatch(value)}
className="relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border-1"
style={{
borderColor: value.icon.border,
}}
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: value.icon.color1,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: value.icon.border,
background: value.icon.color2,
}}
/>
</div>
{t(value.key)} {t(value.key)}
</div> </div>
) : ( ) : (
t("select_your_theme") t("select_your_theme")
) )
} }
onChange={onChange} menuButtonWrapperClassName="flex w-full items-center justify-between rounded-full border border-subtle-1 px-3 py-2 text-13"
buttonClassName="border border-subtle-1" options={THEME_OPTIONS.map((themeOption) => ({
placement="bottom-end" key: themeOption.value,
input isChecked: value?.value === themeOption.value,
> onClick: () => onChange(themeOption),
{THEME_OPTIONS.map((themeOption) => ( title: (
<CustomSelect.Option key={themeOption.value} value={themeOption}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div {renderThemeSwatch(themeOption)}
className="relative flex h-4 w-4 rotate-45 transform items-center justify-center rounded-full border border-1"
style={{
borderColor: themeOption.icon.border,
}}
>
<div
className="h-full w-1/2 rounded-l-full"
style={{
background: themeOption.icon.color1,
}}
/>
<div
className="h-full w-1/2 rounded-r-full border-l"
style={{
borderLeftColor: themeOption.icon.border,
background: themeOption.icon.color2,
}}
/>
</div>
{t(themeOption.key)} {t(themeOption.key)}
</div> </div>
</CustomSelect.Option> ),
))} }))}
</CustomSelect> />
); );
} }

View File

@ -8,7 +8,7 @@ import React from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import type { TCycleEstimateType } from "@plane/types"; import type { TCycleEstimateType } from "@plane/types";
import { EEstimateSystem } from "@plane/types"; import { EEstimateSystem } from "@plane/types";
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
import { useProjectEstimates } from "@/hooks/store/estimates"; import { useProjectEstimates } from "@/hooks/store/estimates";
import { useCycle } from "@/hooks/store/use-cycle"; import { useCycle } from "@/hooks/store/use-cycle";
// local imports // local imports
@ -30,19 +30,16 @@ export const EstimateTypeDropdown = observer(function EstimateTypeDropdown(props
return (getIsPointsDataAvailable(cycleId) || isCurrentProjectEstimateEnabled) && return (getIsPointsDataAvailable(cycleId) || isCurrentProjectEstimateEnabled) &&
currentProjectEstimateType !== EEstimateSystem.CATEGORIES ? ( currentProjectEstimateType !== EEstimateSystem.CATEGORIES ? (
<div className="relative flex items-center gap-2"> <div className="relative flex items-center gap-2">
<CustomSelect <SelectionDropdown
value={value} menuButton={<span>{cycleEstimateOptions.find((v) => v.value === value)?.label ?? "None"}</span>}
label={<span>{cycleEstimateOptions.find((v) => v.value === value)?.label ?? "None"}</span>} menuButtonWrapperClassName="flex items-center rounded-sm bg-surface-2 px-2 py-1 text-13 font-medium"
onChange={onChange} options={cycleEstimateOptions.map((item) => ({
maxHeight="lg" key: item.value,
buttonClassName="bg-surface-2 border-none rounded-sm text-13 font-medium " title: item.label,
> isChecked: value === item.value,
{cycleEstimateOptions.map((item) => ( onClick: () => onChange(item.value),
<CustomSelect.Option key={item.value} value={item.value}> }))}
{item.label} />
</CustomSelect.Option>
))}
</CustomSelect>
</div> </div>
) : showDefault ? ( ) : showDefault ? (
<span className="capitalize">{cycleEstimateOptions.find((v) => v.value === value)?.label ?? value}</span> <span className="capitalize">{cycleEstimateOptions.find((v) => v.value === value)?.label ?? value}</span>

View File

@ -15,7 +15,7 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Tooltip } from "@plane/propel/tooltip"; import { Tooltip } from "@plane/propel/tooltip";
import type { TNameDescriptionLoader } from "@plane/types"; import type { TNameDescriptionLoader } from "@plane/types";
import { EIssuesStoreType } from "@plane/types"; import { EIssuesStoreType } from "@plane/types";
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
import { copyUrlToClipboard, generateWorkItemLink } from "@plane/utils"; import { copyUrlToClipboard, generateWorkItemLink } from "@plane/utils";
// hooks // hooks
import { useIssueDetail } from "@/hooks/store/use-issue-detail"; import { useIssueDetail } from "@/hooks/store/use-issue-detail";
@ -185,19 +185,20 @@ export const IssuePeekOverviewHeader = observer(function IssuePeekOverviewHeader
</Tooltip> </Tooltip>
{currentMode && showLayoutSwitcher && ( {currentMode && showLayoutSwitcher && (
<div className="flex flex-shrink-0 items-center gap-2"> <div className="flex flex-shrink-0 items-center gap-2">
<CustomSelect <SelectionDropdown
value={currentMode} menuButton={
onChange={(val: any) => setPeekMode(val)}
customButton={
<Tooltip tooltipContent={t("common.toggle_peek_view_layout")} isMobile={isMobile}> <Tooltip tooltipContent={t("common.toggle_peek_view_layout")} isMobile={isMobile}>
<button type="button" className=""> <span>
<currentMode.icon className="h-4 w-4 text-tertiary hover:text-secondary" /> <currentMode.icon className="h-4 w-4 text-tertiary hover:text-secondary" />
</button> </span>
</Tooltip> </Tooltip>
} }
> menuButtonWrapperClassName="flex items-center"
{PEEK_OPTIONS.map((mode) => ( options={PEEK_OPTIONS.map((mode) => ({
<CustomSelect.Option key={mode.key} value={mode.key}> key: mode.key,
isChecked: currentMode.key === mode.key,
onClick: () => setPeekMode(mode.key),
title: (
<div <div
className={`flex items-center gap-1.5 ${ className={`flex items-center gap-1.5 ${
currentMode.key === mode.key ? "text-secondary" : "text-placeholder hover:text-secondary" currentMode.key === mode.key ? "text-secondary" : "text-placeholder hover:text-secondary"
@ -206,9 +207,9 @@ export const IssuePeekOverviewHeader = observer(function IssuePeekOverviewHeader
<mode.icon className="-my-1 h-4 w-4 flex-shrink-0" /> <mode.icon className="-my-1 h-4 w-4 flex-shrink-0" />
{t(mode.i18n_title)} {t(mode.i18n_title)}
</div> </div>
</CustomSelect.Option> ),
))} }))}
</CustomSelect> />
</div> </div>
)} )}
{metaSlot} {metaSlot}

View File

@ -11,7 +11,7 @@ import { useTranslation } from "@plane/i18n";
import type { TModuleStatus } from "@plane/propel/icons"; import type { TModuleStatus } from "@plane/propel/icons";
import { ModuleStatusIcon } from "@plane/propel/icons"; import { ModuleStatusIcon } from "@plane/propel/icons";
import type { IModule } from "@plane/types"; import type { IModule } from "@plane/types";
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
type Props = { type Props = {
isDisabled: boolean; isDisabled: boolean;
@ -27,8 +27,8 @@ export const ModuleStatusDropdown = observer(function ModuleStatusDropdown(props
if (!moduleStatus) return <></>; if (!moduleStatus) return <></>;
return ( return (
<CustomSelect <SelectionDropdown
customButton={ menuButton={
<span <span
className={`flex h-6 w-20 items-center justify-center rounded-sm text-center text-11 ${ className={`flex h-6 w-20 items-center justify-center rounded-sm text-center text-11 ${
isDisabled ? "cursor-not-allowed" : "cursor-pointer" isDisabled ? "cursor-not-allowed" : "cursor-pointer"
@ -41,20 +41,19 @@ export const ModuleStatusDropdown = observer(function ModuleStatusDropdown(props
{(moduleStatus && t(moduleStatus?.i18n_label)) ?? t("project_modules.status.backlog")} {(moduleStatus && t(moduleStatus?.i18n_label)) ?? t("project_modules.status.backlog")}
</span> </span>
} }
value={moduleStatus?.value}
onChange={(val: TModuleStatus) => {
handleModuleDetailsChange({ status: val });
}}
disabled={isDisabled} disabled={isDisabled}
> menuButtonWrapperClassName="flex"
{MODULE_STATUS.map((status) => ( options={MODULE_STATUS.map((status) => ({
<CustomSelect.Option key={status.value} value={status.value}> key: status.value,
isChecked: moduleStatus?.value === status.value,
onClick: () => handleModuleDetailsChange({ status: status.value as TModuleStatus }),
title: (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<ModuleStatusIcon status={status.value} /> <ModuleStatusIcon status={status.value} />
{t(status.i18n_label)} {t(status.i18n_label)}
</div> </div>
</CustomSelect.Option> ),
))} }))}
</CustomSelect> />
); );
}); });

View File

@ -14,7 +14,7 @@ import { useTranslation } from "@plane/i18n";
import { StatePropertyIcon, ModuleStatusIcon } from "@plane/propel/icons"; import { StatePropertyIcon, ModuleStatusIcon } from "@plane/propel/icons";
import type { IModule } from "@plane/types"; import type { IModule } from "@plane/types";
// ui // ui
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
// types // types
// constants // constants
@ -34,9 +34,8 @@ export function ModuleStatusSelect({ control, error, tabIndex }: Props) {
render={({ field: { value, onChange } }) => { render={({ field: { value, onChange } }) => {
const selectedValue = MODULE_STATUS.find((s) => s.value === value); const selectedValue = MODULE_STATUS.find((s) => s.value === value);
return ( return (
<CustomSelect <SelectionDropdown
value={value} menuButton={
label={
<div <div
className={`flex items-center justify-center gap-2 py-0.5 text-11 ${error ? "text-danger-primary" : ""}`} className={`flex items-center justify-center gap-2 py-0.5 text-11 ${error ? "text-danger-primary" : ""}`}
> >
@ -50,19 +49,20 @@ export function ModuleStatusSelect({ control, error, tabIndex }: Props) {
)} )}
</div> </div>
} }
onChange={onChange}
tabIndex={tabIndex} tabIndex={tabIndex}
noChevron menuButtonWrapperClassName="flex"
> options={MODULE_STATUS.map((status) => ({
{MODULE_STATUS.map((status) => ( key: status.value,
<CustomSelect.Option key={status.value} value={status.value}> isChecked: value === status.value,
onClick: () => onChange(status.value),
title: (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<ModuleStatusIcon status={status.value} /> <ModuleStatusIcon status={status.value} />
{t(status.i18n_label)} {t(status.i18n_label)}
</div> </div>
</CustomSelect.Option> ),
))} }))}
</CustomSelect> />
); );
}} }}
/> />

View File

@ -14,7 +14,7 @@ import { useTranslation } from "@plane/i18n";
import { StatePropertyIcon } from "@plane/propel/icons"; import { StatePropertyIcon } from "@plane/propel/icons";
import type { IModule } from "@plane/types"; import type { IModule } from "@plane/types";
// ui // ui
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
// types // types
// common // common
// constants // constants
@ -38,8 +38,8 @@ export function SidebarStatusSelect({ control, submitChanges, watch }: Props) {
control={control} control={control}
name="status" name="status"
render={({ field: { value } }) => ( render={({ field: { value } }) => (
<CustomSelect <SelectionDropdown
label={ menuButton={
<span className={`flex items-center gap-2 text-left capitalize ${value ? "" : "text-primary"}`}> <span className={`flex items-center gap-2 text-left capitalize ${value ? "" : "text-primary"}`}>
<span <span
className="h-2 w-2 flex-shrink-0 rounded-full" className="h-2 w-2 flex-shrink-0 rounded-full"
@ -50,20 +50,19 @@ export function SidebarStatusSelect({ control, submitChanges, watch }: Props) {
{watch("status")} {watch("status")}
</span> </span>
} }
value={value} menuButtonWrapperClassName="flex"
onChange={(value: any) => { options={MODULE_STATUS.map((option) => ({
submitChanges({ status: value }); key: option.value,
}} isChecked: value === option.value,
> onClick: () => submitChanges({ status: option.value }),
{MODULE_STATUS.map((option) => ( title: (
<CustomSelect.Option key={option.value} value={option.value}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="h-2 w-2 flex-shrink-0 rounded-full" style={{ backgroundColor: option.color }} /> <span className="h-2 w-2 flex-shrink-0 rounded-full" style={{ backgroundColor: option.color }} />
{t(option.i18n_label)} {t(option.i18n_label)}
</div> </div>
</CustomSelect.Option> ),
))} }))}
</CustomSelect> />
)} )}
/> />
</div> </div>

View File

@ -9,7 +9,7 @@ import { observer } from "mobx-react";
import { START_OF_THE_WEEK_OPTIONS } from "@plane/constants"; import { START_OF_THE_WEEK_OPTIONS } from "@plane/constants";
import { TOAST_TYPE, setToast } from "@plane/propel/toast"; import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { EStartOfTheWeek } from "@plane/types"; import type { EStartOfTheWeek } from "@plane/types";
import { CustomSelect } from "@plane/ui"; import { SelectionDropdown } from "@/components/common/selection-dropdown";
// components // components
import { SettingsControlItem } from "@/components/settings/control-item"; import { SettingsControlItem } from "@/components/settings/control-item";
// hooks // hooks
@ -38,23 +38,17 @@ export const StartOfWeekPreference = observer(function StartOfWeekPreference(pro
title={props.option.title} title={props.option.title}
description={props.option.description} description={props.option.description}
control={ control={
<CustomSelect <SelectionDropdown
value={userProfile.start_of_the_week}
label={getStartOfWeekLabel(userProfile.start_of_the_week)}
onChange={handleStartOfWeekChange}
buttonClassName="border border-subtle-1"
input
maxHeight="lg"
placement="bottom-end" placement="bottom-end"
> menuButton={getStartOfWeekLabel(userProfile.start_of_the_week)}
<> menuButtonWrapperClassName="flex w-full items-center justify-between rounded-full border border-subtle-1 px-3 py-2 text-13"
{START_OF_THE_WEEK_OPTIONS.map((day) => ( options={START_OF_THE_WEEK_OPTIONS.map((day) => ({
<CustomSelect.Option key={day.value} value={day.value}> key: `${day.value}`,
{day.label} title: day.label,
</CustomSelect.Option> isChecked: userProfile.start_of_the_week === day.value,
))} onClick: () => handleStartOfWeekChange(day.value),
</> }))}
</CustomSelect> />
} }
/> />
); );