feat: Add unarchive functionality to ChoreView and enhance project management features
- Implemented unarchive button for archived chores in ChoreView. - Updated chore status handling to disable actions for archived chores. - Enhanced MyChores component to filter tasks based on project selection, including a default project. - Improved ProjectModal to streamline project creation and editing with a new footer layout. - Refactored ProjectView to accurately count tasks for default and user projects. - Added project selection dropdown in AddTaskModal with default project handling. - Updated NavBar to handle logout using apiClient. - Enhanced ProjectSelector to manage projects with a new menu item for project management.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Add, Check, FolderOpen } from '@mui/icons-material'
|
||||
import { Add, Check, FolderOpen, Settings } from '@mui/icons-material'
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
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,
|
||||
@@ -25,9 +26,11 @@ const ProjectSelector = ({
|
||||
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)
|
||||
@@ -56,6 +59,7 @@ const ProjectSelector = ({
|
||||
|
||||
const handleMenuOpen = event => {
|
||||
setAnchorEl(event.currentTarget)
|
||||
setIsKeyboardNavigating(false)
|
||||
}
|
||||
|
||||
const handleMenuClose = () => {
|
||||
@@ -76,6 +80,11 @@ const ProjectSelector = ({
|
||||
handleProjectSelect(project)
|
||||
}
|
||||
|
||||
const handleManageProjects = () => {
|
||||
navigate('/projects')
|
||||
handleMenuClose()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const handleMenuOutsideClick = event => {
|
||||
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
||||
@@ -100,6 +109,7 @@ const ProjectSelector = ({
|
||||
if (!anchorEl) {
|
||||
setAnchorEl(buttonRef.current)
|
||||
setSelectedIndex(0)
|
||||
setIsKeyboardNavigating(true)
|
||||
} else {
|
||||
handleMenuClose()
|
||||
}
|
||||
@@ -112,20 +122,33 @@ const ProjectSelector = ({
|
||||
switch (event.key) {
|
||||
case 'ArrowDown':
|
||||
event.preventDefault()
|
||||
setIsKeyboardNavigating(true)
|
||||
setSelectedIndex(prev =>
|
||||
prev < defaultProjects.length ? prev + 1 : 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 < defaultProjects.length) {
|
||||
handleProjectSelect(defaultProjects[selectedIndex])
|
||||
} else {
|
||||
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':
|
||||
@@ -139,7 +162,7 @@ const ProjectSelector = ({
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown)
|
||||
}
|
||||
}, [anchorEl, selectedIndex, defaultProjects])
|
||||
}, [anchorEl, selectedIndex, defaultProjects, isKeyboardNavigating])
|
||||
|
||||
// Reset selected index when menu opens
|
||||
useEffect(() => {
|
||||
@@ -233,7 +256,6 @@ const ProjectSelector = ({
|
||||
disabled
|
||||
sx={{
|
||||
borderRadius: 'var(--joy-radius-sm)',
|
||||
mb: 1,
|
||||
cursor: 'default',
|
||||
opacity: 1,
|
||||
}}
|
||||
@@ -243,13 +265,7 @@ const ProjectSelector = ({
|
||||
</ListItemDecorator>
|
||||
<ListItemContent>
|
||||
<Typography level='title-sm' sx={{ fontWeight: 600 }}>
|
||||
Select Project
|
||||
</Typography>
|
||||
<Typography
|
||||
level='body-xs'
|
||||
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
|
||||
>
|
||||
Choose or create a project workspace
|
||||
Projects
|
||||
</Typography>
|
||||
</ListItemContent>
|
||||
</MenuItem>
|
||||
@@ -266,12 +282,13 @@ const ProjectSelector = ({
|
||||
icon: 'FolderOpen',
|
||||
})
|
||||
}
|
||||
onMouseEnter={() => setIsKeyboardNavigating(false)}
|
||||
sx={{
|
||||
borderRadius: 'var(--joy-radius-sm)',
|
||||
backgroundColor:
|
||||
effectiveSelectedProject === 'Default Project'
|
||||
? 'var(--joy-palette-primary-softBg)'
|
||||
: selectedIndex === 0 && anchorEl
|
||||
: selectedIndex === 0 && anchorEl && isKeyboardNavigating
|
||||
? 'var(--joy-palette-neutral-softHoverBg)'
|
||||
: 'transparent',
|
||||
'&:hover': {
|
||||
@@ -345,12 +362,13 @@ const ProjectSelector = ({
|
||||
<MenuItem
|
||||
key={project.id}
|
||||
onClick={() => handleProjectSelect(project)}
|
||||
onMouseEnter={() => setIsKeyboardNavigating(false)}
|
||||
sx={{
|
||||
borderRadius: 'var(--joy-radius-sm)',
|
||||
backgroundColor:
|
||||
effectiveSelectedProject === project.name
|
||||
? 'var(--joy-palette-primary-softBg)'
|
||||
: selectedIndex === index && anchorEl
|
||||
: selectedIndex === index + 1 && anchorEl && isKeyboardNavigating
|
||||
? 'var(--joy-palette-neutral-softHoverBg)'
|
||||
: 'transparent',
|
||||
'&:hover': {
|
||||
@@ -437,10 +455,11 @@ const ProjectSelector = ({
|
||||
|
||||
<MenuItem
|
||||
onClick={handleAddProjectClick}
|
||||
onMouseEnter={() => setIsKeyboardNavigating(false)}
|
||||
sx={{
|
||||
borderRadius: 'var(--joy-radius-sm)',
|
||||
backgroundColor:
|
||||
selectedIndex === defaultProjects.length && anchorEl
|
||||
selectedIndex === defaultProjects.length + 1 && anchorEl && isKeyboardNavigating
|
||||
? 'var(--joy-palette-success-softHoverBg)'
|
||||
: 'transparent',
|
||||
'&:hover': {
|
||||
@@ -456,7 +475,6 @@ const ProjectSelector = ({
|
||||
level='body-sm'
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
color: 'var(--joy-palette-success-600)',
|
||||
}}
|
||||
>
|
||||
Create New Project
|
||||
@@ -469,6 +487,41 @@ const ProjectSelector = ({
|
||||
</Typography>
|
||||
</ListItemContent>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem
|
||||
onClick={handleManageProjects}
|
||||
onMouseEnter={() => 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)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ListItemDecorator sx={{ color: 'var(--joy-palette-neutral-500)' }}>
|
||||
<Settings />
|
||||
</ListItemDecorator>
|
||||
<ListItemContent>
|
||||
<Typography
|
||||
level='body-sm'
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
}}
|
||||
>
|
||||
Manage Projects
|
||||
</Typography>
|
||||
<Typography
|
||||
level='body-xs'
|
||||
sx={{ color: 'var(--joy-palette-text-tertiary)' }}
|
||||
>
|
||||
View, edit, and organize all projects
|
||||
</Typography>
|
||||
</ListItemContent>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<ProjectModal
|
||||
|
||||
Reference in New Issue
Block a user