From 5bb9e042cf7b3902eda6faa8f6a4b5e6be5100de Mon Sep 17 00:00:00 2001
From: Ajeyakrishna <98796547+Ajeyakrishna-k@users.noreply.github.com>
Date: Sun, 22 Oct 2023 00:48:06 +0530
Subject: [PATCH] Adds a modal component (#954)
* FEAT : adds a modal component
* TEST : adds tests for modal component
* Adds a task request form component (#955)
* FEAT : adds a task request form
* CHORE : refactored date call
---------
Co-authored-by: Amit Prakash <34869115+iamitprakash@users.noreply.github.com>
---
.../Issues/TaskRequestForm.test.tsx | 62 ++++++++
.../Unit/Components/modal/index.test.tsx | 50 ++++++
src/components/Modal/Modal | 0
src/components/Modal/index.tsx | 30 ++++
src/components/Modal/modal.module.scss | 31 ++++
src/components/issues/TaskRequestForm.tsx | 144 ++++++++++++++++++
6 files changed, 317 insertions(+)
create mode 100644 __tests__/Unit/Components/Issues/TaskRequestForm.test.tsx
create mode 100644 __tests__/Unit/Components/modal/index.test.tsx
create mode 100644 src/components/Modal/Modal
create mode 100644 src/components/Modal/index.tsx
create mode 100644 src/components/Modal/modal.module.scss
create mode 100644 src/components/issues/TaskRequestForm.tsx
diff --git a/__tests__/Unit/Components/Issues/TaskRequestForm.test.tsx b/__tests__/Unit/Components/Issues/TaskRequestForm.test.tsx
new file mode 100644
index 000000000..0fbad8f33
--- /dev/null
+++ b/__tests__/Unit/Components/Issues/TaskRequestForm.test.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { render, fireEvent, screen, waitFor } from '@testing-library/react';
+import TaskRequestForm from '@/components/issues/TaskRequestForm';
+
+describe('TaskRequestForm Component', () => {
+ const date = new Date();
+ const today = date.toISOString().split('T')[0];
+ date.setDate(date.getDate() + 7);
+ const sevenDaysFromToday = date.toISOString().split('T')[0];
+ test('renders form with default values', () => {
+ const createTaskRequestMock = jest.fn();
+ render();
+ const startDateInput = screen.getByLabelText(
+ /Start date:/i
+ ) as HTMLInputElement;
+ const endDateInput = screen.getByLabelText(
+ /End date:/i
+ ) as HTMLInputElement;
+ const descriptionTextarea = screen.getByLabelText(
+ /Description:/i
+ ) as HTMLTextAreaElement;
+ const submitButton = screen.getByRole('button', {
+ name: /Create Request/i,
+ });
+ expect(startDateInput.value).toBe(today);
+ expect(endDateInput.value).toBe(sevenDaysFromToday);
+ expect(descriptionTextarea.value).toBe('');
+ expect(submitButton).toBeInTheDocument();
+ });
+ test('updates state when values are entered', () => {
+ const createTaskRequestMock = jest.fn();
+ render();
+ const startDateInput = screen.getByLabelText(
+ /Start date:/i
+ ) as HTMLInputElement;
+ const endDateInput = screen.getByLabelText(
+ /End date:/i
+ ) as HTMLInputElement;
+ const descriptionTextarea = screen.getByLabelText(
+ /Description:/i
+ ) as HTMLTextAreaElement;
+ fireEvent.change(startDateInput, { target: { value: '2023-10-17' } });
+ fireEvent.change(endDateInput, { target: { value: '2023-10-24' } });
+ fireEvent.change(descriptionTextarea, {
+ target: { value: 'Test description' },
+ });
+ expect(startDateInput.value).toBe('2023-10-17');
+ expect(endDateInput.value).toBe('2023-10-24');
+ expect(descriptionTextarea.value).toBe('Test description');
+ });
+ test('submits form and calls createTaskRequest function', async () => {
+ const createTaskRequestMock = jest.fn();
+ render();
+ const submitButton = screen.getByRole('button', {
+ name: /Create Request/i,
+ });
+ fireEvent.click(submitButton);
+ await waitFor(() => {
+ expect(createTaskRequestMock).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/__tests__/Unit/Components/modal/index.test.tsx b/__tests__/Unit/Components/modal/index.test.tsx
new file mode 100644
index 000000000..cda8b3bb4
--- /dev/null
+++ b/__tests__/Unit/Components/modal/index.test.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import Modal from '@/components/Modal/index';
+
+describe('Modal Component', () => {
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+ test('renders modal when isOpen is true', () => {
+ const mockedFunction = jest.fn();
+ const { getByTestId } = render(
+
+ );
+ const modalOverlay = getByTestId('modal-overlay');
+ const modalBox = getByTestId('modal-box');
+ expect(modalOverlay).toBeInTheDocument();
+ expect(modalBox).toBeInTheDocument();
+ });
+
+ test('does not render modal when isOpen is false', () => {
+ const mockedFunction = jest.fn();
+ const { queryByTestId } = render(
+
+ );
+ const modalOverlay = queryByTestId('modal-overlay');
+ const modalBox = queryByTestId('modal-box');
+ expect(modalOverlay).toBeNull();
+ expect(modalBox).toBeNull();
+ });
+
+ test('toggle should be called when overlay is clicked', () => {
+ const toggleMock = jest.fn();
+ const { getByTestId } = render(
+
+ );
+ const modalOverlay = getByTestId('modal-overlay');
+ fireEvent.click(modalOverlay);
+ expect(toggleMock).toHaveBeenCalled();
+ });
+
+ test('toggle should not be called when modal is clicked', () => {
+ const toggleMock = jest.fn();
+ const { getByTestId } = render(
+
+ );
+ const modalBox = getByTestId('modal-box');
+ fireEvent.click(modalBox);
+ expect(toggleMock).not.toHaveBeenCalled();
+ });
+});
diff --git a/src/components/Modal/Modal b/src/components/Modal/Modal
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx
new file mode 100644
index 000000000..04f36bbd7
--- /dev/null
+++ b/src/components/Modal/index.tsx
@@ -0,0 +1,30 @@
+import React, { ReactNode } from 'react';
+import styles from '@/components/Modal/modal.module.scss';
+
+interface ModalType {
+ children?: ReactNode;
+ isOpen: boolean;
+ toggle: () => void;
+}
+
+export default function Modal(props: ModalType) {
+ return (
+ <>
+ {props.isOpen && (
+
+
e.stopPropagation()}
+ className={styles.modalBox}
+ data-testid="modal-box"
+ >
+ {props.children}
+
+
+ )}
+ >
+ );
+}
diff --git a/src/components/Modal/modal.module.scss b/src/components/Modal/modal.module.scss
new file mode 100644
index 000000000..a146406eb
--- /dev/null
+++ b/src/components/Modal/modal.module.scss
@@ -0,0 +1,31 @@
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+.modalOverlay {
+ z-index: 9999;
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ top: 0;
+ left: 0;
+ background: rgba(0, 0, 0, 0.7);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.modalBox {
+ display: block;
+ background: white;
+ width: max-content;
+ height: max-content;
+ padding: 1rem;
+ border-radius: 1rem;
+ animation: fadeIn ease-in-out 250ms;
+}
diff --git a/src/components/issues/TaskRequestForm.tsx b/src/components/issues/TaskRequestForm.tsx
new file mode 100644
index 000000000..55bfd3f81
--- /dev/null
+++ b/src/components/issues/TaskRequestForm.tsx
@@ -0,0 +1,144 @@
+import { FC, MouseEvent, useReducer, useState } from 'react';
+
+import styles from '@/components/issues/Card.module.scss';
+
+import { reducerAction } from '@/types/ProgressUpdates';
+import { Loader } from '../tasks/card/Loader';
+
+type ActionFormReducer = {
+ startedOn: number | string;
+ endsOn: number | string;
+ description: string | undefined;
+};
+
+type ActionFormProps = {
+ requestId?: string;
+ taskId?: string;
+ createTaskRequest: (data: ActionFormReducer) => Promise;
+};
+
+const date = new Date();
+const today = date.toISOString().split('T')[0];
+date.setDate(date.getDate() + 7);
+const sevenDaysFromToday = date.toISOString().split('T')[0];
+
+const initialState = {
+ endsOn: Date.now(),
+ startedOn: Date.now(),
+ description: ' ',
+};
+
+const reducer = (state: ActionFormReducer, action: reducerAction) => {
+ switch (action.type) {
+ case 'endsOn':
+ return {
+ ...state,
+ endsOn: new Date(`${action.value}`).getTime(),
+ };
+ case 'startedOn':
+ return {
+ ...state,
+ startedOn: new Date(`${action.value}`).getTime(),
+ };
+ case 'description':
+ return {
+ ...state,
+ description: action.value,
+ };
+ default:
+ return state;
+ }
+};
+
+const TaskRequestForm: FC = ({
+ requestId,
+ createTaskRequest,
+ taskId,
+}) => {
+ console.log(requestId);
+ const [state, dispatch] = useReducer(reducer, initialState, undefined);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const handleSubmit = async (e: MouseEvent) => {
+ e.preventDefault();
+ setIsLoading(true);
+ await createTaskRequest(state);
+ setIsLoading(false);
+ };
+
+ return (
+
+ );
+};
+
+export default TaskRequestForm;