import { useRef } from 'react'; import { Key } from 'ts-key-enum'; import { StyledDropdownMenuItemsContainer } from '@/ui/dropdown/components/StyledDropdownMenuItemsContainer'; import { StyledDropdownMenuSeparator } from '@/ui/dropdown/components/StyledDropdownMenuSeparator'; import { IconPlus } from '@/ui/icon'; import { IconComponent } from '@/ui/icon/types/IconComponent'; import { MenuItem } from '@/ui/menu-item/components/MenuItem'; import { MenuItemSelect } from '@/ui/menu-item/components/MenuItemSelect'; import { MenuItemSelectAvatar } from '@/ui/menu-item/components/MenuItemSelectAvatar'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { Avatar } from '@/users/components/Avatar'; import { assertNotNull } from '~/utils/assert'; import { isNonEmptyString } from '~/utils/isNonEmptyString'; import { CreateButtonId, EmptyButtonId } from '../constants'; import { useEntitySelectScroll } from '../hooks/useEntitySelectScroll'; import { EntityForSelect } from '../types/EntityForSelect'; import { RelationPickerHotkeyScope } from '../types/RelationPickerHotkeyScope'; import { DropdownMenuSkeletonItem } from './skeletons/DropdownMenuSkeletonItem'; import { CreateNewButton } from './CreateNewButton'; export type SingleEntitySelectBaseProps< CustomEntityForSelect extends EntityForSelect, > = { EmptyIcon?: IconComponent; emptyLabel?: string; entitiesToSelect: CustomEntityForSelect[]; loading?: boolean; onCancel?: () => void; onEntitySelected: (entity?: CustomEntityForSelect) => void; selectedEntity?: CustomEntityForSelect; onCreate?: () => void; showCreateButton?: boolean; }; export const SingleEntitySelectBase = < CustomEntityForSelect extends EntityForSelect, >({ EmptyIcon, emptyLabel, entitiesToSelect, loading, onCancel, onEntitySelected, selectedEntity, onCreate, showCreateButton, }: SingleEntitySelectBaseProps) => { const containerRef = useRef(null); const entitiesInDropdown = [selectedEntity, ...entitiesToSelect].filter( (entity): entity is CustomEntityForSelect => assertNotNull(entity) && isNonEmptyString(entity.name.trim()), ); const { preselectedOptionId, resetScroll } = useEntitySelectScroll({ selectableOptionIds: [ EmptyButtonId, ...entitiesInDropdown.map((item) => item.id), ...(showCreateButton ? [CreateButtonId] : []), ], containerRef, }); useScopedHotkeys( Key.Enter, () => { if (showCreateButton && preselectedOptionId === CreateButtonId) { onCreate?.(); } else { const entity = entitiesInDropdown.findIndex( (entity) => entity.id === preselectedOptionId, ); onEntitySelected(entitiesInDropdown[entity]); } resetScroll(); }, RelationPickerHotkeyScope.RelationPicker, [entitiesInDropdown, preselectedOptionId, onEntitySelected], ); useScopedHotkeys( Key.Escape, () => { onCancel?.(); }, RelationPickerHotkeyScope.RelationPicker, [onCancel], ); return ( <> {emptyLabel && ( onEntitySelected()} LeftIcon={EmptyIcon} text={emptyLabel} hovered={preselectedOptionId === EmptyButtonId} selected={!selectedEntity} /> )} {loading ? ( ) : entitiesInDropdown.length === 0 ? ( ) : ( entitiesInDropdown?.map((entity) => ( onEntitySelected(entity)} text={entity.name} hovered={preselectedOptionId === entity.id} avatar={ } /> )) )} {showCreateButton && ( <> )} ); };