feat: Enhance UserPoints component with improved filtering and layout

- Updated UserPoints component to include a more user-friendly filter bar with enhanced styling.
- Added a summary section to display the current filter context.
- Refactored user selection and time period filtering logic for better clarity and performance.
- Improved the layout of points cards and history sections for better visual hierarchy.
- Integrated a bar chart for visual representation of points over time.
- Updated redeem points functionality with better user feedback.

feat: Add keyboard shortcuts in AddTaskModal for improved usability

- Implemented keyboard shortcuts for adding descriptions, subtasks, and due dates.
- Enhanced user experience by providing visual hints for keyboard shortcuts.
- Refactored task creation logic to streamline the process.

fix: Refactor ChoreActionMenu to handle mouse events and improve accessibility

- Added mouse enter and leave event handlers for better interaction feedback.
- Adjusted menu positioning for improved usability.

refactor: Update RichTextEditor to support focus handling from parent components

- Converted RichTextEditor to use forwardRef for better integration with parent components.
- Exposed focus and blur methods for external control.
- Improved image upload handling with better error management.

fix: Adjust SubTask component to handle Enter key behavior correctly

- Modified key event handling to prevent unintended task creation when holding meta or ctrl keys.
- Added autoFocus prop to new task input for better user experience.
This commit is contained in:
Mo Tarbin
2025-07-11 20:10:28 -04:00
parent c2f5569010
commit 953c62cc66
42 changed files with 6262 additions and 1887 deletions

View File

@@ -17,6 +17,7 @@ import {
} from './CustomParsers'
import SmartTaskTitleInput from './SmartTaskTitleInput'
import KeyboardShortcutHint from '../../components/common/KeyboardShortcutHint'
import NotificationTemplate from '../../components/NotificationTemplate'
import LearnMoreButton from './LearnMore'
import RichTextEditor from './RichTextEditor'
@@ -53,6 +54,7 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
const textareaRef = useRef(null)
const mainInputRef = useRef(null)
const richTextEditorRef = useRef(null)
const [priority, setPriority] = useState(0)
const [dueDate, setDueDate] = useState(null)
const [description, setDescription] = useState(null)
@@ -67,6 +69,82 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
const [hasDescription, setHasDescription] = useState(false)
const [hasSubTasks, setHasSubTasks] = useState(false)
const [hasNotifications, setHasNotifications] = useState(false)
const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(true)
// set showKeyboardShortcuts true as soon as the user hold ctrl or cmd key:
useEffect(() => {
if (hasDescription && richTextEditorRef.current) {
// Small delay to ensure the component is fully rendered
setTimeout(() => {
richTextEditorRef.current.focus()
}, 100)
}
}, [hasDescription])
// set showKeyboardShortcuts true as soon as the user hold ctrl or cmd key:
useEffect(() => {
const handleKeyDown = event => {
const isHoldingCmd = event.ctrlKey || event.metaKey
if (isHoldingCmd) {
// event.preventDefault()
setShowKeyboardShortcuts(true)
}
if (
isHoldingCmd &&
event.key.toLowerCase() === 'e' &&
isModalOpen &&
!hasDescription
) {
setHasDescription(true)
setShowKeyboardShortcuts(false)
}
if (isHoldingCmd && event.key.toLowerCase() === 'j' && isModalOpen) {
// add subtask:
setHasSubTasks(true)
setShowKeyboardShortcuts(false)
// set focus on the first subtask input:
}
if (
isHoldingCmd &&
event.key.toLowerCase() === 'b' &&
isModalOpen &&
!dueDate
) {
// add due date:
setDueDate(moment().add(1, 'day').format('YYYY-MM-DDTHH:00:00'))
setShowKeyboardShortcuts(false)
}
// Enter key to create task
if (
event.key === 'Enter' &&
(event.ctrlKey || event.metaKey) &&
isModalOpen
) {
event.preventDefault()
createChore()
return
}
// Escape key to cancel/close modal
if (event.key === 'Escape' && isModalOpen) {
event.preventDefault()
handleCloseModal()
return
}
}
const handleKeyUp = event => {
if (event.key === 'Control' || event.key === 'Meta') {
setShowKeyboardShortcuts(false)
}
}
window.addEventListener('keydown', handleKeyDown)
window.addEventListener('keyup', handleKeyUp)
return () => {
window.removeEventListener('keydown', handleKeyDown)
window.removeEventListener('keyup', handleKeyUp)
}
}, [])
useEffect(() => {
if (isModalOpen && textareaRef.current) {
textareaRef.current.focus()
@@ -319,14 +397,6 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
setAssignees([])
}
const handleSubmit = () => {
console.log('Submitting task:', isPlusAccount(userProfile))
// createChore()
// handleCloseModal()
// setTaskText('')
}
const createChore = () => {
const chore = {
name: taskTitle,
@@ -376,6 +446,8 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
handleCloseModal(false)
}
handleCloseModal()
setTaskText('')
})
})
.catch(error => {
@@ -490,23 +562,36 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
sx={{ width: '100%', fontSize: '16px' }}
/>
</Box> */}
<Box>
{!hasDescription && (
<Button
startDecorator={<Add />}
variant='plain'
size='sm'
onClick={() => setHasDescription(true)}
onClick={() => {
setHasDescription(true)
// Focus will be handled by the useEffect hook
}}
endDecorator={
showKeyboardShortcuts && <KeyboardShortcutHint shortcut='E' />
}
>
Description
</Button>
)}
{!hasSubTasks && (
<Button
startDecorator={<Add />}
variant='plain'
size='sm'
onClick={() => setHasSubTasks(true)}
onClick={() => {
setHasSubTasks(true)
}}
endDecorator={
showKeyboardShortcuts && <KeyboardShortcutHint shortcut='J' />
}
>
Subtasks
</Button>
@@ -519,6 +604,9 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
onClick={() => {
setDueDate(moment().add(1, 'day').format('YYYY-MM-DDTHH:00:00'))
}}
endDecorator={
showKeyboardShortcuts && <KeyboardShortcutHint shortcut='B' />
}
>
Due Date
</Button>
@@ -545,6 +633,7 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
<Typography level='body-sm'>Description:</Typography>
<div>
<RichTextEditor
ref={richTextEditorRef}
onChange={setDescription}
entityType={'chore_description'}
/>
@@ -558,6 +647,7 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
editMode={true}
tasks={subTasks ? subTasks : []}
setTasks={setSubTasks}
shouldFocus={true}
/>
</Box>
)}
@@ -570,20 +660,22 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
gap: 2,
}}
>
<FormControl>
<Typography level='body-sm'>Priority</Typography>
<Select
defaultValue={0}
value={priority}
onChange={(e, value) => setPriority(value)}
>
<Option value='0'>No Priority</Option>
<Option value='1'>P1</Option>
<Option value='2'>P2</Option>
<Option value='3'>P3</Option>
<Option value='4'>P4</Option>
</Select>
</FormControl>
{priority > 0 && (
<FormControl>
<Typography level='body-sm'>Priority</Typography>
<Select
defaultValue={0}
value={priority}
onChange={(e, value) => setPriority(value)}
>
<Option value='0'>No Priority</Option>
<Option value='1'>P1</Option>
<Option value='2'>P2</Option>
<Option value='3'>P3</Option>
<Option value='4'>P4</Option>
</Select>
</FormControl>
)}
{dueDate && (
<FormControl>
<Typography level='body-sm'>Due Date</Typography>
@@ -665,9 +757,19 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
>
<Button variant='outlined' color='neutral' onClick={handleCloseModal}>
Cancel
{showKeyboardShortcuts && (
<KeyboardShortcutHint
shortcut='Esc'
sx={{ ml: 1 }}
withCtrl={false}
/>
)}
</Button>
<Button variant='solid' color='primary' onClick={handleSubmit}>
<Button variant='solid' color='primary' onClick={createChore}>
Create
{showKeyboardShortcuts && (
<KeyboardShortcutHint shortcut='Enter' sx={{ ml: 1 }} />
)}
</Button>
</Box>
</FadeModal>