Developer Settings
@@ -308,6 +377,133 @@ const DeveloperSettings = () => {
+ {isNativePlatform && (
+
+
+
+
+ Scheduled Local Notifications
+
+ }
+ onClick={handleRefreshNotifications}
+ loading={isLoadingNotifications}
+ disabled={isLoadingNotifications}
+ >
+ Refresh
+
+
+
+
+
+ {scheduledNotifications.length === 0 ? (
+
+ No scheduled notifications
+
+ ) : (
+
+
+ Total scheduled:{' '}
+
+ {scheduledNotifications.length}
+
+
+
+
+
+
+ {scheduledNotifications.map((notification, index) => {
+ const scheduleTime = notification.schedule?.at
+ const scheduledDate = scheduleTime
+ ? new Date(scheduleTime)
+ : null
+ const now = new Date()
+ const timeUntil = scheduledDate
+ ? scheduledDate - now
+ : null
+
+ return (
+
+
+
+ {notification.title || 'No title'}
+
+
+ {notification.body || 'No body'}
+
+
+
+ {scheduledDate && (
+ <>
+
+ {timeUntil && timeUntil > 0
+ ? formatTimeLeft(timeUntil)
+ : 'Past due'}
+
+
+ {scheduledDate.toLocaleString()}
+
+ >
+ )}
+ {notification.extra?.choreId && (
+
+ Chore ID: {notification.extra.choreId}
+
+ )}
+
+
+
+ )
+ })}
+
+
+ )}
+
+
+ )}
+
Server-Sent Events (SSE)
diff --git a/src/views/Settings/SidepanelSettings.jsx b/src/views/Settings/SidepanelSettings.jsx
index 0734da7..6467858 100644
--- a/src/views/Settings/SidepanelSettings.jsx
+++ b/src/views/Settings/SidepanelSettings.jsx
@@ -2,8 +2,11 @@ import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd'
import {
CalendarMonth,
DragIndicator,
+ EmojiEvents,
History,
Person,
+ SupervisorAccount,
+ TrendingUp,
Visibility,
VisibilityOff,
WavingHand,
@@ -23,48 +26,22 @@ import {
Typography,
} from '@mui/joy'
import { useEffect, useState } from 'react'
+import {
+ DEFAULT_SIDEPANEL_CONFIG,
+ getSidepanelConfig,
+ saveSidepanelConfig,
+} from '../../utils/SidepanelConfig'
import SettingsLayout from './SettingsLayout'
-const DEFAULT_SIDEPANEL_CONFIG = [
- {
- id: 'welcome',
- name: 'Welcome Card',
- description: 'Shows greeting and quick stats',
- iconName: 'WavingHand',
- enabled: true,
- order: 0,
- },
- {
- id: 'assignees',
- name: 'Tasks by Assignee',
- description: 'Groups tasks by who they are assigned to',
- iconName: 'Person',
- enabled: true,
- order: 1,
- },
- {
- id: 'calendar',
- name: 'Calendar View',
- description: 'Shows tasks in a calendar format',
- iconName: 'CalendarMonth',
- enabled: true,
- order: 2,
- },
- {
- id: 'activities',
- name: 'Recent Activities',
- description: 'Shows recent task completions and activities',
- iconName: 'History',
- enabled: true,
- order: 3,
- },
-]
-
const SidepanelSettings = () => {
- const [config, setConfig] = useState(DEFAULT_SIDEPANEL_CONFIG)
+ const [config, setConfig] = useState(getSidepanelConfig())
const getIcon = iconName => {
switch (iconName) {
+ case 'SupervisorAccount':
+ return
+ case 'TrendingUp':
+ return
case 'WavingHand':
return
case 'Person':
@@ -73,27 +50,20 @@ const SidepanelSettings = () => {
return
case 'History':
return
+ case 'EmojiEvents':
+ return
default:
return
}
}
useEffect(() => {
- const saved = localStorage.getItem('sidepanelConfig')
- if (saved) {
- try {
- const parsed = JSON.parse(saved)
- setConfig(parsed)
- } catch (error) {
- console.error('Error parsing sidepanel config:', error)
- }
- }
+ setConfig(getSidepanelConfig())
}, [])
const saveConfig = newConfig => {
setConfig(newConfig)
- localStorage.setItem('sidepanelConfig', JSON.stringify(newConfig))
- window.dispatchEvent(new Event('sidepanelConfigChanged'))
+ saveSidepanelConfig(newConfig)
}
const handleToggleEnabled = (id, enabled) => {
diff --git a/src/views/components/AddTaskModal.jsx b/src/views/components/AddTaskModal.jsx
index 2442d39..4e83499 100644
--- a/src/views/components/AddTaskModal.jsx
+++ b/src/views/components/AddTaskModal.jsx
@@ -20,6 +20,7 @@ import {
} from './CustomParsers'
import SmartTaskTitleInput from './SmartTaskTitleInput'
+import DurationInput from '../../components/common/DurationInput'
import KeyboardShortcutHint from '../../components/common/KeyboardShortcutHint'
import NotificationTemplate from '../../components/NotificationTemplate'
import LearnMoreButton from './LearnMore'
@@ -90,6 +91,8 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
const [hasDescription, setHasDescription] = useState(false)
const [hasSubTasks, setHasSubTasks] = useState(false)
const [hasNotifications, setHasNotifications] = useState(false)
+ const [hasDeadline, setHasDeadline] = useState(false)
+ const [deadlineOffset, setDeadlineOffset] = useState(-1)
const [showKeyboardShortcuts, setShowKeyboardShortcuts] = useState(false)
const [projectId, setProjectId] = useState(getInitialProject())
@@ -491,6 +494,8 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
setLabelsV2([])
setAssignees([])
setProjectId(getInitialProject())
+ setHasDeadline(false)
+ setDeadlineOffset(-1)
}
const createChore = () => {
@@ -529,6 +534,7 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
labelsV2: labelsV2,
priority: priority ? Number(priority) : 0,
points: points > -1 ? points : null,
+ deadlineOffset: deadlineOffset < 0 ? null : deadlineOffset,
status: 0,
frequencyType: 'once',
frequencyMetadata: {},
@@ -798,6 +804,19 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
Edit Notifications
)}
+ {!hasDeadline && dueDate && (
+ }
+ variant='plain'
+ size='sm'
+ onClick={() => {
+ setHasDeadline(true)
+ setDeadlineOffset(86400)
+ }}
+ >
+ Set Deadline
+
+ )}
{hasDescription && (
@@ -959,6 +978,27 @@ const TaskInput = ({ autoFocus, onChoreUpdate, isModalOpen, onClose }) => {
)}
*/}
+ {hasDeadline && dueDate && (
+
+ Deadline
+
+
+ after due date
+
+
+ )}
{hasNotifications && dueDate && (
{
}
if (
['/chores', '/'].includes(location.pathname) &&
- !searchParams.get('filter')
+ !searchParams.get('filterId')
) {
return menuRounded
}