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:
Mo Tarbin
2026-01-17 19:35:36 -05:00
parent b326b1b3d7
commit 7c8fa27aaf
19 changed files with 1132 additions and 462 deletions

View File

@@ -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