diff --git a/src/views/ChoreEdit/ChoreView.jsx b/src/views/ChoreEdit/ChoreView.jsx
index 1eeebad..d00035a 100644
--- a/src/views/ChoreEdit/ChoreView.jsx
+++ b/src/views/ChoreEdit/ChoreView.jsx
@@ -30,7 +30,6 @@ import {
MenuItem,
Sheet,
Snackbar,
- styled,
Typography,
} from '@mui/joy'
import { Divider } from '@mui/material'
@@ -54,16 +53,6 @@ import ConfirmationModal from '../Modals/Inputs/ConfirmationModal'
import LoadingComponent from '../components/Loading.jsx'
import RichTextEditor from '../components/RichTextEditor.jsx'
import SubTasks from '../components/SubTask.jsx'
-const IconCard = styled('div')({
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- backgroundColor: '#f0f0f0', // Adjust the background color as needed
- borderRadius: '50%',
- minWidth: '40px',
- height: '40px',
- marginRight: '16px',
-})
const ChoreView = () => {
const [chore, setChore] = useState({})
diff --git a/src/views/Chores/ChoreCard.jsx b/src/views/Chores/ChoreCard.jsx
index 4a9dc56..03e2085 100644
--- a/src/views/Chores/ChoreCard.jsx
+++ b/src/views/Chores/ChoreCard.jsx
@@ -1,29 +1,9 @@
import {
- Archive,
CancelScheduleSend,
Check,
- CopyAll,
- Delete,
- Edit,
- HorizontalRule,
- KeyboardControlKey,
- KeyboardDoubleArrowUp,
- LocalOffer,
- ManageSearch,
- MoreTime,
- MoreVert,
- Nfc,
- NoteAdd,
- PriorityHigh,
- RecordVoiceOver,
Repeat,
- Report,
- SwitchAccessShortcut,
TimesOneMobiledata,
Toll,
- Unarchive,
- Update,
- ViewCarousel,
Webhook,
} from '@mui/icons-material'
import {
@@ -33,16 +13,13 @@ import {
Card,
Chip,
CircularProgress,
- Divider,
Grid,
IconButton,
- Menu,
- MenuItem,
Snackbar,
Typography,
} from '@mui/joy'
import moment from 'moment'
-import React, { useEffect } from 'react'
+import React from 'react'
import { useNavigate } from 'react-router-dom'
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
import { UserContext } from '../../contexts/UserContext'
@@ -50,11 +27,8 @@ import { useError } from '../../service/ErrorProvider'
import { notInCompletionWindow } from '../../utils/Chores.jsx'
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
import {
- ArchiveChore,
DeleteChore,
MarkChoreComplete,
- SkipChore,
- UnArchiveChore,
UpdateChoreAssignee,
UpdateDueDate,
} from '../../utils/Fetcher'
@@ -64,17 +38,16 @@ import DateModal from '../Modals/Inputs/DateModal'
import SelectModal from '../Modals/Inputs/SelectModal'
import TextModal from '../Modals/Inputs/TextModal'
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
+import ChoreActionMenu from '../components/ChoreActionMenu'
const ChoreCard = ({
chore,
performers,
onChoreUpdate,
onChoreRemove,
- userLabels,
sx,
viewOnly,
onChipClick,
}) => {
- const [activeUserId, setActiveUserId] = React.useState(0)
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
React.useState(false)
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
@@ -85,10 +58,7 @@ const ChoreCard = ({
React.useState(false)
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
- const [anchorEl, setAnchorEl] = React.useState(null)
- const menuRef = React.useRef(null)
const navigate = useNavigate()
- const [isDisabled, setIsDisabled] = React.useState(false)
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
@@ -97,39 +67,7 @@ const ChoreCard = ({
const { impersonatedUser } = useImpersonateUser()
const { showError } = useError()
- useEffect(() => {
- document.addEventListener('mousedown', handleMenuOutsideClick)
- return () => {
- document.removeEventListener('mousedown', handleMenuOutsideClick)
- }
- }, [anchorEl])
- const handleMenuOpen = event => {
- setAnchorEl(event.currentTarget)
- }
-
- const handleMenuClose = () => {
- setAnchorEl(null)
- }
-
- const handleMenuOutsideClick = event => {
- if (
- anchorEl &&
- !anchorEl.contains(event.target) &&
- !menuRef.current.contains(event.target)
- ) {
- handleMenuClose()
- }
- }
- const handleEdit = () => {
- navigate(`/chores/${chore.id}/edit`)
- }
- const handleClone = () => {
- navigate(`/chores/${chore.id}/edit?clone=true`)
- }
- const handleView = () => {
- navigate(`/chores/${chore.id}`)
- }
const handleDelete = () => {
setConfirmModelConfig({
isOpen: true,
@@ -149,30 +87,6 @@ const ChoreCard = ({
},
})
}
- const handleArchive = () => {
- if (chore.isActive) {
- ArchiveChore(chore.id).then(response => {
- if (response.ok) {
- response.json().then(data => {
- const newChore = { ...chore, isActive: false }
-
- onChoreUpdate(newChore, 'archive')
- })
- }
- })
- } else {
- UnArchiveChore(chore.id).then(response => {
- if (response.ok) {
- response.json().then(data => {
- const newChore = { ...chore, isActive: true }
- onChoreUpdate(newChore, 'unarchive')
- })
- }
- })
- }
-
- handleMenuClose()
- }
const handleTaskCompletion = () => {
setIsPendingCompletion(true)
@@ -235,10 +149,6 @@ const ChoreCard = ({
}
const handleChangeDueDate = newDate => {
- if (activeUserId === null) {
- alert('Please select a performer')
- return
- }
UpdateDueDate(chore.id, newDate).then(response => {
if (response.ok) {
response.json().then(data => {
@@ -250,11 +160,6 @@ const ChoreCard = ({
}
const handleCompleteWithPastDate = newDate => {
- if (activeUserId === null) {
- alert('Please select a performer')
- return
- }
-
MarkChoreComplete(
chore.id,
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
@@ -318,29 +223,6 @@ const ChoreCard = ({
return 'neutral'
}
- const getIconForLabel = label => {
- if (!label || label.trim() === '') return <>>
- switch (String(label).toLowerCase()) {
- case 'high':
- return
- case 'important':
- return
- default:
- return
- }
- }
- const getPriorityIcon = priority => {
- switch (Number(priority)) {
- case 1:
- return
- case 2:
- return
- case 3:
- return
- default:
- return
- }
- }
const getRecurrentChipText = chore => {
// if chore.frequencyMetadata is type string then parse it otherwise assigned to the metadata:
const metadata =
@@ -678,135 +560,19 @@ const ChoreCard = ({
)}
-
-
-
- {/* */}
-
+ setIsCompleteWithNoteModalOpen(true)}
+ onCompleteWithPastDate={() =>
+ setIsCompleteWithPastDateModalOpen(true)
+ }
+ onChangeAssignee={() => setIsChangeAssigneeModalOpen(true)}
+ onChangeDueDate={() => setIsChangeDueDateModalOpen(true)}
+ onWriteNFC={() => setIsNFCModalOpen(true)}
+ onDelete={handleDelete}
+ />
diff --git a/src/views/Chores/CompactChoreCard.jsx b/src/views/Chores/CompactChoreCard.jsx
index 78063bd..a3fa4dd 100644
--- a/src/views/Chores/CompactChoreCard.jsx
+++ b/src/views/Chores/CompactChoreCard.jsx
@@ -1,22 +1,8 @@
import {
- Archive,
CancelScheduleSend,
Check,
- CopyAll,
- Delete,
- Edit,
- ManageSearch,
- MoreTime,
- MoreVert,
- Nfc,
- NoteAdd,
- RecordVoiceOver,
Repeat,
- SwitchAccessShortcut,
TimesOneMobiledata,
- Unarchive,
- Update,
- ViewCarousel,
Webhook,
} from '@mui/icons-material'
import {
@@ -24,15 +10,12 @@ import {
Button,
Chip,
CircularProgress,
- Divider,
IconButton,
- Menu,
- MenuItem,
Snackbar,
Typography,
} from '@mui/joy'
import moment from 'moment'
-import React, { useEffect } from 'react'
+import React from 'react'
import { useNavigate } from 'react-router-dom'
import { useImpersonateUser } from '../../contexts/ImpersonateUserContext.jsx'
import { UserContext } from '../../contexts/UserContext'
@@ -40,11 +23,8 @@ import { useError } from '../../service/ErrorProvider'
import { notInCompletionWindow } from '../../utils/Chores.jsx'
import { getTextColorFromBackgroundColor } from '../../utils/Colors.jsx'
import {
- ArchiveChore,
DeleteChore,
MarkChoreComplete,
- SkipChore,
- UnArchiveChore,
UpdateChoreAssignee,
UpdateDueDate,
} from '../../utils/Fetcher'
@@ -54,6 +34,7 @@ import DateModal from '../Modals/Inputs/DateModal'
import SelectModal from '../Modals/Inputs/SelectModal'
import TextModal from '../Modals/Inputs/TextModal'
import WriteNFCModal from '../Modals/Inputs/WriteNFCModal'
+import ChoreActionMenu from '../components/ChoreActionMenu'
const CompactChoreCard = ({
chore,
@@ -64,7 +45,6 @@ const CompactChoreCard = ({
viewOnly,
onChipClick,
}) => {
- const [activeUserId, setActiveUserId] = React.useState(0)
const [isChangeDueDateModalOpen, setIsChangeDueDateModalOpen] =
React.useState(false)
const [isCompleteWithPastDateModalOpen, setIsCompleteWithPastDateModalOpen] =
@@ -75,10 +55,7 @@ const CompactChoreCard = ({
React.useState(false)
const [confirmModelConfig, setConfirmModelConfig] = React.useState({})
const [isNFCModalOpen, setIsNFCModalOpen] = React.useState(false)
- const [anchorEl, setAnchorEl] = React.useState(null)
- const menuRef = React.useRef(null)
const navigate = useNavigate()
- const [isDisabled, setIsDisabled] = React.useState(false)
const [isPendingCompletion, setIsPendingCompletion] = React.useState(false)
const [secondsLeftToCancel, setSecondsLeftToCancel] = React.useState(null)
@@ -88,44 +65,7 @@ const CompactChoreCard = ({
const { showError } = useError()
- useEffect(() => {
- document.addEventListener('mousedown', handleMenuOutsideClick)
- return () => {
- document.removeEventListener('mousedown', handleMenuOutsideClick)
- }
- }, [anchorEl])
-
- const handleMenuOpen = event => {
- setAnchorEl(event.currentTarget)
- }
-
- const handleMenuClose = () => {
- setAnchorEl(null)
- }
-
- const handleMenuOutsideClick = event => {
- if (
- anchorEl &&
- !anchorEl.contains(event.target) &&
- !menuRef.current.contains(event.target)
- ) {
- handleMenuClose()
- }
- }
-
// All the existing handler methods (same as original ChoreCard)
- const handleEdit = () => {
- navigate(`/chores/${chore.id}/edit`)
- }
-
- const handleClone = () => {
- navigate(`/chores/${chore.id}/edit?clone=true`)
- }
-
- const handleView = () => {
- navigate(`/chores/${chore.id}`)
- }
-
const handleDelete = () => {
setConfirmModelConfig({
isOpen: true,
@@ -146,29 +86,6 @@ const CompactChoreCard = ({
})
}
- const handleArchive = () => {
- if (chore.isActive) {
- ArchiveChore(chore.id).then(response => {
- if (response.ok) {
- response.json().then(data => {
- const newChore = { ...chore, isActive: false }
- onChoreUpdate(newChore, 'archive')
- })
- }
- })
- } else {
- UnArchiveChore(chore.id).then(response => {
- if (response.ok) {
- response.json().then(data => {
- const newChore = { ...chore, isActive: true }
- onChoreUpdate(newChore, 'unarchive')
- })
- }
- })
- }
- handleMenuClose()
- }
-
const handleTaskCompletion = () => {
setIsPendingCompletion(true)
let seconds = 3
@@ -230,10 +147,6 @@ const CompactChoreCard = ({
}
const handleChangeDueDate = newDate => {
- if (activeUserId === null) {
- alert('Please select a performer')
- return
- }
UpdateDueDate(chore.id, newDate).then(response => {
if (response.ok) {
response.json().then(data => {
@@ -245,11 +158,6 @@ const CompactChoreCard = ({
}
const handleCompleteWithPastDate = newDate => {
- if (activeUserId === null) {
- alert('Please select a performer')
- return
- }
-
MarkChoreComplete(
chore.id,
impersonatedUser ? { completedBy: impersonatedUser.userId } : null,
@@ -654,113 +562,30 @@ const CompactChoreCard = ({
)}
- {/* Menu Button */}
- {
- e.stopPropagation()
- handleMenuOpen(e)
- }}
+ chore={chore}
+ onChoreUpdate={onChoreUpdate}
+ onChoreRemove={onChoreRemove}
+ onCompleteWithNote={() => setIsCompleteWithNoteModalOpen(true)}
+ onCompleteWithPastDate={() =>
+ setIsCompleteWithPastDateModalOpen(true)
+ }
+ onChangeAssignee={() => setIsChangeAssigneeModalOpen(true)}
+ onChangeDueDate={() => setIsChangeDueDateModalOpen(true)}
+ onWriteNFC={() => setIsNFCModalOpen(true)}
+ onDelete={handleDelete}
sx={{
width: 28,
height: 28,
- opacity: 0.6,
+ // opacity: 0.6,
'&:hover': {
opacity: 1,
},
}}
- >
-
-
+ />
-
- {/* Menu */}
-
{/* All modals (same as original) */}
diff --git a/src/views/Settings/MFASettings.jsx b/src/views/Settings/MFASettings.jsx
index 1089fc0..032ab5f 100644
--- a/src/views/Settings/MFASettings.jsx
+++ b/src/views/Settings/MFASettings.jsx
@@ -1,4 +1,4 @@
-import { CheckCircle, Key, Security, Smartphone } from '@mui/icons-material'
+import { CheckCircle, Security, Smartphone } from '@mui/icons-material'
import {
Alert,
Box,
@@ -264,7 +264,7 @@ const MFASettings = () => {
-
+ {/*
{mfaEnabled && (
@@ -288,7 +288,7 @@ const MFASettings = () => {
- )}
+ )} */}
{/* Setup MFA Modal */}
diff --git a/src/views/components/CalendarView.jsx b/src/views/components/CalendarView.jsx
index 6f34e7f..286e388 100644
--- a/src/views/components/CalendarView.jsx
+++ b/src/views/components/CalendarView.jsx
@@ -122,7 +122,18 @@ const CalendarView = ({ chores }) => {
}
/>
{!selectedDate && (
-
+
{/* Show legend with current user first, then other circle members who have assignments */}
{(() => {
const assignedUserIds = new Set(
@@ -171,7 +182,7 @@ const CalendarView = ({ chores }) => {
backgroundColor: item.color,
}}
/>
-
+
{item.name}
diff --git a/src/views/components/ChoreActionMenu.jsx b/src/views/components/ChoreActionMenu.jsx
new file mode 100644
index 0000000..aecf099
--- /dev/null
+++ b/src/views/components/ChoreActionMenu.jsx
@@ -0,0 +1,303 @@
+import {
+ Archive,
+ CopyAll,
+ Delete,
+ Edit,
+ ManageSearch,
+ MoreTime,
+ MoreVert,
+ Nfc,
+ NoteAdd,
+ RecordVoiceOver,
+ SwitchAccessShortcut,
+ Unarchive,
+ Update,
+ ViewCarousel,
+} from '@mui/icons-material'
+import { Divider, IconButton, Menu, MenuItem } from '@mui/joy'
+import React, { useEffect } from 'react'
+import { useNavigate } from 'react-router-dom'
+import { useError } from '../../service/ErrorProvider'
+import {
+ ArchiveChore,
+ DeleteChore,
+ SkipChore,
+ UnArchiveChore,
+} from '../../utils/Fetcher'
+
+const ChoreActionMenu = ({
+ chore,
+ onChoreUpdate,
+ onChoreRemove,
+ onCompleteWithNote,
+ onCompleteWithPastDate,
+ onChangeAssignee,
+ onChangeDueDate,
+ onWriteNFC,
+ onDelete,
+ sx = {},
+ variant = 'soft',
+}) => {
+ const [anchorEl, setAnchorEl] = React.useState(null)
+ const menuRef = React.useRef(null)
+ const navigate = useNavigate()
+ const { showError } = useError()
+
+ useEffect(() => {
+ const handleMenuOutsideClick = event => {
+ if (
+ anchorEl &&
+ !anchorEl.contains(event.target) &&
+ !menuRef.current.contains(event.target)
+ ) {
+ handleMenuClose()
+ }
+ }
+
+ document.addEventListener('mousedown', handleMenuOutsideClick)
+ return () => {
+ document.removeEventListener('mousedown', handleMenuOutsideClick)
+ }
+ }, [anchorEl])
+
+ const handleMenuOpen = event => {
+ event.stopPropagation()
+ setAnchorEl(event.currentTarget)
+ }
+
+ const handleMenuClose = () => {
+ setAnchorEl(null)
+ }
+
+ const handleEdit = () => {
+ navigate(`/chores/${chore.id}/edit`)
+ handleMenuClose()
+ }
+
+ const handleClone = () => {
+ navigate(`/chores/${chore.id}/edit?clone=true`)
+ handleMenuClose()
+ }
+
+ const handleView = () => {
+ navigate(`/chores/${chore.id}`)
+ handleMenuClose()
+ }
+
+ const handleDelete = () => {
+ if (onDelete) {
+ onDelete()
+ } else {
+ // Default delete behavior
+ DeleteChore(chore.id).then(response => {
+ if (response.ok) {
+ onChoreRemove?.(chore)
+ }
+ })
+ }
+ handleMenuClose()
+ }
+
+ const handleArchive = () => {
+ if (chore.isActive) {
+ ArchiveChore(chore.id).then(response => {
+ if (response.ok) {
+ response.json().then(() => {
+ const newChore = { ...chore, isActive: false }
+ onChoreUpdate?.(newChore, 'archive')
+ })
+ }
+ })
+ } else {
+ UnArchiveChore(chore.id).then(response => {
+ if (response.ok) {
+ response.json().then(() => {
+ const newChore = { ...chore, isActive: true }
+ onChoreUpdate?.(newChore, 'unarchive')
+ })
+ }
+ })
+ }
+ handleMenuClose()
+ }
+
+ const handleSkip = () => {
+ SkipChore(chore.id)
+ .then(response => {
+ if (response.ok) {
+ response.json().then(data => {
+ const newChore = data.res
+ onChoreUpdate?.(newChore, 'skipped')
+ handleMenuClose()
+ })
+ }
+ })
+ .catch(error => {
+ if (error?.queued) {
+ showError({
+ title: 'Failed to update',
+ message: 'Request will be processed when you are online',
+ })
+ } else {
+ showError({
+ title: 'Failed to update',
+ message: error,
+ })
+ }
+ })
+ }
+
+ const handleHistory = () => {
+ navigate(`/chores/${chore.id}/history`)
+ handleMenuClose()
+ }
+
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
+
+export default ChoreActionMenu