diff --git a/__tests__/elements/calendar.tsx b/__tests__/elements/calendar.tsx index d27e2ef..1b733c8 100644 --- a/__tests__/elements/calendar.tsx +++ b/__tests__/elements/calendar.tsx @@ -1,32 +1,31 @@ -import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import { useGetTimelinesByEventQuery } from '@/redux/api/timelineApi'; -import Calendar from '@/components/elements/Timeline/Calendar'; +import React from 'react' +import { render, screen, fireEvent } from '@testing-library/react' +import '@testing-library/jest-dom' +import { useGetTimelinesByEventQuery } from '@/redux/api/timelineApi' +import Calendar from '@/components/elements/Timeline/Calendar' // Mock the useGetTimelinesByEventQuery hook jest.mock('@/redux/api/timelineApi', () => ({ useGetTimelinesByEventQuery: jest.fn(), -})); +})) jest.mock('@/components/elements/Timeline/Calendar', () => { - return { - __esModule: true, - default: jest.fn(() => ( -
-
Calendar Component
-
Task 1
-
Task 2
-
- )), - } -}); - + return { + __esModule: true, + default: jest.fn(() => ( +
+
Calendar Component
+
Task 1
+
Task 2
+
+ )), + } +}) describe('Calendar', () => { beforeEach(() => { // Mock the return value of useGetTimelinesByEventQuery - (useGetTimelinesByEventQuery as jest.Mock).mockReturnValue({ + ;(useGetTimelinesByEventQuery as jest.Mock).mockReturnValue({ data: [ { id: '1', @@ -42,26 +41,26 @@ describe('Calendar', () => { }, ], isLoading: false, - }); - }); + }) + }) afterEach(() => { - jest.clearAllMocks(); - }); + jest.clearAllMocks() + }) test('renders the calendar component', () => { - render(); - expect(screen.getByTestId('calendar')).toBeInTheDocument(); - }); + render() + expect(screen.getByTestId('calendar')).toBeInTheDocument() + }) test('displays calendar events correctly', () => { - render(); - expect(screen.getByText('Task 1')).toBeInTheDocument(); - expect(screen.getByText('Task 2')).toBeInTheDocument(); - }); + render() + expect(screen.getByText('Task 1')).toBeInTheDocument() + expect(screen.getByText('Task 2')).toBeInTheDocument() + }) test('handles event clicks to show details in a modal', async () => { - render(); - fireEvent.click(screen.getByText('Task 1')); - }); -}); + render() + fireEvent.click(screen.getByText('Task 1')) + }) +}) diff --git a/__tests__/timeline/timeline-delete.test.tsx b/__tests__/timeline/timeline-delete.test.tsx new file mode 100644 index 0000000..1f9cce2 --- /dev/null +++ b/__tests__/timeline/timeline-delete.test.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import { render, fireEvent, waitFor } from '@testing-library/react' +import '@testing-library/jest-dom' +import { Provider } from 'react-redux' +import { store } from '@/redux/store' +import TimelineDetailsModal from '@/components/elements/Timeline/TimelineDetailsModal' + +jest.mock('@/redux/api/timelineApi', () => ({ + useDeleteTimelineMutation: jest.fn(() => [ + jest.fn().mockResolvedValue({}), + { isLoading: false, isSuccess: false }, + ]), +})) + +describe('TimelineDetailsModal', () => { + const mockOnClose = jest.fn() + + it('deletes the timeline and closes the modal on successful delete', async () => { + const { getByText } = render( + + + + ) + + global.confirm = jest.fn().mockReturnValue(true) + + fireEvent.click(getByText('Delete Timeline')) + + await waitFor(() => { + expect(mockOnClose).toHaveBeenCalled() + }) + }) + + it('does not delete the timeline if user cancels', async () => { + const { getByText } = render( + + + + ) + + global.confirm = jest.fn().mockReturnValue(false) + + fireEvent.click(getByText('Delete Timeline')) + await waitFor(() => { + expect(mockOnClose).not.toHaveBeenCalled() + }) + }) +}) diff --git a/__tests__/timeline/timeline.test.tsx b/__tests__/timeline/timeline.test.tsx index 27a7097..017f312 100644 --- a/__tests__/timeline/timeline.test.tsx +++ b/__tests__/timeline/timeline.test.tsx @@ -17,6 +17,13 @@ jest.mock('@/components/elements/Timeline/Calendar', () => { } }) +jest.mock('@/components/elements/Timeline/TimelineDetailsModal', () => { + return { + __esModule: true, + default: jest.fn(() =>
Mocked DemoApp
), + } +}) + describe('EventTimeline', () => { beforeEach(() => { ;(useGetTimelinesByEventQuery as jest.Mock).mockReturnValue({ diff --git a/src/components/elements/Timeline/Calendar.tsx b/src/components/elements/Timeline/Calendar.tsx index af85967..4e96c86 100644 --- a/src/components/elements/Timeline/Calendar.tsx +++ b/src/components/elements/Timeline/Calendar.tsx @@ -2,12 +2,10 @@ import React from 'react' import dayGridPlugin from '@fullcalendar/daygrid' import timeGridPlugin from '@fullcalendar/timegrid' import interactionPlugin from '@fullcalendar/interaction' -import Modal from '@mui/material/Modal' -import Box from '@mui/material/Box' -import Typography from '@mui/material/Typography' import { useGetTimelinesByEventQuery } from '@/redux/api/timelineApi' import { EventApi } from '@fullcalendar/core/index.js' import FullCalendar from '@fullcalendar/react' +import TimelineDetailsModal from './TimelineDetailsModal' interface DemoAppProps { eventId: string @@ -51,14 +49,12 @@ const DemoApp: React.FC = ({ eventId }) => { p: 4, } - - if (isLoading) { return (
- ); + ) } return ( @@ -77,27 +73,18 @@ const DemoApp: React.FC = ({ eventId }) => { eventColor="#14b8a6" displayEventTime={false} /> - - - - Task Details - - - Task title: {clickedEvent?.title} - - - Start date: {clickedEvent?.start?.toLocaleTimeString()} - - - End date: {clickedEvent?.end?.toLocaleTimeString()} - - - + {clickedEvent && ( + + )} ) diff --git a/src/components/elements/Timeline/TimelineDetailsModal.tsx b/src/components/elements/Timeline/TimelineDetailsModal.tsx new file mode 100644 index 0000000..9a361cf --- /dev/null +++ b/src/components/elements/Timeline/TimelineDetailsModal.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { useDeleteTimelineMutation } from '@/redux/api/timelineApi'; +import Modal from '@mui/material/Modal'; +import Box from '@mui/material/Box'; +import Typography from '@mui/material/Typography'; +import Button from '@mui/material/Button'; + +interface TimelineDetailsModalProps { + timelineId: string; + onClose: () => void; + showModal: boolean; + clickedEvent: { + title: string; + start: Date; + end: Date; + }; +} + +const style = { + position: 'absolute' as 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: 400, + bgcolor: 'background.paper', + border: '2px solid #000', + boxShadow: 24, + p: 4, +}; + +const TimelineDetailsModal: React.FC = ({ timelineId, onClose, showModal, clickedEvent }) => { + const [deleteTimeline, { isLoading, isSuccess}] = useDeleteTimelineMutation(); + + const handleDelete = async () => { + if (window.confirm('Are you sure you want to delete this timeline?')) { + try { + await deleteTimeline({ id: timelineId }); + onClose(); + } catch (error) { + console.error('Failed to delete the timeline:', error); + alert('There was a problem deleting the timeline.'); + } + } + }; + + React.useEffect(() => { + if (isSuccess) { + onClose(); + } + }, [isSuccess, onClose]); + + + return ( + + + + Task Details + + + Task title: {clickedEvent?.title} + + + Start date: {clickedEvent?.start.toLocaleTimeString()} + + + End date: {clickedEvent?.end.toLocaleTimeString()} + +
+ + +
+
+
+ ); +}; + +export default TimelineDetailsModal; diff --git a/src/redux/api/timelineApi.ts b/src/redux/api/timelineApi.ts index 3a42b0e..b1d2c10 100644 --- a/src/redux/api/timelineApi.ts +++ b/src/redux/api/timelineApi.ts @@ -39,6 +39,13 @@ export const timelineApi = baseApi.injectEndpoints({ }), providesTags: ['Timeline'], }), + deleteTimeline: builder.mutation({ + query: ({ id }) => ({ + url: `/timelines/${id}/delete/`, + method: 'DELETE', + }), + invalidatesTags: (_, __, arg) => [{ type: 'Timeline', id: arg.id }], + }), }), }) @@ -46,4 +53,5 @@ export const { useGetTimelinesByEventQuery, useCreateTimelineMutation, useModifyDetailTimelineMutation, + useDeleteTimelineMutation, } = timelineApi