From 4e31a55b40d23d139347f139121ce63409b9502b Mon Sep 17 00:00:00 2001 From: Mary Caserio <114102750+marycaserio@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:03:50 -0600 Subject: [PATCH] feat(DeleteItem): Add deletion of goals, microgoals, and tasks (#18) - Refactor: Merge all deletion logic inside the hook are all merged into single function `deleteItem` - Feat: Add new component to enable delete goals, microgoals, and tasks by just single click on the delete icon (with mistake handling). - Feat: Add new common components `ConfirmationDialog`. --------- Co-authored-by: ZL Asica <40444637+ZL-Asica@users.noreply.github.com> --- src/components/Home/DeleteItem.jsx | 42 ++++++++++++ src/components/Home/MacroGoal.jsx | 2 + src/components/Home/MicroGoal.jsx | 5 ++ src/components/Home/Task.jsx | 68 +++++++++++-------- .../common/ConfirmSignOutDialog.jsx | 26 ------- src/components/common/ConfirmationDialog.jsx | 43 ++++++++++++ src/components/common/Header.jsx | 14 +++- src/hooks/useGoalsUpdater.js | 10 +-- 8 files changed, 144 insertions(+), 66 deletions(-) create mode 100644 src/components/Home/DeleteItem.jsx delete mode 100644 src/components/common/ConfirmSignOutDialog.jsx create mode 100644 src/components/common/ConfirmationDialog.jsx diff --git a/src/components/Home/DeleteItem.jsx b/src/components/Home/DeleteItem.jsx new file mode 100644 index 0000000..cc7233c --- /dev/null +++ b/src/components/Home/DeleteItem.jsx @@ -0,0 +1,42 @@ +import ConfirmationDialog from '@components/common/ConfirmationDialog'; +import useGoalsUpdater from '@hooks/useGoalsUpdater'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { IconButton, Tooltip } from '@mui/material'; +import { useState } from 'react'; + +const DeleteItem = ({ goalIndex, microGoalIndex, taskIndex }) => { + const { deleteItem } = useGoalsUpdater(); + const [isDialogOpen, setIsDialogOpen] = useState(false); + + const handleDelete = async () => { + await deleteItem({ goalIndex, microGoalIndex, taskIndex }); + setIsDialogOpen(false); // Close the dialog after deletion + }; + + return ( + <> + + setIsDialogOpen(true)} + sx={{ color: 'error.main' }} // Set color to indicate delete action + > + + + + + {/* Delete Confirmation Dialog */} + setIsDialogOpen(false)} + onConfirm={handleDelete} + title="Confirm Delete" + description="Are you sure you want to delete this item?" + confirmText="Delete" + /> + + ); +}; + +export default DeleteItem; diff --git a/src/components/Home/MacroGoal.jsx b/src/components/Home/MacroGoal.jsx index 779201c..a43135a 100644 --- a/src/components/Home/MacroGoal.jsx +++ b/src/components/Home/MacroGoal.jsx @@ -1,4 +1,5 @@ import AddItem from '@components/Home/AddItem'; +import DeleteItem from '@components/Home/DeleteItem'; import MicroGoal from '@components/Home/MicroGoal'; import ProgressIndicator from '@components/Home/ProgressIndicator'; import useGoalsUpdater from '@hooks/useGoalsUpdater'; @@ -17,6 +18,7 @@ const MacroGoal = ({ macroGoal, macroGoalIndex }) => { {macroGoal.name} + toggleGoalExpansion(macroGoalIndex)} size="small"> {macroGoal.expanded ? : } diff --git a/src/components/Home/MicroGoal.jsx b/src/components/Home/MicroGoal.jsx index 0d87b48..cf30bf8 100644 --- a/src/components/Home/MicroGoal.jsx +++ b/src/components/Home/MicroGoal.jsx @@ -1,4 +1,5 @@ import AddItem from '@components/Home/AddItem'; +import DeleteItem from '@components/Home/DeleteItem'; import ProgressIndicator from '@components/Home/ProgressIndicator'; import Task from '@components/Home/Task'; import useGoalsUpdater from '@hooks/useGoalsUpdater'; @@ -17,6 +18,7 @@ const MicroGoal = ({ microGoal, macroGoalIndex, microGoalIndex }) => { {microGoal.name} + toggleMicroGoalExpansion(macroGoalIndex, microGoalIndex)} size="small" @@ -30,6 +32,9 @@ const MicroGoal = ({ microGoal, macroGoalIndex, microGoalIndex }) => { toggleTaskCompletion(macroGoalIndex, microGoalIndex, taskIndex)} /> ))} diff --git a/src/components/Home/Task.jsx b/src/components/Home/Task.jsx index aafbe9b..a827f32 100644 --- a/src/components/Home/Task.jsx +++ b/src/components/Home/Task.jsx @@ -1,35 +1,43 @@ +import DeleteItem from '@components/Home/DeleteItem'; import { Checkbox, ListItem, ListItemText } from '@mui/material'; -const Task = ({ task, onToggle }) => ( - - - { + return ( + - -); + > + + + + + ); +}; export default Task; diff --git a/src/components/common/ConfirmSignOutDialog.jsx b/src/components/common/ConfirmSignOutDialog.jsx deleted file mode 100644 index 244e618..0000000 --- a/src/components/common/ConfirmSignOutDialog.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useUser } from '@contexts/UserContext'; -import { Button, Dialog, DialogActions, DialogTitle } from '@mui/material'; - -const ConfirmSignOutDialog = ({ open, onClose }) => { - const { handleSignOut } = useUser(); - - // Function to confirm sign out - const confirmSignOut = async () => { - await handleSignOut(); - onClose(); - }; - - return ( - - Confirm Sign Out - - - - - - ); -}; - -export default ConfirmSignOutDialog; diff --git a/src/components/common/ConfirmationDialog.jsx b/src/components/common/ConfirmationDialog.jsx new file mode 100644 index 0000000..7e061c5 --- /dev/null +++ b/src/components/common/ConfirmationDialog.jsx @@ -0,0 +1,43 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, +} from '@mui/material'; + +const ConfirmationDialog = ({ + open, + onClose, + onConfirm, + title, + description = '', // If null, no description will be shown + confirmText = 'Confirm', + cancelText = 'Cancel', + confirmColor = 'error', // 'primary' or 'error' +}) => { + return ( + + {title} + + {description && ( + {description} + )} + + + + + + + ); +}; + +export default ConfirmationDialog; diff --git a/src/components/common/Header.jsx b/src/components/common/Header.jsx index c39e2bf..970440e 100644 --- a/src/components/common/Header.jsx +++ b/src/components/common/Header.jsx @@ -1,13 +1,13 @@ +import ConfirmationDialog from '@components/common/ConfirmationDialog'; import { useUser } from '@contexts/UserContext'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import FireIcon from '@mui/icons-material/Whatshot'; import { AppBar, Avatar, Box, Button, IconButton, Toolbar, Typography } from '@mui/material'; import { useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import ConfirmSignOutDialog from './ConfirmSignOutDialog'; const Header = () => { - const { user, handleSignIn } = useUser(); + const { user, handleSignIn, handleSignOut } = useUser(); const location = useLocation(); const navigate = useNavigate(); @@ -65,9 +65,17 @@ const Header = () => { {/* Dialog for Confirm Sign Out */} - setOpenConfirmDialog(false)} + onConfirm={async () => { + navigate('/'); + await handleSignOut(); + onClose(); + }} + title="Confirm Sign Out" + description="Are you sure you want to sign out?" + confirmText="Sign Out" /> ) : ( diff --git a/src/hooks/useGoalsUpdater.js b/src/hooks/useGoalsUpdater.js index 6536fc0..c39fc24 100644 --- a/src/hooks/useGoalsUpdater.js +++ b/src/hooks/useGoalsUpdater.js @@ -64,7 +64,7 @@ const useGoalsUpdater = () => { }; // Delete a goal, microgoal, or task - const deleteItem = async ({ goalIndex, microGoalIndex, taskIndex }) => { + const deleteItem = async ({ goalIndex, microGoalIndex = undefined, taskIndex = undefined }) => { const updatedGoals = [...user.goals]; if (taskIndex !== undefined) { @@ -92,12 +92,8 @@ const useGoalsUpdater = () => { addTask: (goalIndex, microGoalIndex, taskName) => addItem(goalIndex, microGoalIndex, { name: taskName, completed: false }, 'task'), - // Delete a goal, microgoal, or task - deleteGoal: (goalIndex) => deleteItem(goalIndex), - deleteMicrogoal: (goalIndex, microGoalIndex) => deleteItem(goalIndex, microGoalIndex), - deleteTask: (goalIndex, microGoalIndex, taskIndex) => - deleteItem(goalIndex, microGoalIndex, taskIndex), - + // Delete + deleteItem, toggleTaskCompletion, toggleGoalExpansion: (goalIndex) => toggleExpansion(goalIndex),