import { useState, ComponentPropsWithoutRef, useRef, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useSelect } from 'downshift'; import { UserSelectTheme, userSelectTheme } from './UserSelect.theme'; import { EmptyUserSelectItem, UserSelectItem } from './UserSelectItem'; import { BuildingIcon, ChevronUpDown, SettingsSlidersIcon, } from 'components/shared/CustomIcon'; import { WavyBorder } from 'components/shared/WavyBorder'; import { cn } from 'utils/classnames'; export type UserSelectOption = { value: string; label: string; imgSrc?: string; }; interface UserSelectProps extends Omit, 'value' | 'onChange'>, UserSelectTheme { options: UserSelectOption[]; value?: UserSelectOption; } export const UserSelect = ({ options, value }: UserSelectProps) => { const theme = userSelectTheme(); const navigate = useNavigate(); const [selectedItem, setSelectedItem] = useState( (value as UserSelectOption) || null, ); const [dropdownOpen, setDropdownOpen] = useState(false); const [dropdownPosition, setDropdownPosition] = useState<'top' | 'bottom'>( 'bottom', ); const popoverRef = useRef(null); // Ref for the popover const inputWrapperRef = useRef(null); // Ref for the input wrapper // Calculate and update popover position useEffect(() => { if (dropdownOpen && popoverRef.current && inputWrapperRef.current) { const popover = popoverRef.current; // @ts-expect-error – we know it's not null lol const input = inputWrapperRef.current.getBoundingClientRect(); const spaceBelow = window.innerHeight - input.bottom; const spaceAbove = input.top; // @ts-expect-error – we know it's not null lol const popoverHeight = popover.offsetHeight; // Determine if there's enough space below if (spaceBelow >= popoverHeight) { setDropdownPosition('bottom'); } else if (spaceAbove >= popoverHeight) { setDropdownPosition('top'); } else { // Default to bottom if neither has enough space, but you could also set logic to choose the side with more space setDropdownPosition('bottom'); } } }, [dropdownOpen]); // Re-calculate whenever the dropdown is opened useEffect(() => { setSelectedItem(value as UserSelectOption); }, [value]); const handleSelectedItemChange = (selectedItem: UserSelectOption | null) => { setSelectedItem(selectedItem); navigate(`/${selectedItem?.value}`); }; const isSelected = (item: UserSelectOption) => selectedItem?.value === item.value; const { isOpen, getMenuProps, getToggleButtonProps, highlightedIndex, getItemProps, openMenu, } = useSelect({ items: options, // @ts-expect-error – there are two params but we don't need the second one isItemDisabled: (item) => item.disabled, onSelectedItemChange: ({ selectedItem }) => { if (selectedItem) { handleSelectedItemChange(selectedItem); } }, onIsOpenChange: ({ isOpen }) => { setDropdownOpen(isOpen ?? false); }, itemToString: (item) => (item ? item.label : ''), }); const handleManage = () => { //TODO: implement manage handler }; return (
{/* Input */}
!dropdownOpen && openMenu()} className="cursor-pointer relative py-2 pl-2 pr-4 flex min-w-[200px] w-full items-center justify-between rounded-xl bg-surface-card shadow-sm" >
Snowball Logo
{selectedItem?.label ? (

{selectedItem?.label}

) : (
)}

Team

{/* Popover */}
    {/* Settings header */}

    Other teams

    Manage

    {/* Organization */} {isOpen && options.length !== 0 ? ( options.map((item, index) => ( )) ) : ( )}
    {/* WavyBorder */} {/* //TODO:remove if personal dont exist */}
    {/* //TODO:Personal (replace options with Personal Options) */} {isOpen && options.length !== 0 ? ( options.map((item, index) => ( )) ) : ( )}
); };