import { Add, Check, FolderOpen, Settings } from '@mui/icons-material' import { Avatar, Box, Button, Divider, ListItemContent, ListItemDecorator, Menu, MenuItem, Typography, } from '@mui/joy' import { useEffect, useRef, useState } from 'react' import { useNavigate } from 'react-router-dom' import KeyboardShortcutHint from '../../components/common/KeyboardShortcutHint' import LABEL_COLORS, { getTextColorFromBackgroundColor, } from '../../utils/Colors' import { getIconComponent } from '../../utils/ProjectIcons' import ProjectModal from '../Modals/Inputs/ProjectModal' import { useProjects } from '../Projects/ProjectQueries' const ProjectSelector = ({ selectedProject = 'Default Project', onProjectSelect, showKeyboardShortcuts = false, }) => { const { data: projects = [], isLoading } = useProjects() const navigate = useNavigate() const [anchorEl, setAnchorEl] = useState(null) const [selectedIndex, setSelectedIndex] = useState(0) const [isKeyboardNavigating, setIsKeyboardNavigating] = useState(false) const [isProjectModalOpen, setIsProjectModalOpen] = useState(false) const menuRef = useRef(null) const buttonRef = useRef(null) const defaultProjects = projects // Check if selected project still exists, if not fallback to default const selectedProjectExists = defaultProjects.some( p => p.name === selectedProject, ) const effectiveSelectedProject = selectedProjectExists ? selectedProject : 'Default Project' // Notify parent if selected project was deleted useEffect(() => { if (!selectedProjectExists && selectedProject !== 'Default Project') { const defaultProject = defaultProjects.find( p => p.id === 'default' || p.name === 'Default Project', ) if (defaultProject) { onProjectSelect?.(defaultProject) } } }, [selectedProjectExists, selectedProject, defaultProjects, onProjectSelect]) const handleMenuOpen = event => { setAnchorEl(event.currentTarget) setIsKeyboardNavigating(false) } const handleMenuClose = () => { setAnchorEl(null) } const handleProjectSelect = project => { onProjectSelect?.(project) handleMenuClose() } const handleAddProjectClick = () => { setIsProjectModalOpen(true) handleMenuClose() } const handleProjectModalSave = project => { handleProjectSelect(project) } const handleManageProjects = () => { navigate('/projects') handleMenuClose() } useEffect(() => { const handleMenuOutsideClick = event => { if (menuRef.current && !menuRef.current.contains(event.target)) { handleMenuClose() } } document.addEventListener('mousedown', handleMenuOutsideClick) return () => { document.removeEventListener('mousedown', handleMenuOutsideClick) } }, []) // Keyboard shortcut handler useEffect(() => { const handleKeyDown = event => { const isHoldingCmdOrCtrl = event.ctrlKey || event.metaKey // Cmd/Ctrl + E to open project menu if (isHoldingCmdOrCtrl && event.key === 'e') { event.preventDefault() if (!anchorEl) { setAnchorEl(buttonRef.current) setSelectedIndex(0) setIsKeyboardNavigating(true) } else { handleMenuClose() } return } // Only handle navigation keys when menu is open if (!anchorEl) return switch (event.key) { case 'ArrowDown': event.preventDefault() setIsKeyboardNavigating(true) setSelectedIndex(prev => prev < defaultProjects.length + 2 ? prev + 1 : prev, ) break case 'ArrowUp': event.preventDefault() setIsKeyboardNavigating(true) setSelectedIndex(prev => (prev > 0 ? prev - 1 : prev)) break case 'Enter': event.preventDefault() if (selectedIndex === 0) { // Hardcoded Default Project handleProjectSelect({ id: 'default', name: 'Default Project', color: LABEL_COLORS[0].value, icon: 'FolderOpen', }) } else if (selectedIndex <= defaultProjects.length) { // Projects from the array (offset by 1) handleProjectSelect(defaultProjects[selectedIndex - 1]) } else if (selectedIndex === defaultProjects.length + 1) { handleAddProjectClick() } else { handleManageProjects() } break case 'Escape': event.preventDefault() handleMenuClose() break } } document.addEventListener('keydown', handleKeyDown) return () => { document.removeEventListener('keydown', handleKeyDown) } }, [anchorEl, selectedIndex, defaultProjects, isKeyboardNavigating]) // Reset selected index when menu opens useEffect(() => { if (anchorEl) { setSelectedIndex(0) } }, [anchorEl]) // Find the currently selected project const currentProject = defaultProjects.find( p => p.name === effectiveSelectedProject, ) return ( <> Projects handleProjectSelect({ id: 'default', name: 'Default Project', color: LABEL_COLORS[0].value, icon: 'FolderOpen', }) } onMouseEnter={() => setIsKeyboardNavigating(false)} sx={{ borderRadius: 'var(--joy-radius-sm)', backgroundColor: effectiveSelectedProject === 'Default Project' ? 'var(--joy-palette-primary-softBg)' : selectedIndex === 0 && anchorEl && isKeyboardNavigating ? 'var(--joy-palette-neutral-softHoverBg)' : 'transparent', '&:hover': { backgroundColor: effectiveSelectedProject === 'Default Project' ? 'var(--joy-palette-primary-softBg)' : 'var(--joy-palette-neutral-softHoverBg)', }, position: 'relative', }} > Default Project {effectiveSelectedProject === 'Default Project' && ( )} Built-in project workspace {defaultProjects.map((project, index) => ( handleProjectSelect(project)} onMouseEnter={() => setIsKeyboardNavigating(false)} sx={{ borderRadius: 'var(--joy-radius-sm)', backgroundColor: effectiveSelectedProject === project.name ? 'var(--joy-palette-primary-softBg)' : selectedIndex === index + 1 && anchorEl && isKeyboardNavigating ? 'var(--joy-palette-neutral-softHoverBg)' : 'transparent', '&:hover': { backgroundColor: effectiveSelectedProject === project.name ? 'var(--joy-palette-primary-softBg)' : 'var(--joy-palette-neutral-softHoverBg)', }, position: 'relative', }} > {(() => { const IconComponent = getIconComponent( project.icon || 'FolderOpen', ) return ( ) })()} {project.name} {effectiveSelectedProject === project.name && ( )} {project.id === 'default' && ( Built-in project workspace )} ))} setIsKeyboardNavigating(false)} sx={{ borderRadius: 'var(--joy-radius-sm)', backgroundColor: selectedIndex === defaultProjects.length + 1 && anchorEl && isKeyboardNavigating ? 'var(--joy-palette-success-softHoverBg)' : 'transparent', '&:hover': { backgroundColor: 'var(--joy-palette-success-softHoverBg)', }, }} > Create New Project Add a custom project workspace setIsKeyboardNavigating(false)} sx={{ borderRadius: 'var(--joy-radius-sm)', backgroundColor: selectedIndex === defaultProjects.length + 2 && anchorEl && isKeyboardNavigating ? 'var(--joy-palette-neutral-softHoverBg)' : 'transparent', '&:hover': { backgroundColor: 'var(--joy-palette-neutral-softHoverBg)', }, }} > Manage Projects View, edit, and organize all projects setIsProjectModalOpen(false)} onSave={handleProjectModalSave} project={null} /> ) } export default ProjectSelector