diff --git a/src/frontend/src/apis/onboarding.api.ts b/src/frontend/src/apis/onboarding.api.ts index ded829330c..ec95c10adb 100644 --- a/src/frontend/src/apis/onboarding.api.ts +++ b/src/frontend/src/apis/onboarding.api.ts @@ -39,6 +39,13 @@ export const getUsersChecklists = () => { }); }; +/** + * API call to delete a checklist + */ +export const deleteChecklist = (checklistId: string) => { + return axios.post<{ message: string }>(apiUrls.checklistDelete(checklistId)); +}; + /** * API call to toggle a checklist */ @@ -47,7 +54,6 @@ export const toggleChecklist = (payload: ToggleChecklistPayload) => { ...payload }); }; - /** * API Call to download a google image * @param fileId file id to be downloaded diff --git a/src/frontend/src/hooks/onboarding.hook.ts b/src/frontend/src/hooks/onboarding.hook.ts index bdbfffba88..338825d263 100644 --- a/src/frontend/src/hooks/onboarding.hook.ts +++ b/src/frontend/src/hooks/onboarding.hook.ts @@ -5,6 +5,7 @@ import { getGeneralChecklists, getUsersChecklists, downloadGoogleImage, + deleteChecklist, toggleChecklist, getCheckedChecklists } from '../apis/onboarding.api'; @@ -41,6 +42,22 @@ export const useUsersTeamTypeChecklists = () => { }); }; +export const useDeleteChecklist = () => { + const queryClient = useQueryClient(); + return useMutation<{ message: string }, Error, any>( + ['checklists', 'delete'], + async (checklistId: string) => { + const { data } = await deleteChecklist(checklistId); + return data; + }, + { + onSuccess: () => { + queryClient.invalidateQueries(['checklists']); + } + } + ); +}; + export const useToggleChecklist = () => { const queryClient = useQueryClient(); return useMutation( diff --git a/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminChecklist.tsx b/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminChecklist.tsx index 4c1c4751bf..3a5e211d3b 100644 --- a/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminChecklist.tsx +++ b/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminChecklist.tsx @@ -5,17 +5,41 @@ import { useState } from 'react'; import { Checklist } from 'shared'; import AdminTask from './AdminTask'; import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; +import { useDeleteChecklist } from '../../../hooks/onboarding.hook'; +import NERDeleteModal from '../../../components/NERDeleteModal'; +import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline'; +import { useToast } from '../../../hooks/toasts.hooks'; export const AdminChecklist: React.FC<{ parentChecklists: Checklist[]; checklistName?: string }> = ({ parentChecklists, checklistName }) => { const [showTasks, setShowTasks] = useState(false); + const [tasksToDelete, setTasksToDelete] = useState(null); const toggleShowTasks = () => { setShowTasks((prev) => !prev); }; + const toast = useToast(); + const { mutateAsync: deleteChecklist } = useDeleteChecklist(); + + const handleDelete = async () => { + if (!tasksToDelete) return; + + try { + for (const task of tasksToDelete) { + await deleteChecklist(task.checklistId); + } + toast.success('All tasks deleted successfully'); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + setTasksToDelete(null); + }; + return ( @@ -32,7 +56,10 @@ export const AdminChecklist: React.FC<{ parentChecklists: Checklist[]; checklist {checklistName} Checklist - + + setTasksToDelete(parentChecklists)}> + + {showTasks ? ( @@ -69,6 +96,15 @@ export const AdminChecklist: React.FC<{ parentChecklists: Checklist[]; checklist )} + {tasksToDelete && ( + setTasksToDelete(null)} + formId="delete-task-form" + dataType="Checklist" + onFormSubmit={() => handleDelete()} + /> + )} ); }; diff --git a/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminTask.tsx b/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminTask.tsx index b50412c620..efa309b51b 100644 --- a/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminTask.tsx +++ b/src/frontend/src/pages/AdminToolsPage/OnboardingConfig/AdminTask.tsx @@ -7,6 +7,9 @@ import SubtaskSection from '../../HomePage/components/SubtaskSection'; import { GridDragIcon } from '@mui/x-data-grid'; import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline'; import EditIcon from '@mui/icons-material/Edit'; +import NERDeleteModal from '../../../components/NERDeleteModal'; +import { useDeleteChecklist } from '../../../hooks/onboarding.hook'; +import { useToast } from '../../../hooks/toasts.hooks'; interface AdminTaskProps { parentTask: Checklist; @@ -14,11 +17,27 @@ interface AdminTaskProps { const AdminTask: React.FC = ({ parentTask }) => { const [showSubtasks, setShowSubtasks] = useState(false); + const [taskToDelete, setTaskToDelete] = useState(null); const toggleShowSubtasks = () => { setShowSubtasks((prev) => !prev); }; + const toast = useToast(); + const { mutateAsync: deleteChecklist } = useDeleteChecklist(); + + const handleDelete = async (taskId: string) => { + try { + await deleteChecklist(taskId); + toast.success('Task deleted successfully'); + } catch (error: unknown) { + if (error instanceof Error) { + toast.error(error.message); + } + } + setTaskToDelete(null); + }; + return ( @@ -28,7 +47,7 @@ const AdminTask: React.FC = ({ parentTask }) => { {parentTask.name} - + setTaskToDelete(parentTask)}> @@ -41,6 +60,15 @@ const AdminTask: React.FC = ({ parentTask }) => { {showSubtasks && } + {taskToDelete && ( + setTaskToDelete(null)} + formId="delete-task-form" + dataType="Task" + onFormSubmit={() => handleDelete(taskToDelete.checklistId)} + /> + )} ); }; diff --git a/src/frontend/src/utils/onboarding.utils.ts b/src/frontend/src/utils/onboarding.utils.ts index d22f6d4b51..5e00176035 100644 --- a/src/frontend/src/utils/onboarding.utils.ts +++ b/src/frontend/src/utils/onboarding.utils.ts @@ -18,5 +18,16 @@ export const groupChecklists = (checklists: Checklist[]) => { return groupedChecklists; }, {}); - return groupedChecklists; + const sortedGroupNames = Object.keys(groupedChecklists).sort((group1, group2) => { + if (group1 === 'General') return -1; + if (group2 === 'General') return 1; + return group1.localeCompare(group2); + }); + + const sortedGroupedChecklists: Record = {}; + sortedGroupNames.forEach((groupName) => { + sortedGroupedChecklists[groupName] = groupedChecklists[groupName]; + }); + + return sortedGroupedChecklists; }; diff --git a/src/frontend/src/utils/urls.ts b/src/frontend/src/utils/urls.ts index f238a2839a..1d9f59b128 100644 --- a/src/frontend/src/utils/urls.ts +++ b/src/frontend/src/utils/urls.ts @@ -202,6 +202,7 @@ const generalChecklists = () => `${allChecklists()}/general`; const checkedChecklists = () => `${allChecklists()}/checked`; const toggleChecklist = (checklistId: string) => `${allChecklists()}/${checklistId}/toggle`; const usersTeamTypeChecklists = () => `${allChecklists()}/usersChecklists`; +const checklistDelete = (id: string) => `${onboarding()}/checklist/delete/${id}`; const imageById = (imageId: string) => `${onboarding()}/image/${imageId}`; /**************** Other Endpoints ****************/ @@ -368,6 +369,7 @@ export const apiUrls = { checkedChecklists, toggleChecklist, usersTeamTypeChecklists, + checklistDelete, imageById, version