import React, { useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { Project } from '../../entities/Project'; import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline'; interface ProjectDropdownProps { projectName: string; onProjectSearch: (e: React.ChangeEvent) => void; dropdownOpen: boolean; filteredProjects: Project[]; onProjectSelection: (project: Project) => void; onCreateProject: () => void; isCreatingProject: boolean; onShowAllProjects: () => void; allProjects: Project[]; placeholder?: string; disabled?: boolean; } const ProjectDropdown: React.FC = ({ projectName, onProjectSearch, dropdownOpen, filteredProjects, onProjectSelection, onCreateProject, isCreatingProject, onShowAllProjects, allProjects, placeholder, disabled = false, }) => { const { t } = useTranslation(); const dropdownRef = useRef(null); // Scroll to dropdown when it opens, keeping input visible useEffect(() => { if (dropdownOpen && dropdownRef.current) { // Small delay to ensure the dropdown is rendered setTimeout(() => { const dropdownElement = dropdownRef.current; if (dropdownElement) { // Find the input field to keep it visible const inputElement = dropdownElement.parentElement?.querySelector('input'); // Find the appropriate scroll container (modal or window) const modalScrollContainer = dropdownElement.closest( '.absolute.inset-0.overflow-y-auto' ); if (modalScrollContainer && inputElement) { // We're inside a modal - scroll the modal container const containerRect = modalScrollContainer.getBoundingClientRect(); const dropdownRect = dropdownElement.getBoundingClientRect(); const inputRect = inputElement.getBoundingClientRect(); // Only scroll if dropdown extends below the visible area if (dropdownRect.bottom > containerRect.bottom - 50) { // Calculate very conservative scroll - prioritize keeping input visible const inputDistanceFromTop = inputRect.top - containerRect.top; const minInputVisible = 60; // Keep at least 60px of input visible // Only scroll if we can maintain input visibility if (inputDistanceFromTop > minInputVisible) { const maxAllowedScroll = inputDistanceFromTop - minInputVisible; const neededScroll = dropdownRect.bottom - containerRect.bottom + 30; const scrollAmount = Math.min( maxAllowedScroll, neededScroll ); if (scrollAmount > 0) { modalScrollContainer.scrollBy({ top: scrollAmount, behavior: 'smooth', }); } } } } else if (inputElement) { // We're not in a modal - scroll the window const dropdownRect = dropdownElement.getBoundingClientRect(); const inputRect = inputElement.getBoundingClientRect(); const viewportHeight = window.innerHeight; // Only scroll if dropdown extends below the viewport if (dropdownRect.bottom > viewportHeight - 50) { // Calculate very conservative scroll - prioritize keeping input visible const inputDistanceFromTop = inputRect.top; const minInputVisible = 60; // Keep at least 60px of input visible // Only scroll if we can maintain input visibility if (inputDistanceFromTop > minInputVisible) { const maxAllowedScroll = inputDistanceFromTop - minInputVisible; const neededScroll = dropdownRect.bottom - viewportHeight + 30; const scrollAmount = Math.min( maxAllowedScroll, neededScroll ); if (scrollAmount > 0) { window.scrollBy({ top: scrollAmount, behavior: 'smooth', }); } } } } } }, 200); } }, [dropdownOpen]); return (
{dropdownOpen && (
{(() => { // Show filtered projects if user is typing, otherwise show all projects const projectsToShow = projectName ? filteredProjects : allProjects; return projectsToShow.length > 0 ? ( projectsToShow.map((project) => ( )) ) : (
{projectName ? t( 'forms.task.noMatchingProjects', 'No matching projects' ) : 'No projects available'}
); })()} {projectName && ( )}
)}
); }; export default ProjectDropdown;