Repository: Real-Dev-Squad/website-dashboard
Pull request #1002: feat: add util functions for request card
Author: login: AnujChhikara
Created: 2025-05-22T05:39:06Z | Merged: 2025-05-25T18:57:35Z

<!-- Date Here in dd mmm yyyy-->
Date: 22 May 2025
<!--Developer Name Here-->
Developer Name: @AnujChhikara 

---

## Issue Ticket Number
<!--Issue ticket this PR closes-->
- #975 
## Description
- This PR introduces a new function createActionContainer responsible for dynamically generating action elements (buttons, status indicators, input fields) for request cards based on the request type and status.

- Test PR #994 
<!--Description of the changes made in this PR-->

### Documentation Updated?

- [ ] Yes
- [x] No

<!--Additional notes about documentation update if applicable-->

### Under Feature Flag

- [x] Yes
- [ ] No

<!--Indicate if changes are under a feature flag-->

### Database Changes

- [ ] Yes
- [x] No

<!--Notes on any database changes-->

### Breaking Changes

- [ ] Yes
- [x] No

<!--Notes on breaking changes or related issue tickets if applicable-->

### Development Tested?

- [x] Yes
- [ ] No

<!--Confirmation of local testing during development-->
## Screenshots
<details>
<summary>Screenshot 1</summary>

<!-- Attach your screenshots here👇-->
- Note:  these are final Changes after all the PRs of this request card merged 
- Extension Request

https://github.com/user-attachments/assets/bbb406c9-33e6-49f0-9744-ec4d837f39f6

https://github.com/user-attachments/assets/ba68afa0-a4d8-4270-9a26-f5e845b267b6

https://github.com/user-attachments/assets/b4eab7c0-0b4f-4ae3-add2-9a329cf471cc
 

- OOO and Onboarding Requests



https://github.com/user-attachments/assets/ceac2abf-5223-45d9-943c-c96e7ef3249f


https://github.com/user-attachments/assets/44064387-932c-4585-9974-cf9f46254475


</details>

<!--Attach or link to relevant screenshots or visual aids-->

## Test Coverage
<details>
<summary>Screenshot 1</summary>

<!-- Attach your screenshots here👇-->
![image](https://github.com/user-attachments/assets/f2b149ee-af5a-4e65-a273-52b1ae374e06)
![image](https://github.com/user-attachments/assets/2b130a42-817f-4e75-ab7e-d2a90a31a315)
</details>

<!--Attach Details on test coverage and outcomes-->

## Additional Notes
Test PR: https://github.com/Real-Dev-Squad/website-dashboard/pull/994
<!--Any additional notes, considerations or explanations for reviewers-->



Diff:
diff --git a/__tests__/extension-requests/extension-requests.test.js b/__tests__/extension-requests/extension-requests.test.js
index fbd9e4d7..f395ae4f 100644
--- a/__tests__/extension-requests/extension-requests.test.js
+++ b/__tests__/extension-requests/extension-requests.test.js
@@ -643,32 +643,6 @@ describe('Tests the Extension Requests Screen', () => {
     const cardCount = extensionCardsAfter.length;
     expect(cardCount === 3 || cardCount === 7).toBe(true);
   });
-  it('checks whether the shimmer effect is visible under dev flag only for the assignee image element', async () => {
-    await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`);
-    const assignImageSelector = await page.$$(
-      '[data-testid="assignee-image skeleton"]',
-    );
-    expect(assignImageSelector).toBeTruthy();
-
-    await page.waitForTimeout(5000);
-    const hasSkeletonClassAfter = await page.$eval('.assignee-image', (el) =>
-      el.classList.contains('skeleton'),
-    );
-    expect(hasSkeletonClassAfter).toBe(false);
-  });
-
-  it('checks whether the shimmer effect is visible under dev flag only for the assignee name element', async () => {
-    await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`);
-    const assignNameSelector = await page.$$(
-      '[data-testid="assignee-name skeleton-text"]',
-    );
-    expect(assignNameSelector).toBeTruthy();
-    await page.waitForTimeout(5000);
-    const hasSkeletonClassAfter = await page.$eval('.assignee-name', (el) =>
-      el.classList.contains('skeleton-text'),
-    );
-    expect(hasSkeletonClassAfter).toBe(false);
-  });
 
   it('shows error messages for empty title and reason inputs on update under dev feature flag', async () => {
     await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`);
@@ -720,8 +694,8 @@ describe('Tests the Extension Requests Screen', () => {
 
     await page.click(editButtonSelector);
 
-    const extensionInputSelector = '[data-testid="extension-input"]';
-    const extensionErrorSelector = '[data-testid="extension-input-error"]';
+    const extensionInputSelector = '[data-testid="request-input"]';
+    const extensionErrorSelector = '[data-testid="request-input-error"]';
     await page.$eval(extensionInputSelector, (input) => {
       input.value = '2020-01-01';
     });
@@ -750,7 +724,7 @@ describe('Tests the Extension Requests Screen', () => {
 
     await page.type('[data-testid="title-text-input"]', 'Valid Title');
     await page.type('[data-testid="reason-input-text-area"]', 'Valid Reason');
-    await page.type('[data-testid="extension-input"]', '2050-01-01');
+    await page.type('[data-testid="request-input"]', '2050-01-01');
 
     await page.click(updateButtonSelector);
 
@@ -772,7 +746,7 @@ describe('Tests the Extension Requests Screen', () => {
     const titleInputSelector = '[data-testid="title-text-input"]';
     const reasonInputSelector = '[data-testid="reason-input-text-area"]';
     const titleDisplaySelector = '.title-text';
-    const reasonDisplaySelector = '.reason-text';
+    const reasonDisplaySelector = '[data-testid="request-reason"]';
 
     const longTitle = 'A'.repeat(300);
     const longReason = 'This is a very long reason '.repeat(50);
@@ -811,8 +785,8 @@ describe('Tests the Extension Requests Screen', () => {
 
     await page.click(editButtonSelector);
 
-    const extensionInputSelector = '[data-testid="extension-input"]';
-    const extensionErrorSelector = '[data-testid="extension-input-error"]';
+    const extensionInputSelector = '[data-testid="request-input"]';
+    const extensionErrorSelector = '[data-testid="request-input-error"]';
 
     await page.$eval(extensionInputSelector, (input) => {
       input.value = 'invalid-date';
@@ -1206,7 +1180,7 @@ describe('Tests the Extension Requests Screen', () => {
     ).toBe(false);
     const toastMessage = await page.$('[data-testid="toast-message"]');
     expect(await toastMessage.evaluate((el) => el.textContent)).toBe(
-      'Extension request successfully updated.',
+      'Request updated successfully',
     );
   });
 
@@ -1222,13 +1196,15 @@ describe('Tests the Extension Requests Screen', () => {
     await page.click(`input[type="checkbox"][id="DENIED"]`);
     await page.click(applyFilterButton);
     await page.waitForNetworkIdle();
-    const extensionRequestCards = await page.$$('.extension-card');
+    const extensionRequestCards = await page.$$(
+      '[data-testid="extension-request-card"]',
+    );
     expect(extensionRequestCards.length).toBe(
       extensionRequestListForAuditLogs.allExtensionRequests.length,
     );
   });
 
-  it.skip('should display all the required field in the extension request card under feature flag', async () => {
+  it('should display all the required field in the extension request card under feature flag', async () => {
     await page.goto(
       `${LOCAL_TEST_PAGE_URL}/extension-requests?order=desc&dev=true&size=1&q=status%3APENDING`,
     );
@@ -1258,7 +1234,7 @@ describe('Tests the Extension Requests Screen', () => {
     expect(taskTitle).toContain(taskDone.taskData.title);
   });
 
-  it.skip('should remove the card from display after approving the request under feature flag', async () => {
+  it('should remove the card from display after approving the request under feature flag', async () => {
     await page.goto(
       `${LOCAL_TEST_PAGE_URL}/extension-requests?order=desc&dev=true&size=1&q=status%3APENDING`,
     );
@@ -1280,7 +1256,7 @@ describe('Tests the Extension Requests Screen', () => {
     expect(extensionCardsAfter.length).toBe(0);
   });
 
-  it.skip('should remove the card from display after rejecting the request under feature flag', async () => {
+  it('should remove the card from display after rejecting the request under feature flag', async () => {
     await page.goto(
       `${LOCAL_TEST_PAGE_URL}/extension-requests?order=desc&dev=true&size=1&q=status%3APENDING`,
     );
diff --git a/__tests__/requests/requests.test.js b/__tests__/requests/requests.test.js
index 55fb324e..b3da518e 100644
--- a/__tests__/requests/requests.test.js
+++ b/__tests__/requests/requests.test.js
@@ -95,7 +95,9 @@ describe('Tests the request cards', () => {
           body: JSON.stringify(requestActionResponse),
         });
       } else if (
-        url === `${STAGING_API_URL}/requests?dev=true&id=Wl4TTbpSrQDIjs6KLJwD`
+        url ===
+          `${STAGING_API_URL}/requests?dev=true&id=Wl4TTbpSrQDIjs6KLJwD` ||
+        url === `${STAGING_API_URL}/requests/Wl4TTbpSrQDIjs6KLJwD`
       ) {
         interceptedRequest.respond({
           status: 200,
@@ -568,15 +570,8 @@ describe('Tests the request cards', () => {
     await page.goto(`${LOCAL_TEST_PAGE_URL}/requests?dev=true`);
     await page.waitForNetworkIdle();
     await page.click('#ooo_tab_link');
-    await page.waitForSelector('.request__status');
-
-    const statusButtonText = await page.$eval(
-      '.request__status',
-      (el) => el.textContent,
-    );
-    expect(statusButtonText).toBe('Pending');
-
-    await page.click('.request__action__btn.accept__btn');
+    await page.waitForNetworkIdle();
+    await page.click('.approve-button');
     await page.waitForSelector('[data-testid="toast-component"].show');
     const toastComponent = await page.$('[data-testid="toast-component"]');
     expect(
@@ -615,13 +610,13 @@ describe('Tests the request cards', () => {
     expect(requestCards.length).toBe(approvedRequestsData.data.length);
 
     const statusText = await requestCards[0].$eval(
-      '[data-testid="request-status"]',
+      '[data-testid="request-card-status"]',
       (el) => el.textContent,
     );
-    expect(statusText).toContain('Approved');
+    expect(statusText).toContain('APPROVED');
   });
 
-  describe.skip('Test Request Card (Dev Mode Enabled)', () => {
+  describe('Test Request Card (Dev Mode Enabled)', () => {
     beforeEach(async () => {
       await page.goto(`${LOCAL_TEST_PAGE_URL}/requests?dev=true`);
       await page.waitForNetworkIdle();
diff --git a/components/request-card/constant.js b/components/request-card/constant.js
new file mode 100644
index 00000000..49f84b37
--- /dev/null
+++ b/components/request-card/constant.js
@@ -0,0 +1,39 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const HOVER_CARD_HIDE_DELAY = 300;
+const ICONS = Object.freeze({
+  DEFAULT_USER_AVATAR: '/images/avatar.png',
+  EDIT: '/images/edit-icon.svg',
+  CANCEL: '/images/x-icon.svg',
+  CANCEL_WHITE: '/images/x-icon-white.svg',
+  CHECK: '/images/check-icon.svg',
+  CHECK_WHITE: '/images/check-icon-white.svg',
+  ARROW_DOWN: '/images/chevron-down-black.svg',
+});
+
+const REQUEST_STATUS = Object.freeze({
+  APPROVED: 'APPROVED',
+  PENDING: 'PENDING',
+  DENIED: 'DENIED',
+  REJECTED: 'REJECTED',
+});
+
+const REQUEST_TYPE = Object.freeze({
+  EXTENSION: 'EXTENSION',
+  OOO: 'OOO',
+  ONBOARDING: 'ONBOARDING',
+});
+
+const ERROR_MESSAGE = Object.freeze({
+  UPDATE: 'Error updating request',
+  DATE_INPUT_ERROR: 'Invalid date format. Please provide a valid date.',
+  DEADLINE_PASSED: "Past date can't be the new deadline.",
+});
+
+const SUCCESS_MESSAGE = Object.freeze({
+  APPROVED: 'Request approved successfully',
+  REJECTED: 'Request rejected successfully',
+  UPDATED: 'Request updated successfully',
+});
diff --git a/components/request-card/script.js b/components/request-card/script.js
index 2a60c6d6..b4ac99f0 100644
--- a/components/request-card/script.js
+++ b/components/request-card/script.js
@@ -83,7 +83,7 @@ async function createRequestCardComponent({
       isDeadLineCrossed: requestDetails.isDeadlineCrossed,
       deadlineDays: requestDetails.deadlineDays,
       data,
-      oldEndsOn: requestDetails.oldEndsOnInMillisecond,
+      oldEndsOnValue: requestDetails.oldEndsOnInMillisecond,
       isStatusPending: requestDetails.statusPending,
     });
   const {
@@ -126,7 +126,13 @@ async function createRequestCardComponent({
       titleInputWrapper,
     },
     uiHandlers: { toggleInputs, appendLogs },
-    domRefs: { panel, accordionButton, rootElement, parentContainer },
+    domRefs: {
+      panel,
+      accordionButton,
+      rootElement,
+      parentContainer,
+      requestDetails,
+    },
   });
 
   titleInputWrapper.append(titleInput, titleInputError);
@@ -153,12 +159,12 @@ async function createRequestCardComponent({
   taskStatusContainer.append(taskStatusTextLabel, taskStatusElement);
   summaryContainer.append(datesContainer);
   newDeadlineValue.append(newEndsOnTooltip);
-  requestForValue.append(requestCreatedAtTooltip);
+  requestForValue.append(newEndsOnTooltip.cloneNode(true));
 
   const requestNumberContainer = createElement({ type: 'div' });
   if (isExtensionRequest) {
     datesContainer.append(requestNumberContainer);
-  } else if (data.type !== RequestType.OOO) {
+  } else if (data.type !== REQUEST_TYPE.OOO) {
     taskDetailsContainer.append(requestNumberContainer);
   }
 
@@ -177,7 +183,7 @@ async function createRequestCardComponent({
 
   if (isExtensionRequest) {
     panel.append(logContainer);
-  } else if (data?.state !== RequestStatus.PENDING) {
+  } else if (data?.state !== REQUEST_STATUS.PENDING) {
     panel.append(commentContainer);
   }
 
@@ -243,7 +249,12 @@ async function createRequestCardComponent({
         data.title = formData.title;
         data.newEndsOn = formData.newEndsOn;
         showSuccessHighlight(rootElement);
-        showToast(SUCCESS_MESSAGE, 'success');
+        showToastMessage({
+          isDev: true,
+          oldToastFunction: showToast,
+          type: 'success',
+          message: SUCCESS_MESSAGE.UPDATED,
+        });
 
         appendLogs(payloadForLog, data.id);
       })
@@ -252,8 +263,15 @@ async function createRequestCardComponent({
         showErrorHighlight(rootElement);
 
         const errorMessage =
-          error?.response?.data?.message || error?.message || ERROR_MESSAGE;
-        showToast(errorMessage, 'error');
+          error?.response?.data?.message ||
+          error?.message ||
+          ERROR_MESSAGE.UPDATE;
+        showToastMessage({
+          isDev: true,
+          oldToastFunction: showToast,
+          type: 'error',
+          message: errorMessage,
+        });
       })
       .finally(() => {
         rootElement.classList.remove('disabled');
@@ -306,16 +324,49 @@ async function createRequestCardComponent({
   function toggleInputs() {
     titleInputWrapper.classList.toggle('hidden');
     titleInput.classList.toggle('hidden');
-    titleInputError.classList.toggle('hidden');
     titleText.classList.toggle('hidden');
     reasonInput.classList.toggle('hidden');
     reasonParagraph.classList.toggle('hidden');
-    reasonInputError.classList.toggle('hidden');
     newDeadlineValue.classList.toggle('hidden');
     requestInput.classList.toggle('hidden');
   }
 
-  const userImage = requestUser?.picture?.url ?? DEFAULT_USER_AVATAR;
+  async function renderLogs(extensionRequestId) {
+    const logContainer = document.getElementById(
+      `log-container-${extensionRequestId}`,
+    );
+    if (logContainer.querySelector('.server-log')?.innerHTML) {
+      return;
+    }
+    try {
+      const extensionLogs = await getExtensionRequestLogs({
+        extensionRequestId,
+      });
+      const innerHTML = generateSentence(
+        extensionLogs.logs,
+        'server-log',
+        extensionRequestId,
+      );
+      if (innerHTML) {
+        const isLocalLogPresent = logContainer.querySelectorAll('.local-log');
+        if (isLocalLogPresent) {
+          const tempDiv = document.createElement('div');
+          tempDiv.classList.add('invisible-div');
+          tempDiv.innerHTML = innerHTML;
+
+          const localLogElement = logContainer.querySelector('.local-log');
+          logContainer.insertBefore(tempDiv, localLogElement);
+        } else {
+          logContainer.innerHTML += innerHTML;
+        }
+        updateAccordionHeight(panel);
+      }
+    } catch (error) {
+      console.error('Failed to fetch extension request logs:', error);
+    }
+  }
+
+  const userImage = requestUser?.picture?.url ?? ICONS.DEFAULT_USER_AVATAR;
   let userFirstName = requestUser?.first_name ?? data.assignee;
   const userId = requestUser?.id;
   const userStatus = userStatusMap?.get(userId);
@@ -376,10 +427,11 @@ async function createRequestCardComponent({
 
 function prepareRequestCardData({ data, isExtensionRequest }) {
   const currentTimestamp = Date.now();
-  let oldEndsOn = data.oldEndsOn;
-  let newEndsOn = data.newEndsOn;
 
-  if (data.type === RequestType.OOO) {
+  let oldEndsOn = data?.oldEndsOn;
+  let newEndsOn = data?.newEndsOn;
+
+  if (data.type === REQUEST_TYPE.OOO) {
     oldEndsOn = data.from;
     newEndsOn = data.until;
   }
@@ -399,11 +451,9 @@ function prepareRequestCardData({ data, isExtensionRequest }) {
 
   const isDeadlineCrossed = currentTimestamp > oldEndsOnInMillisecond;
   const isNewDeadlineCrossed = currentTimestamp > newEndsOnInMillisecond;
-
   const statusPending = isExtensionRequest
-    ? data.status === RequestStatus.PENDING
-    : data.state === RequestStatus.PENDING;
-
+    ? data.status === REQUEST_STATUS.PENDING
+    : data.state === REQUEST_STATUS.PENDING;
   const deadlineDays = dateDiff(
     currentTimestamp,
     oldEndsOnInMillisecond,
@@ -416,7 +466,7 @@ function prepareRequestCardData({ data, isExtensionRequest }) {
         newEndsOnInMillisecond,
         (d) => d + (isNewDeadlineCrossed ? ' ago' : ''),
       )
-    : getTwoDigitDate(newEndsOn);
+    : getTwoDigitDate(newEndsOnInMillisecond, true);
 
   return {
     oldEndsOnInMillisecond,
@@ -585,7 +635,7 @@ function createAccordionContainer() {
   const downArrowIcon = createElement({
     type: 'img',
     attributes: {
-      src: ICON_ARROW_DOWN,
+      src: ICONS.ARROW_DOWN,
       alt: 'down-arrow',
     },
   });
diff --git a/components/request-card/utils.js b/components/request-card/utils.js
index 935576fe..5cbf6f52 100644
--- a/components/request-card/utils.js
+++ b/components/request-card/utils.js
@@ -1,5 +1,5 @@
-function normalizeToMilliseconds(time, isExtensionRequest) {
-  return isExtensionRequest ? time * 1000 : time;
+function getTimeInMilliseconds(time, isInSeconds) {
+  return isInSeconds ? time * 1000 : time;
 }
 const getRequestColor = (deadline, createdTime) => {
   const wasDeadlineBreached = createdTime > deadline;
@@ -12,7 +12,7 @@ const getRequestColor = (deadline, createdTime) => {
   }
   return 'orange-text';
 };
-const formatToFullDate = (timestamp) => {
+const formatToFullDate = (timestamp, locale = 'en-US') => {
   const options = {
     weekday: 'long',
     year: 'numeric',
@@ -23,10 +23,10 @@ const formatToFullDate = (timestamp) => {
     timeZoneName: 'short',
     hour12: true,
   };
-  return new Intl.DateTimeFormat('en-US', options).format(new Date(timestamp));
+  return new Intl.DateTimeFormat(locale, options).format(new Date(timestamp));
 };
 const getTwoDigitDate = (timestamp, isInSeconds = false) => {
-  const normalizedTime = normalizeToMilliseconds(timestamp, isInSeconds);
+  const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
 
   return new Intl.DateTimeFormat('en-US', {
     day: '2-digit',
@@ -41,6 +41,9 @@ function formatToDateOnly(milliseconds) {
     '0',
   )}-${String(date.getDate()).padStart(2, '0')}`;
 }
+async function addDelay(milliSeconds) {
+  await new Promise((resolve) => setTimeout(resolve, milliSeconds));
+}
 function getFormEntries(formData) {
   if (!formData) return;
   const result = {};
@@ -52,7 +55,7 @@ function getFormEntries(formData) {
 const addLoadingSpinner = (container) => {
   const spinner = createElement({
     type: 'div',
-    attributes: { class: 'loading-spinner' },
+    attributes: { class: 'spinner' },
   });
 
   container.append(spinner);
@@ -121,7 +124,12 @@ async function updateRequestStatus({ id, body, isExtensionRequest }) {
 
   return await res.json();
 }
-async function removeCard(element, elementClass, parentContainer) {
+async function removeRequestCard(
+  element,
+  elementClass,
+  parentContainer,
+  cleanupEventListener,
+) {
   element.classList.add(elementClass);
   await addDelay(800);
   element.style.overflow = 'hidden';
@@ -160,6 +168,7 @@ async function removeCard(element, elementClass, parentContainer) {
       if (parentContainer.innerHTML === '') {
         addEmptyPageMessage(parentContainer);
       }
+      cleanupEventListener();
     });
 }
 function createSummarySection({
@@ -179,7 +188,7 @@ function createSummarySection({
     type: 'div',
     attributes: { class: 'task-details-container' },
   });
-  summaryContainer.appendChild(taskDetailsContainer);
+  summaryContainer.append(taskDetailsContainer);
 
   const statusSiteLink = createElement({
     type: 'a',
@@ -202,13 +211,12 @@ function createSummarySection({
     type: 'div',
     attributes: { id: 'requestType-container' },
   });
-  taskTitle.appendChild(statusSiteLink);
+  taskTitle.append(statusSiteLink);
 
   if (isExtensionRequest) {
-    taskDetailsContainer.appendChild(taskTitle);
-    taskDetailsContainer.appendChild(deadlineContainer);
+    taskDetailsContainer.append(taskTitle, deadlineContainer);
   } else {
-    taskDetailsContainer.appendChild(requestTypeContainer);
+    taskDetailsContainer.append(requestTypeContainer);
   }
 
   const deadlineText = createElement({
@@ -223,9 +231,6 @@ function createSummarySection({
     innerText: 'Request Type ',
   });
 
-  requestTypeContainer.appendChild(requestType);
-  deadlineContainer.appendChild(deadlineText);
-
   const deadlineValue = createElement({
     type: 'span',
     innerText: `${deadlineDays}`,
@@ -238,19 +243,20 @@ function createSummarySection({
 
   const requestTypeText = createElement({
     type: 'span',
+    attributes: {
+      'data-testid': 'request-type',
+    },
     innerText: data?.type,
   });
 
-  deadlineContainer.appendChild(deadlineValue);
-  requestTypeContainer.appendChild(requestTypeText);
   const deadlineTooltip = createElement({
     type: 'span',
     attributes: { class: 'tooltip' },
-    innerText: `${formatToFullDate(
-      normalizeToMilliseconds(oldEndsOnValue, isExtensionRequest),
-    )}`,
+    innerText: `${formatToFullDate(oldEndsOnValue)}`,
   });
-  deadlineValue.appendChild(deadlineTooltip);
+  deadlineValue.append(deadlineTooltip);
+  requestTypeContainer.append(requestType, requestTypeText);
+  deadlineContainer.append(deadlineText, deadlineValue);
 
   return { summaryContainer, taskDetailsContainer, statusSiteLink };
 }
@@ -266,7 +272,10 @@ function createTextBlockContainer(data, isForReasonComponent) {
 
   const paragraph = createElement({
     type: 'p',
-    attributes: { class: 'text-block-content' },
+    attributes: {
+      class: 'text-block-content',
+      'data-testid': isForReasonComponent ? 'request-reason' : 'request-remark',
+    },
     innerText: isForReasonComponent ? data.reason : data.message,
   });
 
@@ -276,7 +285,7 @@ function createTextBlockContainer(data, isForReasonComponent) {
       class: 'input-text-area hidden',
       id: 'reason',
       name: 'reason',
-      'data-testid': 'reason-input',
+      'data-testid': 'reason-input-text-area',
     },
     innerText: data.reason,
   });
@@ -296,17 +305,10 @@ function createTextBlockContainer(data, isForReasonComponent) {
   });
 
   if (isForReasonComponent) {
-    container.appendChild(title);
-    container.appendChild(detailsLine);
-    container.appendChild(textAreaInput);
-    container.appendChild(inputError);
-    container.appendChild(paragraph);
+    container.append(title, detailsLine, textAreaInput, inputError, paragraph);
   } else {
-    container.appendChild(title);
-    container.appendChild(detailsLine);
-    container.appendChild(paragraph);
+    container.append(title, detailsLine, paragraph);
   }
-
   return {
     container,
     textAreaInput,
@@ -371,9 +373,7 @@ function createDateContainer(
       name: 'newEndsOn',
       id: 'newEndsOn',
       oninput: 'this.blur()',
-      value: formatToDateOnly(
-        normalizeToMilliseconds(newEndsOnValue, isExtensionRequest),
-      ),
+      value: formatToDateOnly(newEndsOnValue),
       'data-testid': 'request-input',
     },
   });
@@ -416,41 +416,32 @@ function createDateContainer(
   const fromDateValue = createElement({
     type: 'span',
     attributes: { class: 'tooltip-container' },
-    innerText: getTwoDigitDate(oldEndsOnValue),
+    innerText: getTwoDigitDate(oldEndsOnValue, isExtensionRequest),
   });
 
   const fromDateValueToolTip = createElement({
     type: 'span',
     attributes: { class: 'tooltip' },
-    innerText: formatToFullDate(
-      normalizeToMilliseconds(oldEndsOnValue, isExtensionRequest),
-    ),
+    innerText: formatToFullDate(oldEndsOnValue),
   });
 
-  datesDetailsContainer.appendChild(requestDetailsHeading);
-  datesDetailsContainer.appendChild(requestDetailsLine);
-
-  newDeadlineContainer.appendChild(newDeadlineText);
-  newDeadlineContainer.appendChild(newDeadlineValue);
-  newDeadlineContainer.appendChild(requestInput);
-  newDeadlineContainer.appendChild(requestInputError);
-
-  requestForContainer.appendChild(requestForText);
-  requestForContainer.appendChild(requestForValue);
-
-  fromDateContainer.appendChild(fromDateText);
-  fromDateContainer.appendChild(fromDateValue);
-
-  fromDateValue.appendChild(fromDateValueToolTip);
+  datesDetailsContainer.append(requestDetailsHeading, requestDetailsLine);
+  newDeadlineContainer.append(
+    newDeadlineText,
+    newDeadlineValue,
+    requestInput,
+    requestInputError,
+  );
 
-  datesContainer.appendChild(datesDetailsContainer);
+  requestForContainer.append(requestForText, requestForValue);
+  fromDateValue.append(fromDateValueToolTip);
+  fromDateContainer.append(fromDateText, fromDateValue);
+  datesContainer.append(datesDetailsContainer);
 
   if (isExtensionRequest) {
-    datesContainer.appendChild(newDeadlineContainer);
-    datesContainer.appendChild(requestForContainer);
+    datesContainer.append(newDeadlineContainer, requestForContainer);
   } else {
-    datesContainer.appendChild(fromDateContainer);
-    datesContainer.appendChild(newDeadlineContainer);
+    datesContainer.append(fromDateContainer, newDeadlineContainer);
   }
 
   return {
@@ -461,3 +452,434 @@ function createDateContainer(
     requestForValue,
   };
 }
+
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const eventListenerRemovers = [];
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === REQUEST_STATUS.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: REQUEST_STATUS.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? REQUEST_STATUS.DENIED : REQUEST_STATUS.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? REQUEST_STATUS.DENIED
+        : REQUEST_STATUS.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const saveButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, saveButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICONS.CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    function onEditClick(event) {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) accordionButton.click();
+      expandAccordionPanel(panel);
+    }
+
+    function onSaveClick(event) {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ERROR_MESSAGE.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ERROR_MESSAGE.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(true);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    }
+
+    function onCancelClick(event) {
+      event.preventDefault();
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    }
+
+    async function onApproveClick(event) {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = REQUEST_STATUS.APPROVED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: REQUEST_STATUS.APPROVED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: true,
+        appendLogs,
+        cleanupEventListener,
+      });
+    }
+
+    async function onRejectClick(event) {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = REQUEST_STATUS.DENIED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: isExtensionRequest
+          ? REQUEST_STATUS.DENIED
+          : REQUEST_STATUS.REJECTED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: false,
+        appendLogs,
+        cleanupEventListener,
+      });
+    }
+
+    function onApproveEnter() {
+      approveIcon.src = ICONS.CHECK_WHITE;
+    }
+
+    function onApproveLeave() {
+      approveIcon.src = ICONS.CHECK;
+    }
+
+    function onRejectEnter() {
+      rejectIcon.src = ICONS.CANCEL_WHITE;
+    }
+
+    function onRejectLeave() {
+      rejectIcon.src = ICONS.CANCEL;
+    }
+
+    editButton.addEventListener('click', onEditClick);
+    eventListenerRemovers.push(() =>
+      editButton.removeEventListener('click', onEditClick),
+    );
+
+    saveButton.addEventListener('click', onSaveClick);
+    eventListenerRemovers.push(() =>
+      saveButton.removeEventListener('click', onSaveClick),
+    );
+
+    cancelButton.addEventListener('click', onCancelClick);
+    eventListenerRemovers.push(() =>
+      cancelButton.removeEventListener('click', onCancelClick),
+    );
+
+    approveButton.addEventListener('click', onApproveClick);
+    eventListenerRemovers.push(() =>
+      approveButton.removeEventListener('click', onApproveClick),
+    );
+
+    approveButton.addEventListener('mouseenter', onApproveEnter);
+    eventListenerRemovers.push(() =>
+      approveButton.removeEventListener('mouseenter', onApproveEnter),
+    );
+
+    approveButton.addEventListener('mouseleave', onApproveLeave);
+    eventListenerRemovers.push(() =>
+      approveButton.removeEventListener('mouseleave', onApproveLeave),
+    );
+
+    rejectButton.addEventListener('click', onRejectClick);
+    eventListenerRemovers.push(() =>
+      rejectButton.removeEventListener('click', onRejectClick),
+    );
+
+    rejectButton.addEventListener('mouseenter', onRejectEnter);
+    eventListenerRemovers.push(() =>
+      rejectButton.removeEventListener('mouseenter', onRejectEnter),
+    );
+
+    rejectButton.addEventListener('mouseleave', onRejectLeave);
+    eventListenerRemovers.push(() =>
+      rejectButton.removeEventListener('mouseleave', onRejectLeave),
+    );
+
+    function cleanupEventListener() {
+      eventListenerRemovers.forEach((fn) => fn());
+    }
+
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    function setActionButtonsVisibility(shouldShow) {
+      const displayValue = shouldShow ? 'block' : 'none';
+      approveButton.style.display = displayValue;
+      rejectButton.style.display = displayValue;
+    }
+  }
+  return requestActionContainer;
+}
+
+function buildRequestBody({ isExtensionRequest, data, remarkMessage, status }) {
+  let requestBody;
+
+  if (isExtensionRequest) {
+    requestBody = {
+      status: status,
+    };
+  } else if (!remarkMessage) {
+    requestBody = {
+      type: data?.type,
+      state: status,
+    };
+  } else {
+    requestBody = {
+      type: data?.type,
+      state: status,
+      message: remarkMessage,
+    };
+  }
+  return requestBody;
+}
+
+async function handleRequestStatusUpdate({
+  id,
+  reqBody,
+  isExtensionRequest,
+  payloadForLog,
+  rootElement,
+  parentContainer,
+  isApproved,
+  removeSpinner,
+  appendLogs,
+  cleanupEventListener,
+}) {
+  const toastMessage = isApproved
+    ? SUCCESS_MESSAGE.APPROVED
+    : SUCCESS_MESSAGE.REJECTED;
+  const cardClass = isApproved ? 'green-card' : 'red-card';
+
+  try {
+    await updateRequestStatus({
+      id,
+      body: reqBody,
+      isExtensionRequest,
+    });
+
+    removeSpinner();
+
+    if (isExtensionRequest) {
+      appendLogs(payloadForLog, id);
+    }
+
+    showToastMessage({
+      isDev: true,
+      oldToastFunction: showToast,
+      type: 'success',
+      message: toastMessage,
+    });
+
+    await removeRequestCard(
+      rootElement,
+      cardClass,
+      parentContainer,
+      cleanupEventListener,
+    );
+  } catch (error) {
+    console.error(error);
+    removeSpinner();
+    showErrorHighlight(rootElement);
+  } finally {
+    rootElement.classList.remove('disabled');
+  }
+}
diff --git a/extension-requests/index.html b/extension-requests/index.html
index 252fc14b..af3595f1 100644
--- a/extension-requests/index.html
+++ b/extension-requests/index.html
@@ -10,6 +10,9 @@
     <title>Extension Requests</title>
     <script src="/components/filter/script.js" defer></script>
     <script src="/navbar.global.js" async></script>
+    <script src="/components/request-card/utils.js" defer></script>
+    <script src="/components/request-card/constant.js" defer></script>
+    <script src="/components/request-card/script.js" defer></script>
     <script src="/components/toast/script.js" defer></script>
     <script src="/userLogin.js" async></script>
   </head>
diff --git a/extension-requests/script.js b/extension-requests/script.js
index 79255688..a6063d41 100644
--- a/extension-requests/script.js
+++ b/extension-requests/script.js
@@ -268,10 +268,22 @@ async function populateExtensionRequests(query = {}, newLink) {
     if (currentVersion !== extensionPageVersion) {
       return;
     }
-    for (let data of allExtensionRequests) {
-      if (query.dev) {
-        createExtensionCard(data, true);
-      } else {
+    if (query.dev) {
+      await Promise.all(
+        allExtensionRequests.map(async (data) => {
+          const requestUser = await getUser(data.assignee);
+          createRequestCardComponent({
+            data,
+            isExtensionRequest: true,
+            parentContainer: extensionRequestsContainer,
+            currentUser: currentUserDetails,
+            requestUser,
+            userStatusMap,
+          });
+        }),
+      );
+    } else {
+      for (let data of allExtensionRequests) {
         createExtensionCard(data);
       }
     }
diff --git a/extension-requests/style.css b/extension-requests/style.css
index f3166f3a..baea5d94 100644
--- a/extension-requests/style.css
+++ b/extension-requests/style.css
@@ -41,7 +41,8 @@
   background-color: grey;
 }
 
-.extension-card {
+.extension-card,
+.request-card {
   border-radius: 10px;
   text-align: left;
   display: flex;
@@ -58,7 +59,8 @@
   transition: 800ms ease-in-out;
 }
 
-.extension-card-form {
+.extension-card-form,
+.request-card-form {
   display: flex;
   flex-direction: column;
   gap: 1rem;
@@ -110,6 +112,8 @@
 }
 
 .accordion img {
+  width: 1rem;
+  margin-top: 0.5rem;
   transition: transform 500ms ease, scale 100ms ease;
 }
 
@@ -158,6 +162,23 @@
   padding: 2px;
 }
 
+.reject-button {
+  width: 6.25rem;
+  height: 2rem;
+  background-color: var(--secondary10);
+  border-radius: 6px;
+  border: 1px solid var(--secondary600);
+  transition: 200ms ease-in-out;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 2px;
+}
+
+.reject-button:hover {
+  background-color: var(--secondary600);
+}
+
 .check-icon {
   margin-top: 4px;
 }
@@ -309,7 +330,8 @@
   color: var(--medium-gray);
 }
 
-.extension-card-buttons {
+.extension-card-buttons,
+.request-card-buttons {
   display: flex;
   gap: 0.5rem;
   margin-right: 3.5rem;
@@ -731,7 +753,8 @@ body {
 }
 
 /* Filter modal end */
-.commited-hours-trigger {
+.commited-hours-trigger,
+.committed-hours-trigger {
   width: 1.5rem;
   height: 1.5rem;
   cursor: pointer;
@@ -739,7 +762,8 @@ body {
 .hidden {
   display: none !important;
 }
-.comitted-hours {
+.comitted-hours,
+.committed-hours {
   width: 250px;
   height: 50px;
   position: absolute;
@@ -766,7 +790,8 @@ body {
 .label-content-missing {
   color: var(--secondary600);
 }
-.extension-request-header-wrapper {
+.extension-request-header-wrapper,
+.request-header-wrapper {
   width: 100%;
   display: flex;
   gap: 1rem;
@@ -869,7 +894,8 @@ body {
   .search-filter {
     justify-content: center;
   }
-  .comitted-hours {
+  .comitted-hours,
+  .committed-hours {
     right: 0.5rem;
   }
 }
diff --git a/images/chevron-down-black.svg b/images/chevron-down-black.svg
new file mode 100644
index 00000000..5264d99d
--- /dev/null
+++ b/images/chevron-down-black.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#000000" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
+	 viewBox="0 0 407.437 407.437" xml:space="preserve">
+<polygon points="386.258,91.567 203.718,273.512 21.179,91.567 0,112.815 203.718,315.87 407.437,112.815 "/>
+</svg>
\ No newline at end of file
diff --git a/requests/index.html b/requests/index.html
index 6b4d0909..77a2e41d 100644
--- a/requests/index.html
+++ b/requests/index.html
@@ -22,6 +22,7 @@
     <link rel="stylesheet" href="/components/toast/style.css" />
     <link rel="stylesheet" href="/requests/style.css" />
     <link rel="stylesheet" href="/components/filter/style.css" />
+    <link rel="stylesheet" href="/extension-requests/style.css" />
     <script src="/navbar.global.js" async></script>
     <script src="/userLogin.js" async></script>
     <script src="/helpers/loadENV.js"></script>
@@ -30,6 +31,9 @@
     <script src="/utils.js"></script>
     <script src="/components/filter/script.js" defer></script>
     <script src="/requests/script.js" defer></script>
+    <script src="/components/request-card/utils.js" defer></script>
+    <script src="/components/request-card/constant.js" defer></script>
+    <script src="/components/request-card/script.js" defer></script>
     <script src="/components/toast/script.js" defer></script>
   </head>
 
diff --git a/requests/script.js b/requests/script.js
index 946fcebc..9d8373f5 100644
--- a/requests/script.js
+++ b/requests/script.js
@@ -30,6 +30,17 @@ let userDetails = [];
 let nextLink = '';
 let isDataLoading = false;
 
+let currentUserDetails;
+
+getSelfUser()
+  .then((response) => {
+    currentUserDetails = response;
+  })
+  .catch((error) => {
+    currentUserDetails = null;
+    showMessage('ERROR', ErrorMessages.UNAUTHENTICATED);
+  });
+
 function updateTabLink(requestType) {
   if (requestType === OOO_REQUEST_TYPE) {
     oooTabLink.classList.add(selected__tab__class);
@@ -501,9 +512,19 @@ async function renderRequestCards(queries = {}) {
       if (request.state !== 'PENDING') {
         superUserDetails = await getUserDetails(request.lastModifiedBy);
       }
-      requestContainer.appendChild(
-        createRequestCard(request, superUserDetails, requesterUserDetails),
-      );
+      if (isDev) {
+        createRequestCardComponent({
+          data: request,
+          isExtensionRequest: false,
+          parentContainer: requestContainer,
+          currentUser: currentUserDetails,
+          requestUser: requesterUserDetails,
+        });
+      } else {
+        requestContainer.appendChild(
+          createRequestCard(request, superUserDetails, requesterUserDetails),
+        );
+      }
     }
   } catch (error) {
     console.error(error);
diff --git a/requests/style.css b/requests/style.css
index 61419d30..4dec2430 100644
--- a/requests/style.css
+++ b/requests/style.css
@@ -165,7 +165,15 @@ p {
   padding: 0.5rem;
   width: 8rem;
   margin-right: 1rem;
-  height: 1rem;
+}
+
+.remark-input-field {
+  width: 13rem;
+  border-radius: 0.5rem;
+  height: 2rem;
+  padding: 0.25rem 0.5rem;
+  border: 1px solid var(--black);
+  margin-bottom: 0.25rem;
 }
 
 .search__filter__container {
@@ -685,8 +693,8 @@ nav a:hover {
     justify-content: center;
   }
   .filter__container {
+    margin-left: 4rem;
     justify-content: center;
-    margin-left: 2rem;
   }
 }
 


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 8**

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 37988bb2f8a06fb7f5b71d73e69429774a1bc2e5 and 96b7d1bd1a4cd985bd80192c233d4bc7555e8aa3.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `components/request-card/constant.js` (1 hunks)
* `components/request-card/utils.js` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>components/request-card/utils.js (3)</summary><blockquote>

<details>
<summary>components/request-card/constant.js (5)</summary>

* `DEADLINE_WARNING_THRESHOLD_DAYS` (4-4)
* `ErrorMessage` (27-29)
* `CARD_REMOVAL_INITIAL_DELAY_MS` (1-1)
* `CARD_REMOVAL_ANIMATION_DURATION_MS` (2-2)
* `CARD_REMOVAL_ANIMATION_EASING` (3-3)

</details>
<details>
<summary>components/request-card/script.js (3)</summary>

* `createSummarySection` (80-88)
* `oldEndsOn` (379-379)
* `createDateContainer` (89-102)

</details>
<details>
<summary>extension-requests/script.js (2)</summary>

* `isStatusPending` (522-522)
* `isNewDeadLineCrossed` (520-521)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: Cloudflare Pages

</details>

<details>
<summary>🔇 Additional comments (1)</summary><blockquote>

<details>
<summary>components/request-card/utils.js (1)</summary>

`135-168`: _⚠️ Potential issue_

**DOM IDs reused for every card will break accessibility & CSS selectors**

Functions `createSummarySection` and `createDateContainer` inject elements with hard-coded `id` values (`deadline-container`, `new-deadline-container`, `newEndsOn`, etc.). When multiple cards are rendered, the page contains duplicate IDs – invalid HTML that can cause:

• `document.getElementById` to return the first match only  
• CSS rules to apply unpredictably  
• Screen-readers to misbehave

Convert these to classes or data-attributes, e.g.

```diff
-attributes: { id: 'deadline-container' },
+attributes: { class: 'deadline-container' },
```

and update any selector logic accordingly.




> Likely an incorrect or invalid review comment.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-22T05:52:11Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T05:56:06Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-22T05:56:33Z
user: login: MayankBansal12
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-23T06:27:45Z
user: login: pankajjs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T17:39:27Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T17:48:36Z
user: login: pankajjs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T17:52:10Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T17:58:12Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T17:59:51Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-23T18:34:09Z
user: login: pankajjs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T15:52:42Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T15:52:48Z
user: login: pankajjs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T15:55:59Z
user: login: pankajjs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T15:59:48Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T16:05:54Z
user: login: pankajjs
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T17:12:45Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-24T19:22:44Z
user: login: AnujChhikara
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-25T13:41:31Z
user: login: pankajjs
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-25T16:27:01Z
user: login: pankajjs
body: My comments have been addressed. Therefore approving it.
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-25T16:27:50Z
user: login: Suvidh-kaushik
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-25T17:44:31Z
user: login: iamitprakash
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-25T18:57:24Z

Review comments:
diff_hunk: @@ -0,0 +1,29 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
+const ICON_CANCEL = '/images/x-icon.svg';
+const ICON_CANCEL_WHITE = '/images/x-icon-white.svg';
+const ICON_CHECK = '/images/check-icon.svg';
+const ICON_CHECK_WHITE = '/images/check-icon-white.svg';
+const ICON_ARROW_DOWN = '/images/chevron-down-black.svg';
+const HOVER_CARD_HIDE_DELAY = 700;
path: components/request-card/constant.js
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Export & harden constants for reliable module consumption**

`utils.js` (and probably other modules) expect these constants to be in scope, but this file does not export anything.  
Unless every consumer is loaded **after** this script in a `<script>` tag (global-scope coupling), the values will be undefined in an ES-module or bundler context.

In addition, `RequestStatus` / `RequestType` are mutable objects; a stray write could silently break logic.

```diff
-const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
-…
-const RequestStatus = {
+export const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+…
+export const RequestStatus = Object.freeze({
   APPROVED: 'APPROVED',
   PENDING: 'PENDING',
   DENIED: 'DENIED',
   REJECTED: 'REJECTED',
-};
+});
+
+export const RequestType = Object.freeze({
+  EXTENSION: 'EXTENSION',
+  OOO: 'OOO',
+  ONBOARDING: 'ONBOARDING',
+});
```

• Switch to ES-module named exports (or `module.exports` in CJS)  
• Freeze the enums to prevent accidental mutation.

Down-stream imports then become:

```js
import { CARD_REMOVAL_INITIAL_DELAY_MS, RequestStatus } from './constant.js';
```



Also applies to: 14-30

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/constant.js lines 1 to 12, the constants are declared
but not exported, causing them to be undefined in ES-module or bundler contexts.
Fix this by adding named exports for all constants. Additionally, for mutable
objects like RequestStatus and RequestType (lines 14-30), freeze them using
Object.freeze to prevent accidental mutation. This ensures reliable module
consumption and immutability of enums.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-22T05:52:09Z
author_association: NONE
diff_hunk: @@ -0,0 +1,29 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
+const ICON_CANCEL = '/images/x-icon.svg';
+const ICON_CANCEL_WHITE = '/images/x-icon-white.svg';
+const ICON_CHECK = '/images/check-icon.svg';
+const ICON_CHECK_WHITE = '/images/check-icon-white.svg';
+const ICON_ARROW_DOWN = '/images/chevron-down-black.svg';
+const HOVER_CARD_HIDE_DELAY = 700;
+
path: components/request-card/constant.js
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Unused constant indicates dead code**

`HOVER_CARD_HIDE_DELAY` is declared but never referenced in the newly-added `utils.js`. Please remove it or wire it where intended to avoid misleading future readers.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/constant.js at lines 12 to 13, the constant
HOVER_CARD_HIDE_DELAY is declared but not used anywhere in the new utils.js or
other parts of the code. To fix this, either remove the declaration of
HOVER_CARD_HIDE_DELAY if it is unnecessary, or integrate it properly where it
was intended to be used to avoid confusion and dead code.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-22T05:52:09Z
author_association: NONE
diff_hunk: @@ -0,0 +1,466 @@
+function getTimeInMilliseconds(time, isExtensionRequest) {
+  return isExtensionRequest ? time * 1000 : time;
+}
+
+const getRequestColor = (deadline, createdTime) => {
+  const wasDeadlineBreached = createdTime > deadline;
+  if (wasDeadlineBreached) {
+    return 'red-text';
+  }
+  const days = Math.floor((deadline - createdTime) / (1000 * 60 * 60 * 24));
+  if (days > DEADLINE_WARNING_THRESHOLD_DAYS) {
+    return 'green-text';
+  }
+  return 'orange-text';
+};
+
+const formatToFullDate = (timestamp, locale = 'en-US') => {
+  const options = {
+    weekday: 'long',
+    year: 'numeric',
+    month: 'short',
+    day: 'numeric',
+    hour: 'numeric',
+    minute: 'numeric',
+    timeZoneName: 'short',
+    hour12: true,
+  };
+  return new Intl.DateTimeFormat(locale, options).format(new Date(timestamp));
+};
+
+const getTwoDigitDate = (timestamp, isInSeconds = false) => {
+  const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
+
+  return new Intl.DateTimeFormat('en-US', {
+    day: '2-digit',
+    month: 'long',
+    year: 'numeric',
+  }).format(new Date(normalizedTime));
+};
+
+const formatToDateOnly = (milliseconds) => {
+  const date = new Date(milliseconds);
+  return date.toISOString().split('T')[0];
+};
+
+async function addDelay(milliSeconds) {
+  await new Promise((resolve) => setTimeout(resolve, milliSeconds));
+}
+
+function getFormEntries(formData) {
+  if (!formData) return;
+  return Object.fromEntries(formData.entries());
+}
+
+const addLoadingSpinner = (container) => {
+  const spinner = createElement({
+    type: 'div',
+    attributes: { class: 'loading-spinner' },
+  });
+
+  container.append(spinner);
+
+  function removeSpinner() {
+    spinner.remove();
+  }
+
+  return removeSpinner;
+};
path: components/request-card/utils.js
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Memory-leak risk when spinners outlive their parent**

`addLoadingSpinner` returns a `removeSpinner` closure but does not guard against the container being removed first.  
If the caller forgets to invoke `removeSpinner`, detached DOM nodes accumulate.

Consider using MutationObserver or, at minimum, self-clean when the parent node is gone:

```js
const observer = new MutationObserver(() => {
  if (!container.isConnected) spinner.remove();
});
observer.observe(document.body, { childList: true, subtree: true });
```

or switch to a pattern where the function itself manages the whole loading state (`showLoading(container, fn)`).

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/utils.js around lines 55 to 68, the addLoadingSpinner
function returns a removeSpinner closure but does not handle the case where the
container is removed before removeSpinner is called, causing potential memory
leaks with detached DOM nodes. To fix this, implement a MutationObserver that
watches the document body for changes and removes the spinner if the container
is no longer connected to the DOM. Alternatively, refactor the function to
manage the loading state internally, such as by accepting a callback to run
while showing the spinner and cleaning up afterward.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-22T05:52:09Z
author_association: NONE
diff_hunk: @@ -0,0 +1,466 @@
+function getTimeInMilliseconds(time, isExtensionRequest) {
+  return isExtensionRequest ? time * 1000 : time;
+}
+
+const getRequestColor = (deadline, createdTime) => {
+  const wasDeadlineBreached = createdTime > deadline;
+  if (wasDeadlineBreached) {
+    return 'red-text';
+  }
+  const days = Math.floor((deadline - createdTime) / (1000 * 60 * 60 * 24));
+  if (days > DEADLINE_WARNING_THRESHOLD_DAYS) {
+    return 'green-text';
+  }
+  return 'orange-text';
+};
+
+const formatToFullDate = (timestamp, locale = 'en-US') => {
+  const options = {
+    weekday: 'long',
+    year: 'numeric',
+    month: 'short',
+    day: 'numeric',
+    hour: 'numeric',
+    minute: 'numeric',
+    timeZoneName: 'short',
+    hour12: true,
+  };
+  return new Intl.DateTimeFormat(locale, options).format(new Date(timestamp));
+};
+
+const getTwoDigitDate = (timestamp, isInSeconds = false) => {
+  const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
+
+  return new Intl.DateTimeFormat('en-US', {
+    day: '2-digit',
+    month: 'long',
+    year: 'numeric',
+  }).format(new Date(normalizedTime));
+};
+
+const formatToDateOnly = (milliseconds) => {
+  const date = new Date(milliseconds);
+  return date.toISOString().split('T')[0];
+};
+
+async function addDelay(milliSeconds) {
+  await new Promise((resolve) => setTimeout(resolve, milliSeconds));
+}
+
+function getFormEntries(formData) {
+  if (!formData) return;
+  return Object.fromEntries(formData.entries());
+}
+
+const addLoadingSpinner = (container) => {
+  const spinner = createElement({
+    type: 'div',
+    attributes: { class: 'loading-spinner' },
+  });
+
+  container.append(spinner);
+
+  function removeSpinner() {
+    spinner.remove();
+  }
+
+  return removeSpinner;
+};
+
+const toggleAccordionPanel = (panel) => {
+  const accordion = panel.previousElementSibling;
+  if (!accordion) return;
+
+  const isExpanded = accordion.classList.contains('active');
+
+  if (isExpanded) {
+    accordion.classList.remove('active');
+    panel.style.maxHeight = null;
+  } else {
+    document.querySelectorAll('.accordion.active').forEach((el) => {
+      el.classList.remove('active');
+      el.nextElementSibling?.style &&
+        (el.nextElementSibling.style.maxHeight = null);
+    });
+
+    accordion.classList.add('active');
+    panel.style.maxHeight = `${panel.scrollHeight}px`;
+  }
+};
+
+const expandAccordionPanel = (panel) => {
+  panel.style.maxHeight = `${panel.scrollHeight}px`;
+};
+
+function showSuccessHighlight(element) {
+  element.classList.add('green-card');
+  setTimeout(() => element.classList.remove('green-card'), 1000);
+}
+
+function showErrorHighlight(element) {
+  element.classList.add('red-card');
+  setTimeout(() => element.classList.remove('red-card'), 1000);
+}
+
+async function updateRequestStatus({ id, body, isExtensionRequest }) {
+  let url;
+  let method;
+  if (isExtensionRequest) {
+    url = `${API_BASE_URL}/extension-requests/${id}/status`;
+    method = 'PATCH';
+  } else {
+    url = `${API_BASE_URL}/requests/${id}`;
+    method = 'PUT';
+  }
+
+  try {
+    const res = await fetch(url, {
+      credentials: 'include',
+      method,
+      body: JSON.stringify(body),
+      headers: {
+        'Content-type': 'application/json',
+      },
+    });
+    if (!res.ok) {
+      throw new Error(ErrorMessage.UPDATE_REQUEST);
+    }
+    return await res.json();
+  } catch (error) {
+    console.error('Error updating request status:', error);
+    throw error;
+  }
+}
+
+async function removeCard(element, elementClass, parentContainer) {
+  element.classList.add(elementClass);
+  await addDelay(CARD_REMOVAL_INITIAL_DELAY_MS);
+
+  const height = element.scrollHeight;
+
+  const animation = element.animate(
+    [
+      { height: `${height}px`, opacity: 1 },
+      { height: `${Math.round(height * 0.5)}px`, opacity: 0.2 },
+      {
+        height: `${Math.round(height * 0.2)}px`,
+        opacity: 0,
+        margin: 0,
+        padding: '1rem',
+      },
+      { height: '0', opacity: 0, margin: 0, padding: 0 },
+    ],
+    {
+      duration: CARD_REMOVAL_ANIMATION_DURATION_MS,
+      easing: CARD_REMOVAL_ANIMATION_EASING,
+    },
+  );
+
+  element.style.overflow = 'hidden';
+
+  await animation.finished;
+
+  element.remove();
+
+  if (parentContainer.innerHTML.trim() === '') {
+    addEmptyPageMessage(parentContainer);
+  }
+}
+
+function createSummarySection({
+  isExtensionRequest,
+  isDeadLineCrossed,
+  deadlineDays,
+  data,
+  oldEndsOn,
+  isStatusPending,
+}) {
+  const summaryContainer = createElement({
+    type: 'div',
+    attributes: { class: 'summary-container' },
+  });
+
+  const taskDetailsContainer = createElement({
+    type: 'div',
+    attributes: { class: 'task-details-container' },
+  });
+  summaryContainer.append(taskDetailsContainer);
+
+  const statusSiteLink = createElement({
+    type: 'a',
+    attributes: {
+      class: 'external-link skeleton-link',
+      'data-testid': 'external-link skeleton-link',
+    },
+  });
+  const taskTitle = createElement({
+    type: 'span',
+    attributes: { class: 'task-title' },
+    innerText: 'Task: ',
+  });
+
+  const deadlineContainer = createElement({
+    type: 'div',
+    attributes: { id: 'deadline-container' },
+  });
+  const requestTypeContainer = createElement({
+    type: 'div',
+    attributes: {
+      id: 'requestType-container',
+      'data-testid': 'request-type-container',
+    },
+  });
+  taskTitle.append(statusSiteLink);
+
+  if (isExtensionRequest) {
+    taskDetailsContainer.append(taskTitle, deadlineContainer);
+  } else {
+    taskDetailsContainer.append(requestTypeContainer);
+  }
+
path: components/request-card/utils.js
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Use `aria-*` attributes & `alt` text for better accessibility**

`createSummarySection` creates interactive elements but lacks:

• `aria-label` / `title` on the external link  
• `role="link"` & keyboard handling if the anchor becomes a button  
• No `alt` text for any icons inserted elsewhere

Adding these small attributes greatly improves screen-reader support.

```diff
attributes: {
  class: 'external-link skeleton-link',
  'data-testid': 'external-link skeleton-link',
+  'aria-label': 'Open task in new tab',
},
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
  const statusSiteLink = createElement({
    type: 'a',
    attributes: {
      class: 'external-link skeleton-link',
      'data-testid': 'external-link skeleton-link',
      'aria-label': 'Open task in new tab',
    },
  });
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/utils.js between lines 170 and 220, the
createSummarySection function creates interactive elements like external links
but lacks accessibility attributes. Add an aria-label or title attribute to the
external link element to describe its purpose for screen readers. If any anchor
elements are repurposed as buttons, ensure they have role="link" and appropriate
keyboard event handlers for accessibility. Also, add alt text to any icons used
within this section to provide descriptive text for screen readers.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-22T05:52:09Z
author_association: NONE
diff_hunk: @@ -0,0 +1,466 @@
+function getTimeInMilliseconds(time, isExtensionRequest) {
+  return isExtensionRequest ? time * 1000 : time;
+}
+
+const getRequestColor = (deadline, createdTime) => {
+  const wasDeadlineBreached = createdTime > deadline;
+  if (wasDeadlineBreached) {
+    return 'red-text';
+  }
+  const days = Math.floor((deadline - createdTime) / (1000 * 60 * 60 * 24));
+  if (days > DEADLINE_WARNING_THRESHOLD_DAYS) {
+    return 'green-text';
+  }
+  return 'orange-text';
+};
+
+const formatToFullDate = (timestamp, locale = 'en-US') => {
+  const options = {
+    weekday: 'long',
+    year: 'numeric',
+    month: 'short',
+    day: 'numeric',
+    hour: 'numeric',
+    minute: 'numeric',
+    timeZoneName: 'short',
+    hour12: true,
+  };
+  return new Intl.DateTimeFormat(locale, options).format(new Date(timestamp));
+};
+
+const getTwoDigitDate = (timestamp, isInSeconds = false) => {
+  const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
+
+  return new Intl.DateTimeFormat('en-US', {
+    day: '2-digit',
+    month: 'long',
+    year: 'numeric',
+  }).format(new Date(normalizedTime));
+};
+
+const formatToDateOnly = (milliseconds) => {
+  const date = new Date(milliseconds);
+  return date.toISOString().split('T')[0];
+};
+
+async function addDelay(milliSeconds) {
+  await new Promise((resolve) => setTimeout(resolve, milliSeconds));
+}
+
+function getFormEntries(formData) {
+  if (!formData) return;
+  return Object.fromEntries(formData.entries());
+}
path: components/request-card/utils.js
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Return an empty object instead of `undefined`**

`getFormEntries` currently returns `undefined` when `formData` is falsy.  
Call-sites that perform object operations (`Object.keys`, spread, etc.) will throw.

```diff
-function getFormEntries(formData) {
-  if (!formData) return;
-  return Object.fromEntries(formData.entries());
+function getFormEntries(formData) {
+  if (!formData) return {};
+  return Object.fromEntries(formData.entries());
 }
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
function getFormEntries(formData) {
  if (!formData) return {};
  return Object.fromEntries(formData.entries());
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/utils.js around lines 50 to 53, the function
getFormEntries returns undefined when formData is falsy, which can cause errors
in call-sites expecting an object. Modify the function to return an empty object
{} instead of undefined when formData is falsy to ensure safe object operations
downstream.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-22T05:52:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,466 @@
+function getTimeInMilliseconds(time, isExtensionRequest) {
+  return isExtensionRequest ? time * 1000 : time;
+}
+
+const getRequestColor = (deadline, createdTime) => {
+  const wasDeadlineBreached = createdTime > deadline;
+  if (wasDeadlineBreached) {
+    return 'red-text';
+  }
+  const days = Math.floor((deadline - createdTime) / (1000 * 60 * 60 * 24));
+  if (days > DEADLINE_WARNING_THRESHOLD_DAYS) {
+    return 'green-text';
+  }
+  return 'orange-text';
+};
+
+const formatToFullDate = (timestamp, locale = 'en-US') => {
+  const options = {
+    weekday: 'long',
+    year: 'numeric',
+    month: 'short',
+    day: 'numeric',
+    hour: 'numeric',
+    minute: 'numeric',
+    timeZoneName: 'short',
+    hour12: true,
+  };
+  return new Intl.DateTimeFormat(locale, options).format(new Date(timestamp));
+};
+
+const getTwoDigitDate = (timestamp, isInSeconds = false) => {
+  const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
+
+  return new Intl.DateTimeFormat('en-US', {
+    day: '2-digit',
+    month: 'long',
+    year: 'numeric',
+  }).format(new Date(normalizedTime));
+};
+
+const formatToDateOnly = (milliseconds) => {
+  const date = new Date(milliseconds);
+  return date.toISOString().split('T')[0];
+};
+
+async function addDelay(milliSeconds) {
+  await new Promise((resolve) => setTimeout(resolve, milliSeconds));
+}
+
+function getFormEntries(formData) {
+  if (!formData) return;
+  return Object.fromEntries(formData.entries());
+}
+
+const addLoadingSpinner = (container) => {
+  const spinner = createElement({
+    type: 'div',
+    attributes: { class: 'loading-spinner' },
+  });
+
+  container.append(spinner);
+
+  function removeSpinner() {
+    spinner.remove();
+  }
+
+  return removeSpinner;
+};
+
+const toggleAccordionPanel = (panel) => {
+  const accordion = panel.previousElementSibling;
+  if (!accordion) return;
+
+  const isExpanded = accordion.classList.contains('active');
+
+  if (isExpanded) {
+    accordion.classList.remove('active');
+    panel.style.maxHeight = null;
+  } else {
+    document.querySelectorAll('.accordion.active').forEach((el) => {
+      el.classList.remove('active');
+      el.nextElementSibling?.style &&
+        (el.nextElementSibling.style.maxHeight = null);
+    });
+
+    accordion.classList.add('active');
+    panel.style.maxHeight = `${panel.scrollHeight}px`;
+  }
+};
+
+const expandAccordionPanel = (panel) => {
+  panel.style.maxHeight = `${panel.scrollHeight}px`;
+};
+
+function showSuccessHighlight(element) {
+  element.classList.add('green-card');
+  setTimeout(() => element.classList.remove('green-card'), 1000);
+}
+
+function showErrorHighlight(element) {
+  element.classList.add('red-card');
+  setTimeout(() => element.classList.remove('red-card'), 1000);
+}
+
+async function updateRequestStatus({ id, body, isExtensionRequest }) {
+  let url;
+  let method;
+  if (isExtensionRequest) {
+    url = `${API_BASE_URL}/extension-requests/${id}/status`;
+    method = 'PATCH';
+  } else {
+    url = `${API_BASE_URL}/requests/${id}`;
+    method = 'PUT';
+  }
+
+  try {
+    const res = await fetch(url, {
+      credentials: 'include',
+      method,
+      body: JSON.stringify(body),
+      headers: {
+        'Content-type': 'application/json',
+      },
+    });
+    if (!res.ok) {
+      throw new Error(ErrorMessage.UPDATE_REQUEST);
+    }
+    return await res.json();
+  } catch (error) {
+    console.error('Error updating request status:', error);
+    throw error;
+  }
+}
path: components/request-card/utils.js
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Harden `updateRequestStatus` network layer**

1. `fetch` lacks an `Accept: application/json` header – some back-ends rely on it.  
2. Consider timeouts; a hung request stalls the UI.  
3. Swallowing only non-OK statuses means 4xx/5xx still return control flow via `throw`, but network errors (offline) end up in the same catch with a generic message.  Provide user-friendly feedback.

Example minimal patch:

```diff
   const res = await fetch(url, {
     credentials: 'include',
     method,
     body: JSON.stringify(body),
     headers: {
       'Content-type': 'application/json',
+      Accept: 'application/json',
     },
     signal: AbortSignal.timeout?.(10000), // 10 s timeout in modern browsers
   });
```

Also surface the server-sent error message (if any) to callers before defaulting to `ErrorMessage.UPDATE_REQUEST`.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
async function updateRequestStatus({ id, body, isExtensionRequest }) {
  let url;
  let method;
  if (isExtensionRequest) {
    url = `${API_BASE_URL}/extension-requests/${id}/status`;
    method = 'PATCH';
  } else {
    url = `${API_BASE_URL}/requests/${id}`;
    method = 'PUT';
  }

  try {
    const res = await fetch(url, {
      credentials: 'include',
      method,
      body: JSON.stringify(body),
      headers: {
        'Content-type': 'application/json',
        Accept: 'application/json',
      },
      signal: AbortSignal.timeout?.(10000), // 10 s timeout in modern browsers
    });
    if (!res.ok) {
      throw new Error(ErrorMessage.UPDATE_REQUEST);
    }
    return await res.json();
  } catch (error) {
    console.error('Error updating request status:', error);
    throw error;
  }
}
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/utils.js lines 105 to 133, improve
updateRequestStatus by adding an 'Accept: application/json' header to the fetch
request, implement a timeout mechanism to avoid hanging requests, and enhance
error handling to differentiate between HTTP errors and network errors. Parse
and surface any server-sent error messages before defaulting to the generic
error message, and provide user-friendly feedback for network failures.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-22T05:52:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,466 @@
+function getTimeInMilliseconds(time, isExtensionRequest) {
+  return isExtensionRequest ? time * 1000 : time;
+}
+
+const getRequestColor = (deadline, createdTime) => {
+  const wasDeadlineBreached = createdTime > deadline;
+  if (wasDeadlineBreached) {
+    return 'red-text';
+  }
+  const days = Math.floor((deadline - createdTime) / (1000 * 60 * 60 * 24));
+  if (days > DEADLINE_WARNING_THRESHOLD_DAYS) {
+    return 'green-text';
+  }
+  return 'orange-text';
+};
+
+const formatToFullDate = (timestamp, locale = 'en-US') => {
+  const options = {
+    weekday: 'long',
+    year: 'numeric',
+    month: 'short',
+    day: 'numeric',
+    hour: 'numeric',
+    minute: 'numeric',
+    timeZoneName: 'short',
+    hour12: true,
+  };
+  return new Intl.DateTimeFormat(locale, options).format(new Date(timestamp));
+};
+
+const getTwoDigitDate = (timestamp, isInSeconds = false) => {
+  const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
+
+  return new Intl.DateTimeFormat('en-US', {
+    day: '2-digit',
+    month: 'long',
+    year: 'numeric',
+  }).format(new Date(normalizedTime));
+};
+
+const formatToDateOnly = (milliseconds) => {
+  const date = new Date(milliseconds);
+  return date.toISOString().split('T')[0];
+};
+
+async function addDelay(milliSeconds) {
+  await new Promise((resolve) => setTimeout(resolve, milliSeconds));
+}
+
+function getFormEntries(formData) {
+  if (!formData) return;
+  return Object.fromEntries(formData.entries());
+}
+
+const addLoadingSpinner = (container) => {
+  const spinner = createElement({
+    type: 'div',
+    attributes: { class: 'loading-spinner' },
+  });
+
+  container.append(spinner);
+
+  function removeSpinner() {
+    spinner.remove();
+  }
+
+  return removeSpinner;
+};
+
+const toggleAccordionPanel = (panel) => {
+  const accordion = panel.previousElementSibling;
+  if (!accordion) return;
+
+  const isExpanded = accordion.classList.contains('active');
+
+  if (isExpanded) {
+    accordion.classList.remove('active');
+    panel.style.maxHeight = null;
+  } else {
+    document.querySelectorAll('.accordion.active').forEach((el) => {
+      el.classList.remove('active');
+      el.nextElementSibling?.style &&
+        (el.nextElementSibling.style.maxHeight = null);
+    });
+
+    accordion.classList.add('active');
+    panel.style.maxHeight = `${panel.scrollHeight}px`;
+  }
+};
+
+const expandAccordionPanel = (panel) => {
+  panel.style.maxHeight = `${panel.scrollHeight}px`;
+};
+
+function showSuccessHighlight(element) {
+  element.classList.add('green-card');
+  setTimeout(() => element.classList.remove('green-card'), 1000);
+}
+
+function showErrorHighlight(element) {
+  element.classList.add('red-card');
+  setTimeout(() => element.classList.remove('red-card'), 1000);
+}
+
+async function updateRequestStatus({ id, body, isExtensionRequest }) {
+  let url;
+  let method;
+  if (isExtensionRequest) {
+    url = `${API_BASE_URL}/extension-requests/${id}/status`;
+    method = 'PATCH';
+  } else {
+    url = `${API_BASE_URL}/requests/${id}`;
+    method = 'PUT';
+  }
+
+  try {
+    const res = await fetch(url, {
+      credentials: 'include',
+      method,
+      body: JSON.stringify(body),
+      headers: {
+        'Content-type': 'application/json',
+      },
+    });
+    if (!res.ok) {
+      throw new Error(ErrorMessage.UPDATE_REQUEST);
+    }
+    return await res.json();
+  } catch (error) {
+    console.error('Error updating request status:', error);
+    throw error;
+  }
+}
+
+async function removeCard(element, elementClass, parentContainer) {
+  element.classList.add(elementClass);
+  await addDelay(CARD_REMOVAL_INITIAL_DELAY_MS);
+
+  const height = element.scrollHeight;
+
+  const animation = element.animate(
+    [
+      { height: `${height}px`, opacity: 1 },
+      { height: `${Math.round(height * 0.5)}px`, opacity: 0.2 },
+      {
+        height: `${Math.round(height * 0.2)}px`,
+        opacity: 0,
+        margin: 0,
+        padding: '1rem',
+      },
+      { height: '0', opacity: 0, margin: 0, padding: 0 },
+    ],
+    {
+      duration: CARD_REMOVAL_ANIMATION_DURATION_MS,
+      easing: CARD_REMOVAL_ANIMATION_EASING,
+    },
+  );
+
+  element.style.overflow = 'hidden';
+
+  await animation.finished;
+
+  element.remove();
+
+  if (parentContainer.innerHTML.trim() === '') {
+    addEmptyPageMessage(parentContainer);
+  }
+}
+
+function createSummarySection({
+  isExtensionRequest,
+  isDeadLineCrossed,
+  deadlineDays,
+  data,
+  oldEndsOn,
+  isStatusPending,
+}) {
+  const summaryContainer = createElement({
+    type: 'div',
+    attributes: { class: 'summary-container' },
+  });
+
+  const taskDetailsContainer = createElement({
+    type: 'div',
+    attributes: { class: 'task-details-container' },
+  });
+  summaryContainer.append(taskDetailsContainer);
+
+  const statusSiteLink = createElement({
+    type: 'a',
+    attributes: {
+      class: 'external-link skeleton-link',
+      'data-testid': 'external-link skeleton-link',
+    },
+  });
+  const taskTitle = createElement({
+    type: 'span',
+    attributes: { class: 'task-title' },
+    innerText: 'Task: ',
+  });
+
+  const deadlineContainer = createElement({
+    type: 'div',
+    attributes: { id: 'deadline-container' },
+  });
+  const requestTypeContainer = createElement({
+    type: 'div',
+    attributes: {
+      id: 'requestType-container',
+      'data-testid': 'request-type-container',
+    },
+  });
+  taskTitle.append(statusSiteLink);
+
+  if (isExtensionRequest) {
+    taskDetailsContainer.append(taskTitle, deadlineContainer);
+  } else {
+    taskDetailsContainer.append(requestTypeContainer);
+  }
+
+  const deadlineText = createElement({
+    type: 'span',
+    attributes: { class: 'card-row-text' },
+    innerText: `Deadline${isDeadLineCrossed ? ' ' : ' in '}`,
+  });
+
+  const requestType = createElement({
+    type: 'span',
+    attributes: { class: 'card-row-text' },
+    innerText: 'Request Type ',
+  });
+
+  const deadlineValue = createElement({
+    type: 'span',
+    innerText: `${deadlineDays}`,
+    attributes: {
+      class: `tooltip-container ${
+        isDeadLineCrossed && isStatusPending ? 'red-text' : ''
+      }`,
+    },
+  });
+
+  const requestTypeText = createElement({
+    type: 'span',
+    attributes: {
+      'data-testid': 'request-type',
+    },
+    innerText: data?.type,
+  });
+
+  const deadlineTooltip = createElement({
+    type: 'span',
+    attributes: { class: 'tooltip' },
+    innerText: `${formatToFullDate(oldEndsOn)}`,
+  });
+
+  deadlineValue.append(deadlineTooltip);
+  requestTypeContainer.append(requestType, requestTypeText);
+  deadlineContainer.append(deadlineText, deadlineValue);
+
+  return { summaryContainer, taskDetailsContainer, statusSiteLink };
+}
+
+function createTextBlockContainer(data, isForReasonComponent) {
+  const container = createElement({
+    type: 'div',
+    attributes: {
+      'data-testid': isForReasonComponent
+        ? 'request-reason-container'
+        : 'admin-info-and-status',
+    },
+  });
+
+  const title = createElement({
+    type: 'span',
+    attributes: {
+      class: 'panel-title',
+    },
+    innerText: isForReasonComponent ? 'Reason' : 'Comment',
+  });
+
+  const paragraph = createElement({
+    type: 'p',
+    attributes: {
+      class: 'text-block-content',
+      'data-testid': isForReasonComponent ? 'request-reason' : 'request-remark',
+    },
+    innerText: isForReasonComponent ? data.reason : data.message,
+  });
+
+  const textAreaInput = createElement({
+    type: 'textarea',
+    attributes: {
+      class: 'input-text-area hidden',
+      id: 'reason',
+      name: 'reason',
+      'data-testid': 'reason-input-text-area',
+    },
+    value: data.reason,
+  });
+
+  const inputError = createElement({
+    type: 'span',
+    attributes: {
+      class: 'input-error red-text hidden',
+      'data-testid': 'reason-input-error',
+    },
+    innerText: 'Reason is required',
+  });
+
+  const detailsLine = createElement({
+    type: 'span',
+    attributes: { class: 'details-line' },
+  });
+
+  if (isForReasonComponent) {
+    container.append(title, detailsLine, textAreaInput, inputError, paragraph);
+  } else {
+    container.append(title, detailsLine, paragraph);
+  }
+
+  return {
+    container,
+    textAreaInput,
+    inputError,
+    paragraph,
+  };
+}
+
+function createDateContainer(
+  isExtensionRequest,
+  newDeadlineDays,
+  isNewDeadLineCrossed,
+  newEndsOnValue,
+  requestDays,
+  oldEndsOn,
+) {
+  const datesContainer = createElement({
+    type: 'div',
+    attributes: { class: 'dates-container' },
+  });
+  const datesDetailsContainer = createElement({
+    type: 'div',
+    attributes: { class: 'details-container' },
+  });
+
+  const requestDetailsHeading = createElement({
+    type: 'span',
+    attributes: { class: 'details-heading' },
+    innerText: isExtensionRequest ? 'Extension Details' : 'Request Details',
+  });
+
+  const requestDetailsLine = createElement({
+    type: 'span',
+    attributes: { class: 'details-line' },
+  });
+
+  const newDeadlineContainer = createElement({
+    type: 'div',
+    attributes: { id: 'new-deadline-container' },
+  });
+
+  const newDeadlineText = createElement({
+    type: 'span',
+    attributes: { class: 'card-row-text' },
+    innerText: `${
+      isExtensionRequest
+        ? `New deadline${isNewDeadLineCrossed ? ' ' : ' in '}`
+        : 'Until'
+    }`,
+  });
+
+  const newDeadlineValue = createElement({
+    type: 'span',
+    attributes: { class: 'requested-day tooltip-container' },
+    innerText: ` ${newDeadlineDays}`,
+  });
+
+  const requestInput = createElement({
+    type: 'input',
+    attributes: {
+      class: 'date-input hidden',
+      type: 'date',
+      name: 'newEndsOn',
+      id: 'newEndsOn',
+      oninput: 'this.blur()',
+      value: formatToDateOnly(
+        getTimeInMilliseconds(newEndsOnValue, isExtensionRequest),
+      ),
+      'data-testid': 'request-input',
+    },
+  });
path: components/request-card/utils.js
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Validate date input min/max to prevent past-date errors in the first place**

You already show `"Past date can't be the new deadline"` after submission, but HTML can enforce it proactively:

```diff
attributes: {
  class: 'date-input hidden',
  type: 'date',
+ min: formatToDateOnly(Date.now()),
  name: 'newEndsOn',
  id: `newEndsOn-${crypto.randomUUID()}`, // also fixes duplicate id issue
```

This prevents invalid selections and removes a round-trip of error handling.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
  const newDeadlineValue = createElement({
    type: 'span',
    attributes: { class: 'requested-day tooltip-container' },
    innerText: ` ${newDeadlineDays}`,
  });

  const requestInput = createElement({
    type: 'input',
    attributes: {
      class: 'date-input hidden',
      type: 'date',
      min: formatToDateOnly(Date.now()),
      name: 'newEndsOn',
      id: `newEndsOn-${crypto.randomUUID()}`, // also fixes duplicate id issue
      oninput: 'this.blur()',
      value: formatToDateOnly(
        getTimeInMilliseconds(newEndsOnValue, isExtensionRequest),
      ),
      'data-testid': 'request-input',
    },
  });
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/utils.js around lines 373 to 392, the date input
element lacks min and max attributes to restrict selectable dates. Add
appropriate min and max attributes to the input element to prevent users from
selecting past dates or invalid future dates, enforcing valid date ranges at the
HTML input level and avoiding unnecessary error handling after submission.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-22T05:52:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,466 @@
+function getTimeInMilliseconds(time, isExtensionRequest) {
+  return isExtensionRequest ? time * 1000 : time;
+}
path: components/request-card/utils.js
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Confusing parameter naming hides a potential milliseconds/seconds bug**

`getTimeInMilliseconds` assumes *“extension requests are in seconds”*, yet its second argument is named `isExtensionRequest`.  
`getTwoDigitDate` passes an `isInSeconds` flag instead.  The semantic drift makes it hard to reason about – and if the caller already holds milliseconds (e.g. `newEndsOnInMillisecond`) this function will erroneously multiply by 1 000.

```diff
-function getTimeInMilliseconds(time, isExtensionRequest) {
-  return isExtensionRequest ? time * 1000 : time;
+/**
+ * Normalises a Unix time value to **milliseconds**.
+ * @param {number} time   - Timestamp in seconds or milliseconds.
+ * @param {boolean} isInSeconds - true → multiply by 1 000.
+ */
+function getTimeInMilliseconds(time, isInSeconds = false) {
+  return isInSeconds ? time * 1000 : time;
}
```

Then call with a clearly-named flag:

```diff
-const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
+const normalizedTime = getTimeInMilliseconds(timestamp, isInSeconds);
```

Please audit every caller (especially `newEndsOnValue`) to ensure the correct unit is supplied.  
 


Also applies to: 31-33

---

🏁 Script executed:

```shell
#!/bin/bash
# Locate all usages of getTimeInMilliseconds to verify parameter semantics
rg --color=never -n "getTimeInMilliseconds\(" .
```

Length of output: 736

---

🏁 Script executed:

```shell
#!/bin/bash
# Show usage context for getTimeInMilliseconds in utils.js and script.js
rg -n -C 3 "getTimeInMilliseconds" components/request-card/utils.js components/request-card/script.js
```

Length of output: 2734

---



</details>

**Rename `getTimeInMilliseconds`’s flag to `isInSeconds` and audit all callers for correct units**

The boolean parameter currently named `isExtensionRequest` actually controls whether to multiply by 1 000 (i.e. whether the input is in seconds), which is confusing—especially since some callers pass an `isInSeconds` flag, others pass `isExtensionRequest`.  

Please:

• In `components/request-card/utils.js` (lines 1–3), update the signature and JSDoc:  
```diff
- function getTimeInMilliseconds(time, isExtensionRequest) {
-   return isExtensionRequest ? time * 1000 : time;
- }
+ /**
+  * Normalize a timestamp to milliseconds.
+  * @param {number} time           - Timestamp in seconds or milliseconds.
+  * @param {boolean} isInSeconds   - If true, treat `time` as seconds and multiply by 1000.
+  */
+ function getTimeInMilliseconds(time, isInSeconds = false) {
+   return isInSeconds ? time * 1000 : time;
+ }
```

• Audit every call site to confirm the boolean you’re passing accurately reflects the unit of `time`. Key locations:  
  – `utils.js:32` (`getTimeInMilliseconds(timestamp, isInSeconds)`)  
  – `utils.js:388` (`getTimeInMilliseconds(newEndsOnValue, isExtensionRequest)`)  
  – `script.js:273`  
  – `script.js:387–395`  

Ensure that wherever you pass `true`, the `time` value is in **seconds**, and wherever you pass `false`, it’s already in **milliseconds**.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In components/request-card/utils.js lines 1 to 3, rename the boolean parameter
from isExtensionRequest to isInSeconds in the getTimeInMilliseconds function
signature and update its JSDoc accordingly to clarify that it indicates whether
the input time is in seconds. Then audit all call sites of
getTimeInMilliseconds, especially at lines 32 and 388 in utils.js and lines 273
and 387-395 in script.js, to ensure the boolean argument correctly reflects
whether the time value is in seconds (true) or milliseconds (false), adjusting
calls as needed to prevent incorrect multiplication by 1000.
```

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-22T05:52:10Z
author_association: NONE
diff_hunk: @@ -0,0 +1,29 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
+const ICON_CANCEL = '/images/x-icon.svg';
+const ICON_CANCEL_WHITE = '/images/x-icon-white.svg';
+const ICON_CHECK = '/images/check-icon.svg';
+const ICON_CHECK_WHITE = '/images/check-icon-white.svg';
+const ICON_ARROW_DOWN = '/images/chevron-down-black.svg';
+const HOVER_CARD_HIDE_DELAY = 700;
path: components/request-card/constant.js
user: login: AnujChhikara
body:  We're planning to include the constants.js file directly in the HTML using a <script> tag before other modules.
created_at: 2025-05-22T05:56:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
+const ICON_CANCEL = '/images/x-icon.svg';
+const ICON_CANCEL_WHITE = '/images/x-icon-white.svg';
+const ICON_CHECK = '/images/check-icon.svg';
+const ICON_CHECK_WHITE = '/images/check-icon-white.svg';
+const ICON_ARROW_DOWN = '/images/chevron-down-black.svg';
+const HOVER_CARD_HIDE_DELAY = 700;
path: components/request-card/constant.js
user: login: coderabbitai[bot]
body: @AnujChhikara Including the constants via a `<script>` tag before other modules is a valid approach - the constants will be available in the global scope without needing exports.

I'd still recommend considering `Object.freeze()` for your enum objects though:

```js
const RequestStatus = Object.freeze({
  APPROVED: 'APPROVED',
  PENDING: 'PENDING',
  DENIED: 'DENIED',
  REJECTED: 'REJECTED',
});
```

This prevents accidental mutations at runtime (like `RequestStatus.APPROVED = 'SOMETHING_ELSE'`) that could cause subtle bugs. The freezing has no impact on your loading strategy, but adds an extra layer of safety.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: AnujChhikara
PR: Real-Dev-Squad/website-dashboard#1002
File: components/request-card/constant.js:1-12
Timestamp: 2025-05-22T05:56:32.118Z
Learning: The project loads constants.js directly in the HTML using a <script> tag before other modules, making constants available in the global scope without requiring exports.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>


<!-- <agentComponentType>chat-answer</agentComponentType> -->

<!-- <rawResChunk><answer>@AnujChhikara Including the constants via a `<script>` tag before other modules is a valid approach - the constants will be available in the global scope without needing exports.

I'd still recommend considering `Object.freeze()` for your enum objects though:

```js
const RequestStatus = Object.freeze({
  APPROVED: 'APPROVED',
  PENDING: 'PENDING',
  DENIED: 'DENIED',
  REJECTED: 'REJECTED',
});
```

This prevents accidental mutations at runtime (like `RequestStatus.APPROVED = 'SOMETHING_ELSE'`) that could cause subtle bugs. The freezing has no impact on your loading strategy, but adds an extra layer of safety.

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: AnujChhikara
PR: Real-Dev-Squad/website-dashboard#1002
File: components/request-card/constant.js:1-12
Timestamp: 2025-05-22T05:56:32.118Z
Learning: The project loads constants.js directly in the HTML using a <script> tag before other modules, making constants available in the global scope without requiring exports.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

</answer></rawResChunk> -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-22T05:56:33Z
author_association: NONE
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: RequestStatus.REJECTED,
path: components/request-card/utils.js
user: login: MayankBansal12
body: should it be `DENIED` for `isExtensionRequest` or same for all?
created_at: 2025-05-23T06:11:48Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      toggleActionButtonVisibility();
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText =
+          'Invalid date format. Please provide a valid date.';
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = "Past date can't be the new deadline.";
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        toggleActionButtonVisibility();
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      toggleActionButtonVisibility();
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      let reqBody;
+      const remarkMessage = remarkInputField.value;
+
+      if (isExtensionRequest)
+        reqBody = {
+          status: RequestStatus.APPROVED,
+        };
+      else if (
+        remarkMessage === '' ||
+        remarkMessage === undefined ||
+        remarkMessage === null
+      ) {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.APPROVED,
+        };
+      } else {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.APPROVED,
+          message: remarkMessage,
+        };
+      }
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      let reqBody;
+      const remarkMessage = remarkInputField.value;
+
+      if (isExtensionRequest)
+        reqBody = {
+          status: RequestStatus.DENIED,
+        };
+      else if (
+        remarkMessage === '' ||
+        remarkMessage === undefined ||
+        remarkMessage === null
+      ) {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.REJECTED,
+        };
+      } else {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.REJECTED,
+          message: remarkMessage,
+        };
+      }
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
+    function toggleActionButtonVisibility() {
+      if (approveButton.style.display === 'none') {
+        approveButton.style.display = 'block';
+      } else {
+        approveButton.style.display = 'none';
+      }
+
+      if (rejectButton.style.display === 'none') {
+        rejectButton.style.display = 'block';
+      } else {
+        rejectButton.style.display = 'none';
+      }
path: components/request-card/utils.js
user: login: MayankBansal12
body: will the approve and reject buttons be visible and hidden at same time or diff behaviour? 
i feel this logic can be improved if there's a clear case for when both should be hidden/visible instead of just toggling based on class
created_at: 2025-05-23T06:19:12Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      toggleActionButtonVisibility();
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText =
+          'Invalid date format. Please provide a valid date.';
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = "Past date can't be the new deadline.";
path: components/request-card/utils.js
user: login: MayankBansal12
body: can we put these innerText in constants?
created_at: 2025-05-23T06:19:43Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      toggleActionButtonVisibility();
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText =
+          'Invalid date format. Please provide a valid date.';
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = "Past date can't be the new deadline.";
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        toggleActionButtonVisibility();
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      toggleActionButtonVisibility();
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      let reqBody;
+      const remarkMessage = remarkInputField.value;
+
+      if (isExtensionRequest)
+        reqBody = {
+          status: RequestStatus.APPROVED,
+        };
+      else if (
+        remarkMessage === '' ||
+        remarkMessage === undefined ||
+        remarkMessage === null
+      ) {
path: components/request-card/utils.js
user: login: MayankBansal12
body: ```js
 else if (!remarkMessage) 
```

i believe this does the same thing checking for any falsy or null values and it's more readable

created_at: 2025-05-23T06:24:43Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      toggleActionButtonVisibility();
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText =
+          'Invalid date format. Please provide a valid date.';
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = "Past date can't be the new deadline.";
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        toggleActionButtonVisibility();
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      toggleActionButtonVisibility();
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      let reqBody;
+      const remarkMessage = remarkInputField.value;
+
+      if (isExtensionRequest)
+        reqBody = {
+          status: RequestStatus.APPROVED,
+        };
+      else if (
+        remarkMessage === '' ||
+        remarkMessage === undefined ||
+        remarkMessage === null
+      ) {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.APPROVED,
+        };
+      } else {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.APPROVED,
+          message: remarkMessage,
+        };
+      }
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      let reqBody;
+      const remarkMessage = remarkInputField.value;
+
+      if (isExtensionRequest)
+        reqBody = {
+          status: RequestStatus.DENIED,
+        };
+      else if (
+        remarkMessage === '' ||
+        remarkMessage === undefined ||
+        remarkMessage === null
+      ) {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.REJECTED,
+        };
+      } else {
+        reqBody = {
+          type: data?.type,
+          state: RequestStatus.REJECTED,
+          message: remarkMessage,
+        };
+      }
path: components/request-card/utils.js
user: login: MayankBansal12
body: we are doing the same thing for APPROVED status above, can we refactor this if only state is changing i.e, for APPROVED and REJECTED?
created_at: 2025-05-23T06:26:49Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,30 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
+const ICON_CANCEL = '/images/x-icon.svg';
+const ICON_CANCEL_WHITE = '/images/x-icon-white.svg';
+const ICON_CHECK = '/images/check-icon.svg';
+const ICON_CHECK_WHITE = '/images/check-icon-white.svg';
+const ICON_ARROW_DOWN = '/images/chevron-down-black.svg';
+
+const RequestStatus = Object.freeze({
path: components/request-card/constant.js
user: login: pankajjs
body: ```suggestion
const REQUEST_STATUS = Object.freeze({
```
created_at: 2025-05-23T17:07:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
+const ICON_CANCEL = '/images/x-icon.svg';
+const ICON_CANCEL_WHITE = '/images/x-icon-white.svg';
+const ICON_CHECK = '/images/check-icon.svg';
+const ICON_CHECK_WHITE = '/images/check-icon-white.svg';
+const ICON_ARROW_DOWN = '/images/chevron-down-black.svg';
+
+const RequestStatus = Object.freeze({
+  APPROVED: 'APPROVED',
+  PENDING: 'PENDING',
+  DENIED: 'DENIED',
+  REJECTED: 'REJECTED',
+});
+
+const RequestType = Object.freeze({
path: components/request-card/constant.js
user: login: pankajjs
body: ```suggestion
const REQUEST_TYPE = Object.freeze({
```
created_at: 2025-05-23T17:08:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
+const ICON_CANCEL = '/images/x-icon.svg';
+const ICON_CANCEL_WHITE = '/images/x-icon-white.svg';
+const ICON_CHECK = '/images/check-icon.svg';
+const ICON_CHECK_WHITE = '/images/check-icon-white.svg';
+const ICON_ARROW_DOWN = '/images/chevron-down-black.svg';
+
+const RequestStatus = Object.freeze({
+  APPROVED: 'APPROVED',
+  PENDING: 'PENDING',
+  DENIED: 'DENIED',
+  REJECTED: 'REJECTED',
+});
+
+const RequestType = Object.freeze({
+  EXTENSION: 'EXTENSION',
+  OOO: 'OOO',
+  ONBOARDING: 'ONBOARDING',
+});
+
+const ErrorMessage = Object.freeze({
path: components/request-card/constant.js
user: login: pankajjs
body: ```suggestion
const ERROR_MESSAGE = Object.freeze({
```
created_at: 2025-05-23T17:09:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
path: components/request-card/constant.js
user: login: pankajjs
body: Can we put into a object
created_at: 2025-05-23T17:09:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
+    function setActionButtonsVisibility(shouldShow) {
+      const displayValue = shouldShow ? 'block' : 'none';
+      approveButton.style.display = displayValue;
+      rejectButton.style.display = displayValue;
+    }
+  }
+  return requestActionContainer;
+}
+
+function buildRequestBody({ isExtensionRequest, data, remarkMessage, status }) {
+  let reqBody;
path: components/request-card/utils.js
user: login: pankajjs
body: ```suggestion
  let requestBody;
```
created_at: 2025-05-23T17:15:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
+    function setActionButtonsVisibility(shouldShow) {
+      const displayValue = shouldShow ? 'block' : 'none';
+      approveButton.style.display = displayValue;
+      rejectButton.style.display = displayValue;
+    }
+  }
+  return requestActionContainer;
+}
+
+function buildRequestBody({ isExtensionRequest, data, remarkMessage, status }) {
+  let reqBody;
+
+  if (isExtensionRequest) {
+    reqBody = {
+      status: status,
+    };
path: components/request-card/utils.js
user: login: pankajjs
body: don't we need type here?
created_at: 2025-05-23T17:16:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
+    function setActionButtonsVisibility(shouldShow) {
+      const displayValue = shouldShow ? 'block' : 'none';
+      approveButton.style.display = displayValue;
+      rejectButton.style.display = displayValue;
path: components/request-card/utils.js
user: login: pankajjs
body: ```suggestion
      approveButton.style.display = shouldShow ? 'block' : 'none';
      rejectButton.style.display = shouldShow ? 'block' : 'none';
```
created_at: 2025-05-23T17:17:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
path: components/request-card/utils.js
user: login: pankajjs
body: I think we should remove event listener in cleanup.
created_at: 2025-05-23T17:19:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
path: components/request-card/utils.js
user: login: pankajjs
body: Can we create this into a function and use async await syntax?
created_at: 2025-05-23T17:20:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
path: components/request-card/utils.js
user: login: pankajjs
body: ```suggestion
      const reqBody = buildRequestBody({
        isExtensionRequest,
        data,
        remarkInputField.value,
        status: RequestStatus.APPROVED,
      });

```
created_at: 2025-05-23T17:22:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
path: components/request-card/utils.js
user: login: pankajjs
body: Can we use some better name for this field.
created_at: 2025-05-23T17:23:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
path: components/request-card/utils.js
user: login: pankajjs
body: i think this should be just below the function.
created_at: 2025-05-23T17:24:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
path: components/request-card/utils.js
user: login: pankajjs
body: Can we refactor this into a single line?
created_at: 2025-05-23T17:25:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
path: components/request-card/constant.js
user: login: AnujChhikara
body: don't think so like we can put the images file path into a single object
created_at: 2025-05-23T17:48:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,30 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+const DEFAULT_USER_AVATAR = '/images/avatar.png';
+const ICON_EDIT = '/images/edit-icon.svg';
path: components/request-card/constant.js
user: login: pankajjs
body: const ICONS = {
  EDIT: ""
  }
  
  like that
created_at: 2025-05-23T17:52:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
+    function setActionButtonsVisibility(shouldShow) {
+      const displayValue = shouldShow ? 'block' : 'none';
+      approveButton.style.display = displayValue;
+      rejectButton.style.display = displayValue;
+    }
+  }
+  return requestActionContainer;
+}
+
+function buildRequestBody({ isExtensionRequest, data, remarkMessage, status }) {
+  let reqBody;
+
+  if (isExtensionRequest) {
+    reqBody = {
+      status: status,
+    };
path: components/request-card/utils.js
user: login: AnujChhikara
body: We're passing it as a parameter, and we're specifying its type when doing so.
created_at: 2025-05-23T17:58:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
+    function setActionButtonsVisibility(shouldShow) {
+      const displayValue = shouldShow ? 'block' : 'none';
+      approveButton.style.display = displayValue;
+      rejectButton.style.display = displayValue;
path: components/request-card/utils.js
user: login: AnujChhikara
body: Used a variable to avoid repeating the ternary, but happy to switch to inline if that’s preferred.
created_at: 2025-05-23T17:59:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
path: components/request-card/utils.js
user: login: AnujChhikara
body: We could use nested ternary operators, but I don’t think that’s a good idea because it reduces code readability
created_at: 2025-05-23T18:34:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === REQUEST_STATUS.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: REQUEST_STATUS.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? REQUEST_STATUS.DENIED : REQUEST_STATUS.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? REQUEST_STATUS.DENIED
+        : REQUEST_STATUS.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICONS.CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ERROR_MESSAGE.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ERROR_MESSAGE.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', async (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: RequestStatus.APPROVED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: true,
+      });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICONS.CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICONS.CHECK;
+    });
+    rejectButton.addEventListener('click', async (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: false,
+      });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICONS.CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICONS.CANCEL;
+    });
path: components/request-card/utils.js
user: login: pankajjs
body: Please remove event listener when cleanup
created_at: 2025-05-24T15:52:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,346 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === Status.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: Status.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? RequestStatus.DENIED : RequestStatus.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? RequestStatus.DENIED
+        : RequestStatus.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICON_CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICON_CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ErrorMessage.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ErrorMessage.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: RequestStatus.APPROVED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: APPROVED_MESSAGE,
+          });
+          await removeCard(rootElement, 'green-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICON_CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICON_CHECK;
+    });
+    rejectButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestRequestId: data.id,
+        name: `${currentUserDetails?.first_name} ${currentUserDetails?.last_name}`,
+        userId: currentUserDetails?.id,
+      };
+
+      const remarkMessage = remarkInputField.value;
+      const reqBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      updateRequestStatus({
+        id: data.id,
+        body: reqBody,
+        isExtensionRequest,
+      })
+        .then(async () => {
+          removeSpinner();
+          isExtensionRequest && appendLogs(payloadForLog, data.id);
+          showToastMessage({
+            isDev: true,
+            oldToastFunction: showToast,
+            type: 'success',
+            message: REJECTED_MESSAGE,
+          });
+          await removeCard(rootElement, 'red-card', parentContainer);
+        })
+        .catch(() => {
+          removeSpinner();
+          showErrorHighlight(rootElement);
+        })
+        .finally(() => {
+          rootElement.classList.remove('disabled');
+        });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICON_CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICON_CANCEL;
+    });
+
path: components/request-card/utils.js
user: login: AnujChhikara
body: we will add the clean up function in the remove card in the final pr 
created_at: 2025-05-24T15:52:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === REQUEST_STATUS.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: REQUEST_STATUS.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? REQUEST_STATUS.DENIED : REQUEST_STATUS.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? REQUEST_STATUS.DENIED
+        : REQUEST_STATUS.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICONS.CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ERROR_MESSAGE.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ERROR_MESSAGE.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', async (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
path: components/request-card/utils.js
user: login: pankajjs
body: Is this correct variable name?
created_at: 2025-05-24T15:55:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,38 @@
+const CARD_REMOVAL_INITIAL_DELAY_MS = 800;
+const CARD_REMOVAL_ANIMATION_DURATION_MS = 800;
+const CARD_REMOVAL_ANIMATION_EASING = 'ease-out';
+const DEADLINE_WARNING_THRESHOLD_DAYS = 3;
+
+const ICONS = Object.freeze({
+  DEFAULT_USER_AVATAR: '/images/avatar.png',
+  EDIT: '/images/edit-icon.svg',
+  CANCEL: '/images/x-icon.svg',
+  CANCEL_WHITE: '/images/x-icon-white.svg',
+  CHECK: '/images/check-icon.svg',
+  CHECK_WHITE: '/images/check-icon-white.svg',
+  ARROW_DOWN: '/images/chevron-down-black.svg',
+});
+
+const REQUEST_STATUS = Object.freeze({
+  APPROVED: 'APPROVED',
+  PENDING: 'PENDING',
+  DENIED: 'DENIED',
+  REJECTED: 'REJECTED',
+});
+
+const REQUEST_TYPE = Object.freeze({
+  EXTENSION: 'EXTENSION',
+  OOO: 'OOO',
+  ONBOARDING: 'ONBOARDING',
+});
+
+const ERROR_MESSAGE = Object.freeze({
+  UPDATE_REQUEST: 'Error updating request',
+  DATE_INPUT_ERROR: 'Invalid date format. Please provide a valid date.',
+  DEADLINE_PASSED: "Past date can't be the new deadline.",
+});
+
+const SUCCESS_MESSAGE = Object.freeze({
+  APPROVED_MESSAGE: 'Request approved successfully',
+  REJECTED_MESSAGE: 'Request rejected successfully',
path: components/request-card/constant.js
user: login: pankajjs
body: ```suggestion
  APPROVED: 'Request approved successfully',
  REJECTED: 'Request rejected successfully',
```

I think Message is unnecessary here
created_at: 2025-05-24T15:59:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === REQUEST_STATUS.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: REQUEST_STATUS.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? REQUEST_STATUS.DENIED : REQUEST_STATUS.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? REQUEST_STATUS.DENIED
+        : REQUEST_STATUS.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICONS.CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ERROR_MESSAGE.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ERROR_MESSAGE.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', async (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: RequestStatus.APPROVED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: true,
+      });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICONS.CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICONS.CHECK;
+    });
+    rejectButton.addEventListener('click', async (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: false,
+      });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICONS.CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICONS.CANCEL;
+    });
path: components/request-card/utils.js
user: login: AnujChhikara
body: we will add the clean up function in the remove card function in the final pr #1003
created_at: 2025-05-24T16:05:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,364 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === REQUEST_STATUS.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: REQUEST_STATUS.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? REQUEST_STATUS.DENIED : REQUEST_STATUS.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? REQUEST_STATUS.DENIED
+        : REQUEST_STATUS.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
path: components/request-card/utils.js
user: login: pankajjs
body: ```suggestion
    const saveButton = createElement({
```
created_at: 2025-05-24T17:12:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,364 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === REQUEST_STATUS.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: REQUEST_STATUS.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? REQUEST_STATUS.DENIED : REQUEST_STATUS.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? REQUEST_STATUS.DENIED
+        : REQUEST_STATUS.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
path: components/request-card/utils.js
user: login: AnujChhikara
body: changes 
created_at: 2025-05-24T19:22:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,362 @@
+function createActionContainer({ context, elements, uiHandlers, domRefs }) {
+  const { isExtensionRequest, data, currentUser, isStatusPending } = context;
+  const {
+    titleInput,
+    titleInputError,
+    reasonInput,
+    reasonInputError,
+    requestInput,
+    requestInputError,
+    titleInputWrapper,
+  } = elements;
+  const { toggleInputs, appendLogs } = uiHandlers;
+  const {
+    panel,
+    accordionButton,
+    rootElement,
+    parentContainer,
+    requestDetails,
+  } = domRefs;
+  const requestStatus = isExtensionRequest ? data.status : data.state;
+  const requestActionContainer = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-action-container`,
+      'data-testid': 'request-action-container',
+    },
+  });
+
+  const requestCardButtons = createElement({
+    type: 'div',
+    attributes: {
+      class: `request-card-buttons ${
+        isStatusPending ? '' : 'request-card-status'
+      }`,
+      'data-testid': 'request-card-status',
+    },
+  });
+
+  const remarkInputField = createElement({
+    type: 'input',
+    attributes: {
+      class: 'remark-input-field',
+      placeholder: 'add comment ...',
+      'data-testid': 'request-remark-input',
+    },
+  });
+
+  if (!isExtensionRequest && isStatusPending) {
+    requestActionContainer.append(remarkInputField);
+  }
+  requestActionContainer.append(requestCardButtons);
+
+  if (requestStatus === REQUEST_STATUS.APPROVED) {
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button approved ',
+      },
+
+      innerText: REQUEST_STATUS.APPROVED,
+    });
+    requestCardButtons.append(approveButton);
+  } else if (
+    requestStatus ===
+    (isExtensionRequest ? REQUEST_STATUS.DENIED : REQUEST_STATUS.REJECTED)
+  ) {
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button denied',
+      },
+
+      innerText: isExtensionRequest
+        ? REQUEST_STATUS.DENIED
+        : REQUEST_STATUS.REJECTED,
+    });
+    requestCardButtons.append(rejectButton);
+  } else {
+    const editButton = createElement({
+      type: 'button',
+      attributes: { class: 'edit-button', 'data-testid': 'edit-button' },
+    });
+
+    if (
+      isExtensionRequest &&
+      shouldDisplayEditButton(data.assigneeId, currentUser)
+    ) {
+      requestCardButtons.append(editButton);
+    }
+
+    const editIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.EDIT, alt: 'edit-icon' },
+    });
+    editButton.append(editIcon);
+    const updateWrapper = createElement({
+      type: 'div',
+      attributes: {
+        class: 'update-wrapper hidden',
+        'data-testid': 'update-wrapper',
+      },
+    });
+    requestCardButtons.append(updateWrapper);
+    const updateButton = createElement({
+      type: 'button',
+      attributes: { class: 'update-button', 'data-testid': 'update-button' },
+      innerText: 'SAVE',
+    });
+
+    const cancelButton = createElement({
+      type: 'button',
+      attributes: { class: 'cancel-button' },
+      innerText: 'CANCEL',
+    });
+    updateWrapper.append(cancelButton, updateButton);
+    const rejectButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'reject-button',
+        'data-testid': 'request-reject-button',
+      },
+    });
+
+    const rejectIcon = createElement({
+      type: 'img',
+      attributes: { src: ICONS.CANCEL, alt: 'edit-icon' },
+    });
+
+    rejectButton.append(rejectIcon);
+
+    const approveButton = createElement({
+      type: 'button',
+      attributes: {
+        class: 'approve-button',
+        'data-testid': 'request-approve-button',
+      },
+    });
+    const approveIcon = createElement({
+      type: 'img',
+      attributes: { class: 'check-icon', src: ICONS.CHECK, alt: 'check-icon' },
+    });
+    approveButton.append(approveIcon);
+    requestCardButtons.append(rejectButton, approveButton);
+
+    editButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      toggleInputs();
+      setActionButtonsVisibility(false);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+      if (!panel.style.maxHeight) {
+        accordionButton.click();
+      }
+      expandAccordionPanel(panel);
+    });
+    updateButton.addEventListener('click', (event) => {
+      const isTitleMissing = !titleInput.value;
+      const isReasonMissing = !reasonInput.value;
+      const todayDate = Math.floor(new Date().getTime() / 1000);
+      const newDeadline = new Date(requestInput.value).getTime() / 1000;
+      const isDeadlineInPast = newDeadline < todayDate;
+      const isInvalidDateFormat = isNaN(newDeadline);
+
+      if (isInvalidDateFormat) {
+        requestInputError.innerText = ERROR_MESSAGE.DATE_INPUT_ERROR;
+      } else if (isDeadlineInPast) {
+        requestInputError.innerText = ERROR_MESSAGE.DEADLINE_PASSED;
+      }
+
+      titleInputError.classList.toggle('hidden', !isTitleMissing);
+      reasonInputError.classList.toggle('hidden', !isReasonMissing);
+      requestInputError.classList.toggle(
+        'hidden',
+        !(isDeadlineInPast || isInvalidDateFormat),
+      );
+
+      if (
+        !isTitleMissing &&
+        !isReasonMissing &&
+        !(isDeadlineInPast || isInvalidDateFormat)
+      ) {
+        toggleInputs();
+        setActionButtonsVisibility(false);
+        editButton.classList.toggle('hidden');
+        updateWrapper.classList.toggle('hidden');
+        titleInputWrapper.classList.add('hidden');
+      }
+    });
+    cancelButton.addEventListener('click', (event) => {
+      event.preventDefault();
+      titleInput.value = data.title;
+      reasonInput.value = data.reason;
+      requestInput.value = formatToDateOnly(
+        getTimeInMilliseconds(
+          requestDetails.newEndsOnInMillisecond,
+          isExtensionRequest,
+        ),
+      );
+      toggleInputs();
+      setActionButtonsVisibility(true);
+      editButton.classList.toggle('hidden');
+      updateWrapper.classList.toggle('hidden');
+
+      titleInputError.classList.add('hidden');
+      reasonInputError.classList.add('hidden');
+      requestInputError.classList.add('hidden');
+    });
+    const payloadForLog = {
+      body: {},
+      meta: {},
+      timestamp: {
+        _seconds: Date.now() / 1000,
+      },
+    };
+
+    approveButton.addEventListener('click', async (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.APPROVED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: RequestStatus.APPROVED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: true,
+      });
+    });
+    approveButton.addEventListener('mouseenter', (event) => {
+      approveIcon.src = ICONS.CHECK_WHITE;
+    });
+    approveButton.addEventListener('mouseleave', (event) => {
+      approveIcon.src = ICONS.CHECK;
+    });
+    rejectButton.addEventListener('click', async (event) => {
+      event.preventDefault();
+      const removeSpinner = addLoadingSpinner(rootElement);
+      rootElement.classList.add('disabled');
+      payloadForLog.body.status = RequestStatus.DENIED;
+      payloadForLog.meta = {
+        requestId: data.id,
+        name: `${currentUser?.first_name} ${currentUser?.last_name}`,
+        userId: currentUser?.id,
+      };
+
+      const requestBody = buildRequestBody({
+        isExtensionRequest,
+        data,
+        remarkMessage: remarkInputField.value,
+        status: isExtensionRequest
+          ? RequestStatus.DENIED
+          : RequestStatus.REJECTED,
+      });
+
+      await handleRequestStatusUpdate({
+        id: data.id,
+        reqBody: requestBody,
+        isExtensionRequest,
+        payloadForLog,
+        rootElement,
+        parentContainer,
+        removeSpinner,
+        isApproved: false,
+      });
+    });
+    rejectButton.addEventListener('mouseenter', (event) => {
+      rejectIcon.src = ICONS.CANCEL_WHITE;
+    });
+    rejectButton.addEventListener('mouseleave', (event) => {
+      rejectIcon.src = ICONS.CANCEL;
+    });
path: components/request-card/utils.js
user: login: AnujChhikara
body: added in this PR
created_at: 2025-05-25T13:41:31Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-22T05:39:14Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Review skipped
> 
> Auto incremental reviews are disabled on this repository.
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- walkthrough_start -->

## Summary by CodeRabbit

- **New Features**
	- Introduced new visual enhancements and interactive behaviors for request cards, including improved animations, status indicators, and deadline warnings.
	- Added support for displaying different request types and statuses with corresponding icons and colors.
	- Enhanced user feedback with visual highlights for success and error states, as well as loading spinners during updates.
	- Improved date and deadline formatting for clearer information display.
- **Bug Fixes**
	- Improved error messaging for failed request updates.
- **Chores**
	- Centralized constants and utility functions for better consistency and maintainability in request card components.
## Walkthrough

This update introduces two new modules for the `request-card` component: a constants file defining fixed values, icon paths, and enumerations, and a utilities file providing helper functions for time handling, date formatting, UI manipulation, API interaction, and dynamic DOM construction for request and extension request cards.

## Changes

| File(s)                                      | Change Summary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
|----------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| components/request-card/constant.js          | New module defining constants for animation timing, icon paths, default images, deadline thresholds, hover delay, error messages, and enumerations for request status and type.                                                                                                                                                                                                                                                                                                                                                                                                               |
| components/request-card/utils.js             | New module introducing utility functions for time/date conversion, deadline color calculation, date formatting, UI state toggling, loading spinners, accordion handling, card removal with animation, API request status updates, and creation of structured DOM elements for request card summaries, text blocks, and date containers.                                                                                                                                                                                                                                                        |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant UI as User Interface
    participant Utils as request-card/utils.js
    participant API as Backend API

    UI->>Utils: updateRequestStatus({ id, body, isExtensionRequest })
    Utils->>API: PATCH /requests or /extension-requests
    API-->>Utils: Response (JSON)
    Utils-->>UI: Updated status or error message

    UI->>Utils: removeCard(element, class, container)
    Utils->>UI: Animate removal, update DOM
```

## Possibly related PRs

- [#994](https://github.com/Real-Dev-Squad/website-dashboard/pull/994): Adds test cases for request card component UI and interactions, complementing the utility and constant additions in this PR.
- [#999](https://github.com/Real-Dev-Squad/website-dashboard/pull/999): Introduces `createRequestCardComponent` which uses the constants and utilities defined here for building the request card UI.
- [#1001](https://github.com/Real-Dev-Squad/website-dashboard/pull/1001): Enhances `createRequestCardComponent` with extended use of `createSummarySection` and `createDateContainer` utilities introduced in this PR.

## Suggested reviewers

- Suvidh-kaushik
- iamitprakash

## Poem

> In the garden of code where requests abound,  
> Constants and helpers now gather around.  
> With icons and dates, and colors that warn,  
> Cards animate softly, no need to mourn.  
> The bunny hops by, with DOM freshly spun—  
> Request cards are ready, the work’s just begun!  
> 🐇✨

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- DwQgtGAEAqAWCWBnSTIEMB26CuAXA9mAOYCmGJATmriQCaQDG+Ats2bgFyQAOFk+AIwBWJBrngA3EsgEBPRvlqU0AgfFwA6NPEgQAfACgjoCEYDEZyAAUASpETZWaCrKNwSPbABsvkCiQBHbGlcSHFcLzpIACIAMxJqLjRaejx4X1jsDDF4fAxkWPw+fyCQxmdaaMgAdzRkBwFmdRp6OUhsREpIAEEMbCEAYVgEAGtnNHRkW0g+5gEugEYABiWAJn4sXFgPGwSvMAAREgkwAGUg5IB6apIBRHUSMFo62AF8Cr8Sbnx7ghcNGDbax2ZK0fyITrIJAODxmACcAHYAKzoDD0WrIBj+ahRPKQVbrACyaHkqzWSI0biBzG0WG42Ao306/FiYQQUzsqAIn1iaDERTZHiYSgEdQ8bRIAA9cFQchgiJ8OipIpADgB5QmMbHiPFefBEeAMVGpcRedTyTLZHX5T5eHH0bklYKIUKwTC0M3ylAYbmdbjjGiQbZebhdZiKbzSAGnUMMeCxQ1oHyyAA0kEtOTy9WwDFgk0gAAMsQkaABRSJsH0FtNF7UkbqZjADPK4WmUavG/hbLoAVQAkmB/HaWpA9QajTd/JBw1IHfh0IW0l5EBohIgC+n0iQAd0Uupchgk15U5Bnq30yRcLn4F6x4bR/ARh4C6RcKXpWR7nldqUXUdW+k641HU6DLvOQ74Aw9phPO3b2GgbDtKa5rThGkQAu4kBSkg4herWJYkD+zq4AMFTNsw3zkFW6ZZI2wHINg3BnlE3JLvAABeHjdsy5DVEGJAhl0GbWiuVKoP4vL8hQN4KtozDINy8AURQ+BSAoSiobQ3jOOaabYs8ahmrgJ7uoqzJ8ipEKnvG8T+D6ny/qExmhiugJCm68rSOgU5KdwFbsFEWRKHwEzxNQDIeLEdqyWip7zhg+ChDeMoRgwHiYPIZ4qGKjAeaQyACgI2IjDJuWYPlGFAkoUh6qGfBMBgCYUGwDpuk5QLCh4GJhCEUR6lByangypXVQJ+DcJWmiQAAcvOjHMQp860JBjjsNQB41JQHg0hpIH+hQoT4KyWyoLYAKzfYxafrAiUFXwNAugoUhUKQp6Xtoy6bVO1CtrmdCUgYFiQORk3Zk4LhUh4eTHgorDsBsbKnZyBQqcwgo4FsRRpr0/RDKM4x6YExGlRM/gSPAJB8bEqPox0XRFooyiqOo2gFgCABi+A+Pg1SlSdiBppgGMsNB4KUcy1MsOjzZKDYKhqKEiCyC6JBo3yIwJdUkS0KQrUeGTFN8U6ZSmTetCJiOWzUAuBuU/RYTSUQpD+LQlVbd5HgJTRB3bPVLCg2m5uIAwHRfvkaYCvEdCigwIw8Cp5NKPQeL88CAP6MY4BQGQyesmgeCEKQ5BUCOTBwz6XC8PwwiiOIUgyPInVUMzmjaLoYCGCYUBwKgqBC/nBDEGQyil/77BcFQfEOOD8htE38vqFoOgZ5npgGGXlHsIglzGy6YBQRQtCXA1LqYJoa4cAY0TX4DljdAORcj1E080i4LJlZ5iBGN0Mx2yfrY+mQOGLSKpCj3SBLvXA+8PgbzyPDXuPoVJaTSrQQOJAEwYFKhIHS+AOibklFEbBXhnSdjIKtEuB4GKdFaipbARAbp4HRrAqiU0+xJWyMQpQCklKlX/mfAoAoD70H8DOJMqIlLrSzJAAAFDefcYilB2hPFpCheQ0wJHuPKAAlILNk4IbpeHoGAt6yRPRdWcJg+UAtOwTCULybwoQ6YhWwa2PgEjXr+i2NGY4yhfCGjxO4jwnjYDIGcB4JQDA7Qu3TAKfsWF/KAPsDmPMIE6DqDTFBbIAkZE3jCNUecTA9R8GwdJfhOjcqiDjrIzY+SFBFMgCU+AZTBaxVsTzDAtRD7eRUtUHcQZVJdEUSSBQ+QAGhGMQgc2XohFQlCWBewsZ4wU1djAWpZC2CqJtGEt6GC6BcALEREIpxWy4A6BuXmWx7AnK8t0Kwtg1QADVSwHDTFYUs00Dh9mmgAcTTAcd5fZnktPoDYUsAApUsAxoDPIANydgOUTEI0BZChnOeoPMzkvKlgABrQumqcPsappppjVKSmRuDDqsiOgmNK5TTJEoAEJqm6DYT5Pydx7mtEeEy9hfIqkoCpPgbAIRoFenw+yxj5o4gcsRdMH0IqzO9JE7AScAbmDvl4GgmzFrowiVEyRNojpYUlN8A6uI+D0gEGaI07B9zSCMFAaaf8sxjNCSkKIuSGYUTgYAneiK95COPi6s+q51yX0gLoQsAwWUHAAPqgsJI87oAAZWNXy+zQD7Cm2N/zk3dAAJqxsJKcAsBgI1QALNG1l8bSyJoedm7o00+yEm6JmolOaew2FbYS6aRaS1lsjZWmNNa60NqbS2ttvbSzdAJT80t5bCz/O6AcZNXzSyxoAOosqbT82N0AAASoLTj7rVMmuNBwC39oXQWf57Nug9mTdAWNPZTilhsLG7o9boAsvnYOvsAx23PIzb+it/723RumgMUsyaQOFjA72iDUHU0bv3Rm0ssGCzwdjQMfdkKADSGGsM4fw5u1D0LCMAd7SymwaoN05to9NDDJ6nnvqrXG1D/yc3QYLaWx1dspSmpHIIEQYhCyHJdMc8KQELl5ifMrfZtz7lPIOB2AsbyPlfO+ap/5TbnmqdBRCqFemDB8b4gJooQma6iYRY5ZFqKajosgHJxA+ycV4oJUS1TpK1ReemkymNmneMzX4yaizuIrOhALKWCggrCTSEQKKkgaLLlyf2T2KwF7oU1oAIo9lLKcaApbr7RAdWvZhW8/WOWgYfS4S4VwXyvjfIG98h7F2gi/Zw8gjW5nKvagwP9eJIXSChYBkZFymnq0BYxcECyQOq7QDc5X7JuhkCQMg3oUrILoGmXgql4BTNkrDXgJBtj5EkB4TolL+KCT4MJShnY4kCVVvDf+FAcx/GQEOaCjp/WhFMlKGgZ28SQKDO6T0RAARsKVZwry4hEINWemHIbRkKbIGkS+S80AlIkD7BgQk6QzSdAarQdc5SlCmJvEKLmAolBaqaIea0MiMe4HEyRanFACx0tiswBx8A/LhOlWAmkuBcIKju1I9HQvqDQHwOzbwXgDg4lU6+aA+SDjwANLgRXNBVNS9wDL7XJA1QYGPJzt231vpK2yLAFSCU8HBjqsgM0T5CygiOEojc02eHTJbCpXwpkCxSpoKzyTpypsChpCVL0ty+zlB8DqoP+tfv8D4ADz8G0QenzD15GTWEYsCg8h6EmsUwWnCJZ8RA4sgnOE0RDow/ZBwCWgmxcQXkbzKo0uLm03JQSdhEQM0c7wDsLJvMXaxBAnYqn+ya0yfImCHw2v6cgy5gUNKQNgblQYNewDNPQ0IT3QYxL4A4BgaUrICgFQKLPUY3KFn71IUih9Pe0UZ5gCRD10b37EUaiYQj4nPfslz1sSb3kFMm2G31wEuHGj5BQhlEwF+EoTTG7CwHv1hyBAP3hlMmJ33DyE31BFCSwFVm4GMh4ES2nHizIPjCYRbDbDcWQCIOMgBlOB8SoAyBf3u2LGlRdDezEAinoHVE1AwMSWMTsmClKkz0cFflR07Fpw+hc0LE4JoFOEkM62YMbA3AEGwHSBJwXA6zfgagAmLgc0uVbEQDjlkMAjQQp3IFXxB0xThXwhxGgABwZX6hGGbB9FoMWzrExBoMpwoAEWKA0TxEETHnshoGlEgCtUghGGQFzzSVbCtS4gBw9hAn+3zyFQoPygcMUJIENw8MMPbBGW4Pe1CRGUKOPxul5i9EG3JyL3IGsTTyBywAsJXz7ybxHGYm9HpFwDiMcyIX2wNXIJFQqjcglnYKkTpgXAd3plyPLAANwA3GkTqGniiDTwoEPC8C0RgiiK0MMX/0PyAJF2kk0IegyTtAhGkFX1Hy6AiNwDTAcG4EE1KjeEuSaKR0gQIPoASmajEU+OMLzGwK5V8DiUaQNVEgMDVGeiPCQOpDQiFHYFYI4i8mYkuDhw8EL3BzTDiWvxgknxkkFit1zFt1wXqBOTwUT2sVMloFkEPCaCNAEOKJlHew2hEOTxmQeMYmeK9FeLzHeI2lMlPjRA+H+Nz1aMIXXzEVNh9GUByDUiEN6LVVvh6E1RHnu25Dgj1QDHuyNXMzNWTgtWwCtXvFtVby/hM0gDlytAFPdVoH2RV2x1x3xx8CQFEDyBJ2kXRLTCQHfEBzDlZy0Q3E9SW16Mq2Inm1qwm1DSCytLolBD2ULFfFZ2bCKWkTqLMQyTrFoCxzYEDO9AUJYE3l9Tm0DTq2jItNjNf1tP2T1xlzlx8EN09Ox1PgojTH6iTBIDzODMLJ9VDJLIqEjMAnLKgErJtKTntMxzVw13UEbPRJbO4G9MQFxzUPdMQC7KwC9SLL7N+wjLLLXBjImKwHjLtMLFrPwEN2N2PGkSaBdKJ1XPXILO9RYW3n7Jqz3PXAtO6CJJomtLxGPP2TdxAOvIJ3gBXLRDXKDI3JDJfJ3NLKjP3IrMPPQGrMTMvE5malLEQVR2kSF21zQAfM3N7JgqqzgqHIQpHKQv/NdxSGTSHxkhjBuIoGkQMNoIIugrDJCF3Pgo/Iot/KPJQoLAnyIEiAbHn3NjyCsEwAEmkSXwEjYp7OfI4oDQHPfIPL4uQvHMLAE3dFEqKHEowEkuXxkqkq2MgsfK3OIvDNIuXGHMtMooEsQCqOUNP3i33W3131gFwGkQVPkqfIq1fKPlUsQvUqooLEcp5mi0FTcvoQ8q8p8rMsIsUoCsHJsvIp6G/K7w0oTMDyYhxBD3JMQGkQAG8UBUEojFATwfSPxmjWdIAABfXyiypSqBayybILL82ko0TK0K1Ax/WgbyhJe4g49gAYC46xfaEavw4uRqoi5qrisiniuykKgS3I5QmeNQ60YqlARAX09Pb8X7Rco4ZIZNSnAYSyahKw+ovIkkaxLKCOQxTCknY3Rc0PDoKwHOUqBqhK9i5KoK3iuMlausZw6UVwmIgo2gtM6gNARc9C3YOoPIciLcmapK2ClS7itSgGzSxwmgfIqaygWRHa6q/0g63+aoI6q6xXZWRcp1MmhIWgE68gM6n4C60mx6xAY3B5JMYIQmRySm6xLmWgNm43ZG/y1Gt89GxrErEzDuVebOWKH/AuVrJ+egMuSaCeNAKeFQt+OeRmZuBWJeduTuLOWGJoXAWNfbRAWNW2G4WgWNU+A6Q22WyAOEAANgEARFoAWAEE9rQAABYGBaA4QAAOJEb2oOpYBYOEVYBgVYAAZljtoF9oEAYGRCRCRBICDrQDQFjsdoMC7hNvUHNpJytuOENjoFjRzkNqAA== -->

<!-- internal state end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Real-Dev-Squad/website-dashboard&utm_content=1002):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: AnujChhikara
created_at: 2025-05-22T05:47:26Z
body: @coderabbitai review
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-05-22T05:47:31Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
<details>
<summary>✅ Actions performed</summary>

Review triggered.

> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

</details>
author_association: NONE
user: login: cloudflare-workers-and-pages[bot]
created_at: 2025-05-22T06:18:19Z
body: ## Deploying dashboard-rds with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>602b090</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>&nbsp;✅&nbsp; Deploy successful!</td></tr>
<tr><td><strong>Preview URL:</strong></td><td>
<a href='https://75c69ae9.dashboard-rds.pages.dev'>https://75c69ae9.dashboard-rds.pages.dev</a>
</td></tr>
<tr><td><strong>Branch Preview URL:</strong></td><td>
<a href='https://request-card-util-functions.dashboard-rds.pages.dev'>https://request-card-util-functions.dashboard-rds.pages.dev</a>
</td></tr>
</table>

[View logs](https://dash.cloudflare.com/9a288cd5c278d949cd79ed99f986b061/pages/view/dashboard-rds/75c69ae9-a788-4519-a9d9-65604ae54641)

author_association: NONE