From fc2745cd7d407f00dc649680bc0a5cb0c12abe2f Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Mon, 11 Nov 2024 23:17:25 +0530 Subject: [PATCH 01/11] Added input validation and toast based on api response - behind dev flag. --- extension-requests/script.js | 142 +++++++++++++++++++++++++++++++++-- extension-requests/style.css | 37 ++++++++- 2 files changed, 171 insertions(+), 8 deletions(-) diff --git a/extension-requests/script.js b/extension-requests/script.js index dfe1818b..961570cb 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -227,7 +227,18 @@ const getExtensionColor = (deadline, createdTime) => { return 'orange-text'; }; +const currentUserDetailsPromise = getSelfUser() + .then((response) => { + currentUserDetails = response; + }) + .catch((error) => { + currentUserDetails = null; + }); + async function populateExtensionRequests(query = {}, newLink) { + if (query.dev && !currentUserDetails) { + await currentUserDetailsPromise; + } extensionPageVersion++; const currentVersion = extensionPageVersion; try { @@ -540,6 +551,19 @@ async function createExtensionCard(data, dev) { value: data.title, }, }); + const titleInputWrapper = createElement({ + type: 'div', + attributes: { class: 'title-input-wrapper hidden' }, + }); + const titleInputError = createElement({ + type: 'div', + attributes: { class: 'title-input-error hidden' }, + innerText: 'Title is required', + }); + if (dev) { + titleInputWrapper.appendChild(titleInput); + titleInputWrapper.appendChild(titleInputError); + } const commitedHoursHoverCard = createElement({ type: 'div', attributes: { class: 'comitted-hours hidden' }, @@ -562,7 +586,11 @@ async function createExtensionCard(data, dev) { }); commitedHoursHoverCard.appendChild(CommitedHourslabel); commitedHoursHoverCard.appendChild(CommitedHoursContent); - extensionCardHeaderWrapper.appendChild(titleInput); + if (dev) { + extensionCardHeaderWrapper.appendChild(titleInputWrapper); + } else { + extensionCardHeaderWrapper.appendChild(titleInput); + } extensionCardHeaderWrapper.appendChild(titleText); extensionCardHeaderWrapper.appendChild(commitedHoursHoverTrigger); extensionCardHeaderWrapper.appendChild(commitedHoursHoverCard); @@ -806,7 +834,15 @@ async function createExtensionCard(data, dev) { value: dateString(secondsToMilliSeconds(data.newEndsOn)), }, }); + const extensionInputError = createElement({ + type: 'div', + attributes: { class: 'extension-input-error hidden' }, + innerText: "Past date can't be the new deadline", + }); newDeadlineContainer.appendChild(extensionInput); + if (dev) { + newDeadlineContainer.appendChild(extensionInputError); + } extensionForContainer.appendChild(extensionForValue); const extensionRequestNumberContainer = createElement({ type: 'div' }); @@ -909,7 +945,13 @@ async function createExtensionCard(data, dev) { type: 'button', attributes: { class: 'edit-button' }, }); - extensionCardButtons.appendChild(editButton); + if (dev) { + if (shouldDisplayEditButton(data.assigneeId)) { + extensionCardButtons.appendChild(editButton); + } + } else { + extensionCardButtons.appendChild(editButton); + } const editIcon = createElement({ type: 'img', attributes: { src: EDIT_ICON, alt: 'edit-icon' }, @@ -971,10 +1013,30 @@ async function createExtensionCard(data, dev) { updateAccordionHeight(panel); }); updateButton.addEventListener('click', (event) => { - toggleInputs(); - toggleActionButtonVisibility(); - editButton.classList.toggle('hidden'); - updateWrapper.classList.toggle('hidden'); + if (dev) { + const isTitleMissing = !titleInput.value; + const isReasonMissing = !reasonInput.value; + const todayDate = Math.floor(new Date().getTime() / 1000); + const newDeadline = new Date(extensionInput.value).getTime() / 1000; + const isDeadlineInPast = newDeadline < todayDate; + + titleInputError.classList.toggle('hidden', !isTitleMissing); + reasonInputError.classList.toggle('hidden', !isReasonMissing); + extensionInputError.classList.toggle('hidden', !isDeadlineInPast); + + if (!isTitleMissing && !isReasonMissing && !isDeadlineInPast) { + toggleInputs(); + toggleActionButtonVisibility(); + editButton.classList.toggle('hidden'); + updateWrapper.classList.toggle('hidden'); + titleInputWrapper.classList.add('hidden'); + } + } else { + toggleInputs(); + toggleActionButtonVisibility(); + editButton.classList.toggle('hidden'); + updateWrapper.classList.toggle('hidden'); + } }); cancelButton.addEventListener('click', (event) => { titleInput.value = data.title; @@ -985,6 +1047,11 @@ async function createExtensionCard(data, dev) { toggleActionButtonVisibility(); editButton.classList.toggle('hidden'); updateWrapper.classList.toggle('hidden'); + if (dev) { + titleInputError.classList.add('hidden'); + reasonInputError.classList.add('hidden'); + extensionInputError.classList.add('hidden'); + } }); const payloadForLog = { body: {}, @@ -1115,7 +1182,15 @@ async function createExtensionCard(data, dev) { }, innerText: data.reason, }); + const reasonInputError = createElement({ + type: 'span', + attributes: { class: 'reason-input-error red-text hidden' }, + innerText: 'Reason is required', + }); reasonContainer.appendChild(reasonInput); + if (dev) { + reasonContainer.appendChild(reasonInputError); + } reasonContainer.appendChild(reasonParagraph); const renderExtensionCreatedLog = () => { @@ -1171,6 +1246,16 @@ async function createExtensionCard(data, dev) { e.preventDefault(); let formData = formDataToObject(new FormData(e.target)); formData['newEndsOn'] = new Date(formData['newEndsOn']).getTime() / 1000; + if (dev) { + const todayDate = Math.floor(new Date().getTime() / 1000); + if ( + !formData.title || + !formData.reason || + formData['newEndsOn'] < todayDate + ) { + return; + } + } const removeSpinner = addSpinner(rootElement); rootElement.classList.add('disabled'); const revertDataChange = updateCardData(formData); @@ -1207,11 +1292,22 @@ async function createExtensionCard(data, dev) { data.tile = formData.title; data.newEndsOn = data.newEndsOn; handleSuccess(rootElement); + if (dev) { + const successMessage = 'Extension request successfully updated.'; + showToast(successMessage, 'success'); + } appendLogs(payloadForLog, data.id); }) - .catch(() => { + .catch((error) => { revertDataChange(); handleFailure(rootElement); + if (dev) { + const errorMessage = + error?.response?.data?.message || + error?.message || + 'An error occurred. Please try again.'; + showToast(errorMessage, 'error'); + } }) .finally(() => { rootElement.classList.remove('disabled'); @@ -1257,6 +1353,9 @@ async function createExtensionCard(data, dev) { return revertDataChange; } function toggleInputs() { + if (dev) { + titleInputWrapper.classList.toggle('hidden'); + } titleInput.classList.toggle('hidden'); titleText.classList.toggle('hidden'); reasonInput.classList.toggle('hidden'); @@ -1398,6 +1497,35 @@ async function createExtensionCard(data, dev) { } } +function shouldDisplayEditButton(assigneeId) { + return ( + currentUserDetails && + (assigneeId === currentUserDetails.id || + currentUserDetails.roles.super_user) + ); +} + +function showToast(message, type) { + const existingToast = document.querySelector( + '.extension-request-update-toast', + ); + if (existingToast) { + existingToast.remove(); + } + const toast = document.createElement('div'); + toast.className = `extension-request-update-toast toast-${type}`; + toast.textContent = message; + + document.body.appendChild(toast); + + setTimeout(() => { + toast.classList.add('fade-out'); + toast.addEventListener('transitionend', () => { + toast.remove(); + }); + }, 3000); +} + function generateSentence(response, parentClassName, id) { let arraySentence = []; let sentence = ''; diff --git a/extension-requests/style.css b/extension-requests/style.css index bfcafebe..6a066ab7 100644 --- a/extension-requests/style.css +++ b/extension-requests/style.css @@ -773,8 +773,43 @@ body { align-items: center; justify-content: space-between; position: relative; - height: 1.6rem; + height: 2rem; +} + +.title-input-wrapper { + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.title-input-error, +.reason-input-error, +.extension-input-error { + font-size: 12px; + color: var(--red-color); } + +.extension-request-update-toast { + position: fixed; + bottom: 20px; + right: 20px; + padding: 15px 20px; + background-color: var(--red-color); + color: #fff; + font-size: 14px; + border-radius: 5px; + opacity: 1; + transition: opacity 0.3s ease; + z-index: 1000; +} + +.extension-request-update-toast.fade-out { + opacity: 0; +} + +.extension-request-update-toast.toast-success { + background-color: var(--green-color); +} + .disabled { opacity: 0.5; pointer-events: none; From ddff30bde5a3785b31a1181cbdc435f4a6e5b6ca Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Wed, 13 Nov 2024 13:47:01 +0530 Subject: [PATCH 02/11] Added tests for input validation and edit button under dev flag. --- .../extension-requests.test.js | 91 +++++++++++++++++++ extension-requests/script.js | 27 ++++-- 2 files changed, 112 insertions(+), 6 deletions(-) diff --git a/__tests__/extension-requests/extension-requests.test.js b/__tests__/extension-requests/extension-requests.test.js index b8d50c5e..b3482dac 100644 --- a/__tests__/extension-requests/extension-requests.test.js +++ b/__tests__/extension-requests/extension-requests.test.js @@ -740,6 +740,97 @@ describe('Tests the Extension Requests Screen', () => { expect(taskStatusValueElement).toBeTruthy(); }); + it('shows error messages for empty title and reason inputs on update under dev feature flag', async () => { + await page.goto(`${baseUrl}/?dev=true`); + const editButtonSelector = '[data-testid="edit-button"]'; + const editButton = await page.$(editButtonSelector); + if (!editButton) { + return; + } + await page.click(editButtonSelector); + const updateButtonSelector = '[data-testid="update-button"]'; + const titleInputSelector = '[data-testid="title-text-input"]'; + const reasonInputSelector = '[data-testid="reason-input-text-area"]'; + const titleErrorSelector = '[data-testid="title-input-error"]'; + const reasonErrorSelector = '[data-testid="reason-input-error"]'; + + await page.evaluate((selector) => { + const element = document.querySelector(selector); + if (element) element.value = ''; + }, titleInputSelector); + + await page.evaluate((selector) => { + const element = document.querySelector(selector); + if (element) element.value = ''; + }, reasonInputSelector); + + await page.click(updateButtonSelector); + + const isTitleErrorVisible = await page + .$eval(titleErrorSelector, (el) => el && !el.classList.contains('hidden')) + .catch(() => false); + + const isReasonErrorVisible = await page + .$eval( + reasonErrorSelector, + (el) => el && !el.classList.contains('hidden'), + ) + .catch(() => false); + expect(isTitleErrorVisible).toBe(true); + expect(isReasonErrorVisible).toBe(true); + }); + + it('shows error message if deadline is set to past date under dev feature flag', async () => { + await page.goto(`${baseUrl}/?dev=true`); + const editButtonSelector = '[data-testid="edit-button"]'; + const editButton = await page.$(editButtonSelector); + if (!editButton) { + return; + } + + await page.click(editButtonSelector); + + const extensionInputSelector = '[data-testid="extension-input"]'; + const extensionErrorSelector = '[data-testid="extension-input-error"]'; + await page.type(extensionInputSelector, '2020-01-01'); + await page.click('[data-testid="update-button"]'); + const isExtensionErrorVisible = await page.$eval( + extensionErrorSelector, + (el) => !el.classList.contains('hidden'), + ); + expect(isExtensionErrorVisible).toBe(true); + }); + + it('hides edit button and displays update wrapper on successful update under dev feature flag', async () => { + await page.goto(`${baseUrl}/?dev=true`); + const editButtonSelector = '[data-testid="edit-button"]'; + const editButton = await page.$(editButtonSelector); + if (!editButton) { + return; + } + + await page.click(editButtonSelector); + + const updateButtonSelector = '[data-testid="update-button"]'; + const updateWrapperSelector = '[data-testid="update-wrapper"]'; + + 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.click(updateButtonSelector); + + const isEditButtonHidden = await page.$eval(editButtonSelector, (el) => + el.classList.contains('hidden'), + ); + const isUpdateWrapperVisible = await page.$eval( + updateWrapperSelector, + (el) => !el.classList.contains('hidden'), + ); + expect(isEditButtonHidden).toBe(true); + expect(isUpdateWrapperVisible).toBe(true); + }); + it('Checks whether the card is not removed from display when api call is unsuccessful', async () => { const extensionCards = await page.$$('.extension-card'); diff --git a/extension-requests/script.js b/extension-requests/script.js index 961570cb..7fe5c9f1 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -549,6 +549,7 @@ async function createExtensionCard(data, dev) { id: 'title', name: 'title', value: data.title, + 'data-testid': 'title-text-input', }, }); const titleInputWrapper = createElement({ @@ -557,7 +558,10 @@ async function createExtensionCard(data, dev) { }); const titleInputError = createElement({ type: 'div', - attributes: { class: 'title-input-error hidden' }, + attributes: { + class: 'title-input-error hidden', + 'data-testid': 'title-input-error', + }, innerText: 'Title is required', }); if (dev) { @@ -832,11 +836,15 @@ async function createExtensionCard(data, dev) { id: 'newEndsOn', oninput: 'this.blur()', value: dateString(secondsToMilliSeconds(data.newEndsOn)), + 'data-testid': 'extension-input', }, }); const extensionInputError = createElement({ type: 'div', - attributes: { class: 'extension-input-error hidden' }, + attributes: { + class: 'extension-input-error hidden', + 'data-testid': 'extension-input-error', + }, innerText: "Past date can't be the new deadline", }); newDeadlineContainer.appendChild(extensionInput); @@ -943,7 +951,7 @@ async function createExtensionCard(data, dev) { } else { const editButton = createElement({ type: 'button', - attributes: { class: 'edit-button' }, + attributes: { class: 'edit-button', 'data-testid': 'edit-button' }, }); if (dev) { if (shouldDisplayEditButton(data.assigneeId)) { @@ -959,12 +967,15 @@ async function createExtensionCard(data, dev) { editButton.appendChild(editIcon); const updateWrapper = createElement({ type: 'div', - attributes: { class: 'update-wrapper hidden' }, + attributes: { + class: 'update-wrapper hidden', + 'data-testid': 'update-wrapper', + }, }); extensionCardButtons.appendChild(updateWrapper); const updateButton = createElement({ type: 'button', - attributes: { class: 'update-button' }, + attributes: { class: 'update-button', 'data-testid': 'update-button' }, innerText: 'SAVE', }); @@ -1179,12 +1190,16 @@ async function createExtensionCard(data, dev) { class: 'input-text-area hidden', id: 'reason', name: 'reason', + 'data-testid': 'reason-input-text-area', }, innerText: data.reason, }); const reasonInputError = createElement({ type: 'span', - attributes: { class: 'reason-input-error red-text hidden' }, + attributes: { + class: 'reason-input-error red-text hidden', + 'data-testid': 'reason-input-error', + }, innerText: 'Reason is required', }); reasonContainer.appendChild(reasonInput); From c90d8381e4d8b8bbb3c9c61af46628fcbc29947d Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Wed, 27 Nov 2024 23:17:59 +0530 Subject: [PATCH 03/11] Added dev flag in ER update api request. --- extension-requests/local-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js index 78769c11..a238e88f 100644 --- a/extension-requests/local-utils.js +++ b/extension-requests/local-utils.js @@ -104,7 +104,7 @@ const parseExtensionRequestParams = (uri, nextPageParamsObject) => { }; async function updateExtensionRequest({ id, body }) { - const url = `${API_BASE_URL}/extension-requests/${id}`; + const url = `${API_BASE_URL}/extension-requests/${id}?dev=true`; const res = await fetch(url, { credentials: 'include', method: 'PATCH', From 3e2490afc23162405e36f6a2acd756d13512f626 Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Sun, 1 Dec 2024 21:22:03 +0530 Subject: [PATCH 04/11] Resolved failing test cases. --- extension-requests/local-utils.js | 6 ++++-- extension-requests/script.js | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js index a238e88f..32015d0c 100644 --- a/extension-requests/local-utils.js +++ b/extension-requests/local-utils.js @@ -103,8 +103,10 @@ const parseExtensionRequestParams = (uri, nextPageParamsObject) => { return nextPageParamsObject; }; -async function updateExtensionRequest({ id, body }) { - const url = `${API_BASE_URL}/extension-requests/${id}?dev=true`; +async function updateExtensionRequest({ id, body, dev }) { + const url = dev + ? `${API_BASE_URL}/extension-requests/${id}?dev=true` + : `${API_BASE_URL}/extension-requests/${id}`; const res = await fetch(url, { credentials: 'include', method: 'PATCH', diff --git a/extension-requests/script.js b/extension-requests/script.js index 88f8886a..02743e34 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -1260,6 +1260,7 @@ async function createExtensionCard(data, dev) { updateExtensionRequest({ id: data.id, body: formData, + dev: dev, }) .then(() => { data.reason = formData.reason; From 490dd27e05e215b7b037c00293f0c6331489942d Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Tue, 3 Dec 2024 19:21:20 +0530 Subject: [PATCH 05/11] Updated failing tests based on new changes. --- __tests__/extension-requests/extension-requests.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__tests__/extension-requests/extension-requests.test.js b/__tests__/extension-requests/extension-requests.test.js index 8ce69c0d..2653d5aa 100644 --- a/__tests__/extension-requests/extension-requests.test.js +++ b/__tests__/extension-requests/extension-requests.test.js @@ -655,7 +655,7 @@ describe('Tests the Extension Requests Screen', () => { }); it('shows error messages for empty title and reason inputs on update under dev feature flag', async () => { - await page.goto(`${baseUrl}/?dev=true`); + await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`); const editButtonSelector = '[data-testid="edit-button"]'; const editButton = await page.$(editButtonSelector); if (!editButton) { @@ -695,7 +695,7 @@ describe('Tests the Extension Requests Screen', () => { }); it('shows error message if deadline is set to past date under dev feature flag', async () => { - await page.goto(`${baseUrl}/?dev=true`); + await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`); const editButtonSelector = '[data-testid="edit-button"]'; const editButton = await page.$(editButtonSelector); if (!editButton) { @@ -716,7 +716,7 @@ describe('Tests the Extension Requests Screen', () => { }); it('hides edit button and displays update wrapper on successful update under dev feature flag', async () => { - await page.goto(`${baseUrl}/?dev=true`); + await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`); const editButtonSelector = '[data-testid="edit-button"]'; const editButton = await page.$(editButtonSelector); if (!editButton) { From ec02a3679b76ba4585d2cdb835a8ce05ffe86b92 Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Sun, 8 Dec 2024 19:33:57 +0530 Subject: [PATCH 06/11] Added missing tests. --- .../extension-requests.test.js | 72 ++++++++++++++++++- extension-requests/script.js | 21 +++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/__tests__/extension-requests/extension-requests.test.js b/__tests__/extension-requests/extension-requests.test.js index 2653d5aa..31382af6 100644 --- a/__tests__/extension-requests/extension-requests.test.js +++ b/__tests__/extension-requests/extension-requests.test.js @@ -706,11 +706,15 @@ describe('Tests the Extension Requests Screen', () => { const extensionInputSelector = '[data-testid="extension-input"]'; const extensionErrorSelector = '[data-testid="extension-input-error"]'; - await page.type(extensionInputSelector, '2020-01-01'); + await page.$eval(extensionInputSelector, (input) => { + input.value = '2020-01-01'; + }); await page.click('[data-testid="update-button"]'); const isExtensionErrorVisible = await page.$eval( extensionErrorSelector, - (el) => !el.classList.contains('hidden'), + (el) => + !el.classList.contains('hidden') && + el.innerText.includes("Past date can't be the new deadline"), ); expect(isExtensionErrorVisible).toBe(true); }); @@ -745,6 +749,70 @@ describe('Tests the Extension Requests Screen', () => { expect(isUpdateWrapperVisible).toBe(true); }); + it('handles long title and long reason properly under dev feature flag', async () => { + await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`); + + const editButtonSelector = '[data-testid="edit-button"]'; + const titleInputSelector = '[data-testid="title-text-input"]'; + const reasonInputSelector = '[data-testid="reason-input-text-area"]'; + const titleDisplaySelector = '.title-text'; + const reasonDisplaySelector = '.reason-text'; + + const longTitle = 'A'.repeat(300); + const longReason = 'This is a very long reason '.repeat(50); + + const editButton = await page.$(editButtonSelector); + if (!editButton) { + return; + } + await page.click(editButtonSelector); + + await page.type(titleInputSelector, longTitle); + await page.type(reasonInputSelector, longReason); + + const isTitleTruncated = await page.$eval( + titleDisplaySelector, + (el) => window.getComputedStyle(el).textOverflow === 'ellipsis', + ); + + const isReasonWrapped = await page.$eval( + reasonDisplaySelector, + (el) => window.getComputedStyle(el).whiteSpace === 'normal', + ); + + expect(isTitleTruncated).toBe(true); + expect(isReasonWrapped).toBe(true); + }); + + it('displays an error message for invalid date format under dev feature flag', async () => { + await page.goto(`${LOCAL_TEST_PAGE_URL}/extension-requests/?dev=true`); + + const editButtonSelector = '[data-testid="edit-button"]'; + const editButton = await page.$(editButtonSelector); + if (!editButton) { + return; + } + + await page.click(editButtonSelector); + + const extensionInputSelector = '[data-testid="extension-input"]'; + const extensionErrorSelector = '[data-testid="extension-input-error"]'; + + await page.$eval(extensionInputSelector, (input) => { + input.value = 'invalid-date'; + }); + await page.click('[data-testid="update-button"]'); + + const isExtensionErrorVisible = await page.$eval( + extensionErrorSelector, + (el) => + !el.classList.contains('hidden') && + el.innerText.includes('Invalid date format.'), + ); + + expect(isExtensionErrorVisible).toBe(true); + }); + it('Checks whether the card is not removed from display when api call is unsuccessful', async () => { const extensionCards = await page.$$('.extension-card'); diff --git a/extension-requests/script.js b/extension-requests/script.js index 02743e34..ac7cb435 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -989,12 +989,28 @@ async function createExtensionCard(data, dev) { const todayDate = Math.floor(new Date().getTime() / 1000); const newDeadline = new Date(extensionInput.value).getTime() / 1000; const isDeadlineInPast = newDeadline < todayDate; + const isInvalidDateFormat = isNaN(newDeadline); + + if (isInvalidDateFormat) { + extensionInputError.innerText = + 'Invalid date format. Please provide a valid date.'; + } else if (isDeadlineInPast) { + extensionInputError.innerText = + "Past date can't be the new deadline."; + } titleInputError.classList.toggle('hidden', !isTitleMissing); reasonInputError.classList.toggle('hidden', !isReasonMissing); - extensionInputError.classList.toggle('hidden', !isDeadlineInPast); + extensionInputError.classList.toggle( + 'hidden', + !(isDeadlineInPast || isInvalidDateFormat), + ); - if (!isTitleMissing && !isReasonMissing && !isDeadlineInPast) { + if ( + !isTitleMissing && + !isReasonMissing && + !(isDeadlineInPast || isInvalidDateFormat) + ) { toggleInputs(); toggleActionButtonVisibility(); editButton.classList.toggle('hidden'); @@ -1225,6 +1241,7 @@ async function createExtensionCard(data, dev) { if ( !formData.title || !formData.reason || + isNaN(formData['newEndsOn']) || formData['newEndsOn'] < todayDate ) { return; From f64ab02f62d771f6775c0f32efb9924fb06d2918 Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Sun, 8 Dec 2024 19:49:30 +0530 Subject: [PATCH 07/11] Changed the confusing dev feature flag name. --- extension-requests/local-utils.js | 4 ++-- extension-requests/script.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js index 32015d0c..c0a6b9a5 100644 --- a/extension-requests/local-utils.js +++ b/extension-requests/local-utils.js @@ -103,8 +103,8 @@ const parseExtensionRequestParams = (uri, nextPageParamsObject) => { return nextPageParamsObject; }; -async function updateExtensionRequest({ id, body, dev }) { - const url = dev +async function updateExtensionRequest({ id, body, underDevFeatureFlag }) { + const url = underDevFeatureFlag ? `${API_BASE_URL}/extension-requests/${id}?dev=true` : `${API_BASE_URL}/extension-requests/${id}`; const res = await fetch(url, { diff --git a/extension-requests/script.js b/extension-requests/script.js index ac7cb435..4efaeb74 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -1277,7 +1277,7 @@ async function createExtensionCard(data, dev) { updateExtensionRequest({ id: data.id, body: formData, - dev: dev, + underDevFeatureFlag: dev, }) .then(() => { data.reason = formData.reason; From f3884423f53fd47b7df4cf8dd289052012d4863b Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Fri, 13 Dec 2024 00:17:58 +0530 Subject: [PATCH 08/11] Added Error Handling for Unavailable user details. --- extension-requests/script.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extension-requests/script.js b/extension-requests/script.js index 4efaeb74..c1890069 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -233,6 +233,9 @@ const currentUserDetailsPromise = getSelfUser() }) .catch((error) => { currentUserDetails = null; + if (isDev) { + showToast(error?.message || "Couldn't fetch user details.", 'error'); + } }); async function populateExtensionRequests(query = {}, newLink) { From 48ac2ef6866e6fdbb05932c33333f65cc905b846 Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Sat, 14 Dec 2024 22:06:48 +0530 Subject: [PATCH 09/11] Changes style values to 8/4 metric and made toast timing a constant. --- extension-requests/constants.js | 2 ++ extension-requests/script.js | 2 +- extension-requests/style.css | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/extension-requests/constants.js b/extension-requests/constants.js index d3575b10..f74146a3 100644 --- a/extension-requests/constants.js +++ b/extension-requests/constants.js @@ -41,3 +41,5 @@ const SORT_ASC_ICON = 'asc-sort-icon'; const SORT_DESC_ICON = 'desc-sort-icon'; const OLDEST_FIRST = 'Oldest first'; const NEWEST_FIRST = 'Newest first'; + +const UPDATE_TOAST_TIMING = 3000; diff --git a/extension-requests/script.js b/extension-requests/script.js index c1890069..e029c8c6 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -1481,7 +1481,7 @@ function showToast(message, type) { toast.addEventListener('transitionend', () => { toast.remove(); }); - }, 3000); + }, UPDATE_TOAST_TIMING); } function generateSentence(response, parentClassName, id) { diff --git a/extension-requests/style.css b/extension-requests/style.css index 6a066ab7..f3166f3a 100644 --- a/extension-requests/style.css +++ b/extension-requests/style.css @@ -790,13 +790,13 @@ body { .extension-request-update-toast { position: fixed; - bottom: 20px; - right: 20px; - padding: 15px 20px; + bottom: 24px; + right: 24px; + padding: 16px 24px; background-color: var(--red-color); color: #fff; - font-size: 14px; - border-radius: 5px; + font-size: 16px; + border-radius: 4px; opacity: 1; transition: opacity 0.3s ease; z-index: 1000; From 20a6ff63c5af0ad7b5f196ee13bd27a0d1249f76 Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Sun, 15 Dec 2024 12:27:32 +0530 Subject: [PATCH 10/11] Changed the getSelfUser endpoint to new one. --- extension-requests/local-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js index c0a6b9a5..200d8dc3 100644 --- a/extension-requests/local-utils.js +++ b/extension-requests/local-utils.js @@ -10,7 +10,7 @@ const Order = { }; async function getSelfUser() { try { - const res = await fetch(`${API_BASE_URL}/users/self`, { + const res = await fetch(`${API_BASE_URL}/users?profile=true`, { method: 'GET', credentials: 'include', headers: { From 3a2cda057825a6401dbad43998f67f7ac0b43a58 Mon Sep 17 00:00:00 2001 From: Tanu Chahal Date: Sun, 15 Dec 2024 14:14:02 +0530 Subject: [PATCH 11/11] Updated the getSelfUser() url for tests. --- __tests__/extension-requests/extension-requests.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/extension-requests/extension-requests.test.js b/__tests__/extension-requests/extension-requests.test.js index 31382af6..392c0de1 100644 --- a/__tests__/extension-requests/extension-requests.test.js +++ b/__tests__/extension-requests/extension-requests.test.js @@ -281,7 +281,7 @@ describe('Tests the Extension Requests Screen', () => { }, body: JSON.stringify(extensionRequestListForAuditLogs), }); - } else if (url === `${STAGING_API_URL}/users/self`) { + } else if (url === `${STAGING_API_URL}/users?profile=true`) { interceptedRequest.respond({ status: 200, contentType: 'application/json',