From b2bfb82833b6deebc3a44918b8e0fe70c003e379 Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Sat, 14 Jan 2023 19:46:40 +0530 Subject: [PATCH 1/9] refactor private options handler --- script.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/script.js b/script.js index 1281fd51..fc5652ac 100644 --- a/script.js +++ b/script.js @@ -1,13 +1,16 @@ const userManagementLink = document.getElementById(USER_MANAGEMENT_LINK); -export async function showUserManagementButton() { + +export async function showSuperUserOptions(...privateBtns) { try { const isSuperUser = await checkUserIsSuperUser(); if (isSuperUser) { - userManagementLink.classList.remove('element-display-remove'); + privateBtns.forEach((btn) => + btn.classList.remove('element-display-remove'), + ); } } catch (err) { console.log(err); } } -showUserManagementButton(); +showSuperUserOptions(userManagementLink); From d4691d079a0f5742db82d4dd97d561da8e950d22 Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Sat, 14 Jan 2023 19:59:11 +0530 Subject: [PATCH 2/9] basic setup --- constants.js | 3 ++- extension-requests/index.html | 11 +++++++++++ extension-requests/script.js | 0 extension-requests/style.css | 0 index.html | 7 +++++++ script.js | 9 ++++++++- style.css | 31 ++++++++++++++++++++++++++----- 7 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 extension-requests/index.html create mode 100644 extension-requests/script.js create mode 100644 extension-requests/style.css diff --git a/constants.js b/constants.js index d4b50532..61341eac 100644 --- a/constants.js +++ b/constants.js @@ -1,2 +1,3 @@ -const API_BASE_URL = 'https://api.realdevsquad.com'; +const API_BASE_URL = 'http://localhost:3000'; const USER_MANAGEMENT_LINK = 'user-management-link'; +const EXTENSION_REQUESTS_LINK = 'extension-requests-link'; diff --git a/extension-requests/index.html b/extension-requests/index.html new file mode 100644 index 00000000..3e796a6e --- /dev/null +++ b/extension-requests/index.html @@ -0,0 +1,11 @@ + + + + + + + Extension Requests + + + + diff --git a/extension-requests/script.js b/extension-requests/script.js new file mode 100644 index 00000000..e69de29b diff --git a/extension-requests/style.css b/extension-requests/style.css new file mode 100644 index 00000000..e69de29b diff --git a/index.html b/index.html index 3d82a865..c779a060 100644 --- a/index.html +++ b/index.html @@ -37,6 +37,13 @@ > User Management + + Extension Requests + Online Members diff --git a/script.js b/script.js index fc5652ac..b0a86648 100644 --- a/script.js +++ b/script.js @@ -1,4 +1,5 @@ const userManagementLink = document.getElementById(USER_MANAGEMENT_LINK); +const extensionRequestsLink = document.getElementById(EXTENSION_REQUESTS_LINK); export async function showSuperUserOptions(...privateBtns) { try { @@ -13,4 +14,10 @@ export async function showSuperUserOptions(...privateBtns) { } } -showSuperUserOptions(userManagementLink); +/* + * To show the super user options only to the super user, give all those + * buttons or node the class "element-display-remove" so by default they are hidden. + * Then get the node from the DOM into a variable and pass that variable in the + * function below. + */ +showSuperUserOptions(userManagementLink, extensionRequestsLink); diff --git a/style.css b/style.css index a24d3915..c650199d 100644 --- a/style.css +++ b/style.css @@ -35,8 +35,9 @@ body { height: 80vh; display: flex; justify-content: center; - align-items: center; + align-content: center; gap: 20px; + flex-wrap: wrap; } button { @@ -58,7 +59,7 @@ button { .create-task-btn:hover { color: white; background-color: #1d1283; - border: none; + border-color: transparent; } /* profile section */ @@ -82,7 +83,7 @@ button { .profile-task-btn:hover { color: white; background-color: #1d1283; - border: none; + border-color: transparent; } #user-management-link { color: black; @@ -100,7 +101,27 @@ button { #user-management-link:hover { color: var(--white-color); background-color: var(--blue-color); - border: none; + border-color: transparent; +} + +/* Extension Requests */ +#extension-requests-link { + color: black; + font-weight: 500; + font-size: larger; + background-color: var(--white-color); + border: 2px solid var(--black-color); + border-radius: 5px; + padding: 10px 50px; + cursor: pointer; + transition: all 0.5s ease; + width: max-content; + text-decoration: none; +} +#extension-requests-link:hover { + color: var(--white-color); + background-color: var(--blue-color); + border-color: transparent; } /* Online-members */ @@ -117,7 +138,7 @@ button { .online-members-link:hover { color: white; background-color: #1d1283; - border: none; + border-color: transparent; } .info-repo { From 2047c82c3c5beb5af6c6b0a86a1d5837c8c7d73d Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Mon, 16 Jan 2023 23:41:12 +0530 Subject: [PATCH 3/9] draft feature --- extension-requests/index.html | 46 ++++++- extension-requests/local-utils.js | 92 ++++++++++++++ extension-requests/script.js | 150 +++++++++++++++++++++++ extension-requests/style.css | 192 ++++++++++++++++++++++++++++++ utils.js | 27 +++++ 5 files changed, 506 insertions(+), 1 deletion(-) create mode 100644 extension-requests/local-utils.js diff --git a/extension-requests/index.html b/extension-requests/index.html index 3e796a6e..f64bcd32 100644 --- a/extension-requests/index.html +++ b/extension-requests/index.html @@ -7,5 +7,49 @@ Extension Requests - + +
+
+ +
+

Update Extension Request Status

+ + + + + + + + + + +
+
+
+

Extension Requests

+
+
+
+
+

+ + + + + diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js new file mode 100644 index 00000000..b0264636 --- /dev/null +++ b/extension-requests/local-utils.js @@ -0,0 +1,92 @@ +async function getExtensionRequests(query = {}) { + const url = new URL(`${API_BASE_URL}/extensionRequests`); + + const { assignee, status, taskId } = query; + if (assignee) url.searchParams.set('assignee', assignee); + if (status) url.searchParams.set('status', status); + if (taskId) url.searchParams.set('taskId', taskId); + + const res = await fetch(url, { + credentials: 'include', + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + return await res.json(); +} + +async function createExtensionRequestStatus({ extensionRequest }) { + const url = `${API_BASE_URL}/extensionRequests`; + const res = await fetch(url, { + credentials: 'include', + method: 'POST', + body: JSON.stringify(extensionRequest), + headers: { + 'Content-type': 'application/json', + }, + }); + return await res.json(); +} + +async function updateExtensionRequestStatus({ id, status }) { + const url = `${API_BASE_URL}/extensionRequests/${id}/status`; + const res = await fetch(url, { + credentials: 'include', + method: 'PATCH', + body: JSON.stringify({ status }), + headers: { + 'Content-type': 'application/json', + }, + }); + return await res.json(); +} + +async function getTaskDetails(taskId) { + if (!taskId) return; + const url = `${API_BASE_URL}/tasks/${taskId}/details`; + const res = await fetch(url, { + credentials: 'include', + method: 'GET', + headers: { + 'Content-type': 'application/json', + }, + }); + return await res.json(); +} + +function getTimeFromTimestamp(timestamp) { + return new Date(timestamp * 1000).toLocaleString(); +} + +function createTable(headings, data, className = '') { + const main = createElement({ + type: 'table', + attributes: { + class: className, + }, + }); + const content = createElement({ type: 'tbody' }); + headings.forEach(({ title, key, time, bold }) => { + let row = createElement({ type: 'tr' }); + let heading = createElement({ type: 'th', innerText: title }); + + let contentText = ''; + if (time) contentText = getTimeFromTimestamp(data[key]); + else contentText = key ? data[key] : data[title.toLowerCase()]; + + let text = createElement({ + type: 'td', + innerText: contentText, + attributes: { + class: bold ? 'bold' : '', + }, + }); + row.appendChild(heading); + row.appendChild(text); + content.appendChild(row); + }); + + main.appendChild(content); + return main; +} diff --git a/extension-requests/script.js b/extension-requests/script.js index e69de29b..aa0eb759 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -0,0 +1,150 @@ +const container = document.querySelector('.container'); +const extensionRequestsContainer = document.querySelector( + '.extension-requests', +); + +const errorHeading = document.querySelector('h2#error'); +const modalParent = document.querySelector('.extension-requests-modal-parent'); +const closeModal = document.querySelectorAll('#close-modal'); + +//modal containers +const modalShowInfo = document.querySelector('.extension-requests-info'); +const modalStatusForm = document.querySelector( + '.extension-requests-status-form', +); + +const state = { + currentExtensionRequest: null, +}; + +const render = async () => { + try { + addLoader(container); + const extensionRequests = await getExtensionRequests(); + const allExtensionRequests = extensionRequests.allExtensionRequests; + allExtensionRequests.forEach((data) => { + extensionRequestsContainer.appendChild(createExtensionRequestCard(data)); + }); + } catch (error) { + errorHeading.textContent = 'Something went wrong'; + errorHeading.classList.add('error-visible'); + reload(); + } finally { + removeLoader(); + } +}; + +const showTaskDetails = async (taskId) => { + if (!taskId) return; + try { + modalShowInfo.innerHTML = '

Task Details

'; + addLoader(modalShowInfo); + const taskDetails = await getTaskDetails(taskId); + const taskData = taskDetails.taskData; + modalShowInfo.append(createTaskInfoModal(taskData)); + } catch (error) { + errorHeading.textContent = 'Something went wrong'; + errorHeading.classList.add('error-visible'); + reload(); + } finally { + removeLoader(); + } +}; + +function updateStatusForm() { + document.querySelector('.extensionId').value = + state.currentExtensionRequest.id; + document.querySelector('.extensionTitle').value = + state.currentExtensionRequest.title; + document.querySelector('.extensionAssignee').value = + state.currentExtensionRequest.assignee; +} + +function createTaskInfoModal(data) { + if (!data) return; + + const dataHeadings = [ + { title: 'Title' }, + { title: 'Ends On', key: 'endsOn', time: true }, + { title: 'Purpose' }, + { title: 'Assignee' }, + { title: 'Created By', key: 'createdBy' }, + { title: 'Is Noteworthy', key: 'isNoteworthy' }, + ]; + + const updateStatus = createElement({ + type: 'button', + attributes: { class: 'status-form' }, + innerText: 'Update Status', + }); + const closeModal = createElement({ + type: 'button', + attributes: { id: 'close-modal' }, + innerText: 'Cancel', + }); + updateStatus.addEventListener('click', () => { + showModal('status-form'); + updateStatusForm(); + }); + closeModal.addEventListener('click', () => hideModal()); + + const main = createTable(dataHeadings, data); + + main.appendChild(updateStatus); + main.appendChild(closeModal); + return main; +} + +function createExtensionRequestCard(data) { + if (!data) return; + + const dataHeadings = [ + { title: 'Title' }, + { title: 'Reason' }, + { title: 'Old Ends On', key: 'oldEndsOn', time: true }, + { title: 'New Ends On', key: 'newEndsOn', time: true }, + { title: 'Status', bold: true }, + { title: 'Assignee' }, + { title: 'Created At', key: 'timestamp', time: true }, + { title: 'Task', key: 'taskId' }, + ]; + + const moreInfoBtn = createElement({ + type: 'button', + attributes: { class: 'more' }, + innerText: 'More', + }); + moreInfoBtn.addEventListener('click', () => { + showModal('info'); + showTaskDetails(data.taskId); + state.currentExtensionRequest = data; + }); + + const main = createTable(dataHeadings, data, 'extension-request'); + + main.appendChild(moreInfoBtn); + return main; +} + +render(); + +modalParent.addEventListener('click', hideModal); +closeModal.forEach((node) => node.addEventListener('click', () => hideModal())); + +function showModal(show = 'form') { + modalParent.classList.add('visible'); + modalParent.setAttribute('show', show); +} +function hideModal(e) { + if (!e) { + modalParent.classList.remove('visible'); + return; + } + e.stopPropagation(); + if (e.target === modalParent) { + modalParent.classList.remove('visible'); + } +} +function reload() { + setTimeout(() => window.history.go(0), 2000); +} diff --git a/extension-requests/style.css b/extension-requests/style.css index e69de29b..14b9a60b 100644 --- a/extension-requests/style.css +++ b/extension-requests/style.css @@ -0,0 +1,192 @@ +:root { + --dark-blue: #1b1378; + --light-aqua: #d4f9f2; + --scandal: #e5fcf5; + --white: #ffffff; + --black-transparent: #000000a8; + --black: #181717; + --light-gray: #d9d9d9; + --razzmatazz: #df0057; + --gray: #808080; + --button-proceed: #008000; +} + +*, +::after, +::before { + box-sizing: border-box; +} + +button { + cursor: pointer; +} + +.bold { + font-weight: bolder; +} + +body { + font-family: 'Roboto', sans-serif; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + min-height: 100vh; + user-select: none; + max-width: 100vw; +} + +.container { + width: 100%; + text-align: center; + padding: 10px; +} + +.header { + background-color: var(--dark-blue); + text-align: center; + color: var(--white); +} + +.extension-requests-modal-parent { + display: none; +} +.extension-requests-modal-parent.visible { + z-index: 1; + position: fixed; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + min-width: 100vw; + min-height: 100vh; + background-color: #00000048; +} + +.extension-requests-modal-parent > * { + display: none; + flex-direction: column; + justify-content: center; + align-items: flex-start; + width: 40%; + height: 100%; + margin: 10px 0px; + background-color: var(--white); + padding: 20px; + border-radius: 5px; + min-width: 250px; +} + +#close-modal { + align-self: center; +} + +/* task info */ +.extension-requests-modal-parent[show='info'] .extension-requests-info { + display: flex; +} + +.extension-requests-info table { + text-align: left; + margin: 10px; + color: var(--black); + border-radius: 5px; +} + +.extension-requests-info button { + background-color: var(--button-proceed); + border: none; + color: var(--white); + padding: 8px 16px; + font-size: medium; + font-weight: bold; + border-radius: 5px; + margin: 10px; +} + +/* task info ends here */ + +/* status form */ +.extension-requests-modal-parent[show='status-form'] + .extension-requests-status-form { + display: flex; +} + +.extension-requests-status-form input, +.extension-requests-status-form select { + margin: 5px 0px 15px 0px; + padding: 5px; + width: 100%; + border: none; + border-bottom: 1px solid var(--gray); +} +.extension-requests-status-form input:focus { + outline: none; + border-bottom: 1px solid var(--gray); +} +.extension-requests-status-form button { + background-color: var(--button-proceed); + border: none; + color: var(--white); + padding: 8px 16px; + font-size: medium; + font-weight: bold; + border-radius: 5px; + margin: 10px; +} + +/* status form ends here */ + +.extension-requests { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(475px, 1fr)); + flex-wrap: wrap; +} + +.extension-request { + text-align: left; + border: 2px solid var(--black-transparent); + padding: 20px; + margin: 10px; + color: var(--black); + border-radius: 5px; +} + +.extension-request tr th { + width: 50%; +} + +.extension-request .more { + background-color: var(--button-proceed); + border: none; + color: var(--white); + width: 40%; + padding: 8px 16px; + font-size: medium; + font-weight: bold; + border-radius: 5px; + margin-top: 10px; +} + +/* Loader Container */ +.loader-text { + text-align: center; + font-size: 2rem; +} +.loader { + margin: auto auto; +} + +.loader p { + font-weight: 800; + font-size: 3em; +} + +/* Error Heading */ +.error { + display: none; +} +.error-visible { + display: block; +} diff --git a/utils.js b/utils.js index fe287218..fcd10ebe 100644 --- a/utils.js +++ b/utils.js @@ -14,3 +14,30 @@ async function checkUserIsSuperUser() { const self_user = await getSelfUser(); return self_user?.roles['super_user']; } + +function createElement({ type, attributes = {}, innerText }) { + const element = document.createElement(type); + Object.keys(attributes).forEach((item) => { + element.setAttribute(item, attributes[item]); + }); + element.textContent = innerText; + return element; +} + +function addLoader(container) { + const loader = createElement({ + type: 'div', + attributes: { class: 'loader' }, + }); + const loadertext = createElement({ + type: 'p', + attributes: { class: 'loader-text' }, + innerText: 'Loading...', + }); + loader.appendChild(loadertext); + container.appendChild(loader); +} + +function removeLoader() { + document.querySelector('.loader').remove(); +} From 896ccda07d072f0c94bb20c5a22593960eb9ad89 Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Wed, 1 Feb 2023 01:52:23 +0530 Subject: [PATCH 4/9] added feature --- extension-requests/index.html | 56 ++++++++++++++- extension-requests/local-utils.js | 21 ++++-- extension-requests/script.js | 109 ++++++++++++++++++++++++------ extension-requests/style.css | 36 +++++++++- 4 files changed, 194 insertions(+), 28 deletions(-) diff --git a/extension-requests/index.html b/extension-requests/index.html index f64bcd32..e2ceca7e 100644 --- a/extension-requests/index.html +++ b/extension-requests/index.html @@ -10,7 +10,61 @@
- +
+

Update Extension Request

+ + + + + + + + + + + + + + + + +

Update Extension Request Status

diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js index b0264636..9a75e3ec 100644 --- a/extension-requests/local-utils.js +++ b/extension-requests/local-utils.js @@ -16,12 +16,12 @@ async function getExtensionRequests(query = {}) { return await res.json(); } -async function createExtensionRequestStatus({ extensionRequest }) { - const url = `${API_BASE_URL}/extensionRequests`; +async function updateExtensionRequest({ id, body }) { + const url = `${API_BASE_URL}/extensionRequests/${id}`; const res = await fetch(url, { credentials: 'include', - method: 'POST', - body: JSON.stringify(extensionRequest), + method: 'PATCH', + body: JSON.stringify(body), headers: { 'Content-type': 'application/json', }, @@ -29,12 +29,12 @@ async function createExtensionRequestStatus({ extensionRequest }) { return await res.json(); } -async function updateExtensionRequestStatus({ id, status }) { +async function updateExtensionRequestStatus({ id, body }) { const url = `${API_BASE_URL}/extensionRequests/${id}/status`; const res = await fetch(url, { credentials: 'include', method: 'PATCH', - body: JSON.stringify({ status }), + body: JSON.stringify(body), headers: { 'Content-type': 'application/json', }, @@ -90,3 +90,12 @@ function createTable(headings, data, className = '') { main.appendChild(content); return main; } + +function formDataToObject(formData) { + if (!formData) return; + const result = {}; + for (let x of formData.keys()) { + result[x] = formData.get(x); + } + return result; +} diff --git a/extension-requests/script.js b/extension-requests/script.js index aa0eb759..726568d3 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -12,6 +12,7 @@ const modalShowInfo = document.querySelector('.extension-requests-info'); const modalStatusForm = document.querySelector( '.extension-requests-status-form', ); +const modalUpdateForm = document.querySelector('.extension-requests-form'); const state = { currentExtensionRequest: null, @@ -33,15 +34,14 @@ const render = async () => { removeLoader(); } }; - -const showTaskDetails = async (taskId) => { +const showTaskDetails = async (taskId, approved) => { if (!taskId) return; try { modalShowInfo.innerHTML = '

Task Details

'; addLoader(modalShowInfo); const taskDetails = await getTaskDetails(taskId); const taskData = taskDetails.taskData; - modalShowInfo.append(createTaskInfoModal(taskData)); + modalShowInfo.append(createTaskInfoModal(taskData, approved)); } catch (error) { errorHeading.textContent = 'Something went wrong'; errorHeading.classList.add('error-visible'); @@ -50,17 +50,7 @@ const showTaskDetails = async (taskId) => { removeLoader(); } }; - -function updateStatusForm() { - document.querySelector('.extensionId').value = - state.currentExtensionRequest.id; - document.querySelector('.extensionTitle').value = - state.currentExtensionRequest.title; - document.querySelector('.extensionAssignee').value = - state.currentExtensionRequest.assignee; -} - -function createTaskInfoModal(data) { +function createTaskInfoModal(data, approved) { if (!data) return; const dataHeadings = [ @@ -84,17 +74,16 @@ function createTaskInfoModal(data) { }); updateStatus.addEventListener('click', () => { showModal('status-form'); - updateStatusForm(); + fillStatusForm(); }); closeModal.addEventListener('click', () => hideModal()); const main = createTable(dataHeadings, data); - main.appendChild(updateStatus); + if (!approved) main.appendChild(updateStatus); main.appendChild(closeModal); return main; } - function createExtensionRequestCard(data) { if (!data) return; @@ -109,25 +98,77 @@ function createExtensionRequestCard(data) { { title: 'Task', key: 'taskId' }, ]; + const updateRequestBtn = createElement({ + type: 'button', + attributes: { class: 'update_request' }, + innerText: 'Update Request', + }); const moreInfoBtn = createElement({ type: 'button', attributes: { class: 'more' }, innerText: 'More', }); + updateRequestBtn.addEventListener('click', () => { + showModal('update-form'); + state.currentExtensionRequest = data; + fillUpdateForm(); + }); moreInfoBtn.addEventListener('click', () => { showModal('info'); - showTaskDetails(data.taskId); + showTaskDetails(data.taskId, data.status === 'APPROVED'); state.currentExtensionRequest = data; }); const main = createTable(dataHeadings, data, 'extension-request'); main.appendChild(moreInfoBtn); + main.appendChild(updateRequestBtn); return main; } - render(); +//API functions +async function onStatusFormSubmit(e) { + e.preventDefault(); + try { + addLoader(container); + let formData = formDataToObject(new FormData(e.target)); + await updateExtensionRequestStatus({ + id: state.currentExtensionRequest.id, + body: formData, + }); + reload(); + } catch (error) { + errorHeading.textContent = 'Something went wrong'; + errorHeading.classList.add('error-visible'); + reload(); + } finally { + removeLoader(); + } +} +async function onUpdateFormSubmit(e) { + e.preventDefault(); + try { + addLoader(container); + let formData = formDataToObject(new FormData(e.target)); + formData['newEndsOn'] = new Date(formData['newEndsOn']).getTime() / 1000; + await updateExtensionRequest({ + id: state.currentExtensionRequest.id, + body: formData, + }); + reload(); + } catch (error) { + errorHeading.textContent = 'Something went wrong'; + errorHeading.classList.add('error-visible'); + reload(); + } finally { + removeLoader(); + } +} + +modalUpdateForm.addEventListener('submit', onUpdateFormSubmit); +modalStatusForm.addEventListener('submit', onStatusFormSubmit); + modalParent.addEventListener('click', hideModal); closeModal.forEach((node) => node.addEventListener('click', () => hideModal())); @@ -148,3 +189,33 @@ function hideModal(e) { function reload() { setTimeout(() => window.history.go(0), 2000); } +function fillStatusForm() { + modalStatusForm.querySelector('.extensionId').value = + state.currentExtensionRequest.id; + modalStatusForm.querySelector('.extensionTitle').value = + state.currentExtensionRequest.title; + modalStatusForm.querySelector('.extensionAssignee').value = + state.currentExtensionRequest.assignee; +} +function fillUpdateForm() { + modalUpdateForm.querySelector('.extensionNewEndsOn').value = new Date( + state.currentExtensionRequest.newEndsOn * 1000, + ) + .toISOString() + .replace('Z', ''); + modalUpdateForm.querySelector('.extensionOldEndsOn').value = new Date( + state.currentExtensionRequest.oldEndsOn * 1000, + ) + .toISOString() + .replace('Z', ''); + modalUpdateForm.querySelector('.extensionStatus').value = + state.currentExtensionRequest.status; + modalUpdateForm.querySelector('.extensionId').value = + state.currentExtensionRequest.id; + modalUpdateForm.querySelector('.extensionTitle').value = + state.currentExtensionRequest.title; + modalUpdateForm.querySelector('.extensionAssignee').value = + state.currentExtensionRequest.assignee; + modalUpdateForm.querySelector('.extensionReason').value = + state.currentExtensionRequest.reason; +} diff --git a/extension-requests/style.css b/extension-requests/style.css index 14b9a60b..039c30ec 100644 --- a/extension-requests/style.css +++ b/extension-requests/style.css @@ -107,6 +107,36 @@ body { /* task info ends here */ +/* update form */ +.extension-requests-modal-parent[show='update-form'] .extension-requests-form { + display: flex; +} + +.extension-requests-form input, +.extension-requests-form select { + margin: 5px 0px 15px 0px; + padding: 5px; + width: 100%; + border: none; + border-bottom: 1px solid var(--gray); +} +.extension-requests-form input:focus { + outline: none; + border-bottom: 1px solid var(--gray); +} +.extension-requests-form button { + background-color: var(--button-proceed); + border: none; + color: var(--white); + padding: 8px 16px; + font-size: medium; + font-weight: bold; + border-radius: 5px; + margin: 10px; +} + +/* update form ends here */ + /* status form */ .extension-requests-modal-parent[show='status-form'] .extension-requests-status-form { @@ -157,16 +187,18 @@ body { width: 50%; } -.extension-request .more { +.extension-request .more, +.extension-request .update_request { background-color: var(--button-proceed); border: none; color: var(--white); width: 40%; + min-width: max-content; padding: 8px 16px; font-size: medium; font-weight: bold; border-radius: 5px; - margin-top: 10px; + margin: 10px 10px 0px 0px; } /* Loader Container */ From 3bb1d85e744529e7fac300f96e62f8329c8c6f89 Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Wed, 1 Feb 2023 01:57:17 +0530 Subject: [PATCH 5/9] . --- constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constants.js b/constants.js index 61341eac..94fd1b91 100644 --- a/constants.js +++ b/constants.js @@ -1,3 +1,3 @@ -const API_BASE_URL = 'http://localhost:3000'; +const API_BASE_URL = 'https://api.realdevsquad.com'; const USER_MANAGEMENT_LINK = 'user-management-link'; const EXTENSION_REQUESTS_LINK = 'extension-requests-link'; From ca2ca3c0b7c05de6e27c9c3ae4cfbbe2702e5d17 Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Tue, 21 Feb 2023 22:36:59 +0530 Subject: [PATCH 6/9] made suggested changes --- extension-requests/local-utils.js | 36 +++++++++++++++---------------- extension-requests/script.js | 2 +- extension-requests/style.css | 15 +++++++------ utils.js | 1 + 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/extension-requests/local-utils.js b/extension-requests/local-utils.js index 9a75e3ec..513555ad 100644 --- a/extension-requests/local-utils.js +++ b/extension-requests/local-utils.js @@ -1,10 +1,10 @@ async function getExtensionRequests(query = {}) { - const url = new URL(`${API_BASE_URL}/extensionRequests`); + const url = new URL(`${API_BASE_URL}/extension-requests`); - const { assignee, status, taskId } = query; - if (assignee) url.searchParams.set('assignee', assignee); - if (status) url.searchParams.set('status', status); - if (taskId) url.searchParams.set('taskId', taskId); + queryParams = ['assignee', 'status', 'taskId']; + queryParams.forEach( + (key) => query[key] && url.searchParams.set(key, query[key]), + ); const res = await fetch(url, { credentials: 'include', @@ -17,7 +17,7 @@ async function getExtensionRequests(query = {}) { } async function updateExtensionRequest({ id, body }) { - const url = `${API_BASE_URL}/extensionRequests/${id}`; + const url = `${API_BASE_URL}/extension-requests/${id}`; const res = await fetch(url, { credentials: 'include', method: 'PATCH', @@ -30,7 +30,7 @@ async function updateExtensionRequest({ id, body }) { } async function updateExtensionRequestStatus({ id, body }) { - const url = `${API_BASE_URL}/extensionRequests/${id}/status`; + const url = `${API_BASE_URL}/extension-requests/${id}/status`; const res = await fetch(url, { credentials: 'include', method: 'PATCH', @@ -60,42 +60,42 @@ function getTimeFromTimestamp(timestamp) { } function createTable(headings, data, className = '') { - const main = createElement({ + const table = createElement({ type: 'table', attributes: { class: className, }, }); - const content = createElement({ type: 'tbody' }); + const tableBody = createElement({ type: 'tbody' }); headings.forEach(({ title, key, time, bold }) => { let row = createElement({ type: 'tr' }); - let heading = createElement({ type: 'th', innerText: title }); + let rowHeading = createElement({ type: 'th', innerText: title }); let contentText = ''; if (time) contentText = getTimeFromTimestamp(data[key]); else contentText = key ? data[key] : data[title.toLowerCase()]; - let text = createElement({ + let tableData = createElement({ type: 'td', innerText: contentText, attributes: { class: bold ? 'bold' : '', }, }); - row.appendChild(heading); - row.appendChild(text); - content.appendChild(row); + row.appendChild(rowHeading); + row.appendChild(tableData); + tableBody.appendChild(row); }); - main.appendChild(content); - return main; + table.appendChild(tableBody); + return table; } function formDataToObject(formData) { if (!formData) return; const result = {}; - for (let x of formData.keys()) { - result[x] = formData.get(x); + for (const [key, value] of formData.entries()) { + result[key] = value; } return result; } diff --git a/extension-requests/script.js b/extension-requests/script.js index 726568d3..154faa1f 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -127,7 +127,7 @@ function createExtensionRequestCard(data) { } render(); -//API functions +//PATCH requests functions async function onStatusFormSubmit(e) { e.preventDefault(); try { diff --git a/extension-requests/style.css b/extension-requests/style.css index 039c30ec..9105d0f4 100644 --- a/extension-requests/style.css +++ b/extension-requests/style.css @@ -9,6 +9,7 @@ --razzmatazz: #df0057; --gray: #808080; --button-proceed: #008000; + --modal-color: #00000048; } *, @@ -61,7 +62,7 @@ body { align-items: center; min-width: 100vw; min-height: 100vh; - background-color: #00000048; + background-color: var(--modal-color); } .extension-requests-modal-parent > * { @@ -73,7 +74,7 @@ body { height: 100%; margin: 10px 0px; background-color: var(--white); - padding: 20px; + padding: 1.25rem; border-radius: 5px; min-width: 250px; } @@ -98,7 +99,7 @@ body { background-color: var(--button-proceed); border: none; color: var(--white); - padding: 8px 16px; + padding: 0.5rem 1rem; font-size: medium; font-weight: bold; border-radius: 5px; @@ -128,7 +129,7 @@ body { background-color: var(--button-proceed); border: none; color: var(--white); - padding: 8px 16px; + padding: 0.5rem 1rem; font-size: medium; font-weight: bold; border-radius: 5px; @@ -159,7 +160,7 @@ body { background-color: var(--button-proceed); border: none; color: var(--white); - padding: 8px 16px; + padding: 0.5rem 1rem; font-size: medium; font-weight: bold; border-radius: 5px; @@ -177,7 +178,7 @@ body { .extension-request { text-align: left; border: 2px solid var(--black-transparent); - padding: 20px; + padding: 1.25rem; margin: 10px; color: var(--black); border-radius: 5px; @@ -194,7 +195,7 @@ body { color: var(--white); width: 40%; min-width: max-content; - padding: 8px 16px; + padding: 0.5rem 1rem; font-size: medium; font-weight: bold; border-radius: 5px; diff --git a/utils.js b/utils.js index fcd10ebe..26b53963 100644 --- a/utils.js +++ b/utils.js @@ -25,6 +25,7 @@ function createElement({ type, attributes = {}, innerText }) { } function addLoader(container) { + if (!container) return; const loader = createElement({ type: 'div', attributes: { class: 'loader' }, From 304dfb91d85eb2c0f496a8347e2313ea6d0b7dc3 Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Sun, 12 Mar 2023 12:22:20 +0530 Subject: [PATCH 7/9] requested changes done --- extension-requests/constants.js | 19 ++++++++++ extension-requests/index.html | 1 + extension-requests/script.js | 63 ++++++++++++--------------------- utils.js | 4 +-- 4 files changed, 45 insertions(+), 42 deletions(-) create mode 100644 extension-requests/constants.js diff --git a/extension-requests/constants.js b/extension-requests/constants.js new file mode 100644 index 00000000..95f314f1 --- /dev/null +++ b/extension-requests/constants.js @@ -0,0 +1,19 @@ +const taskInfoModelHeadings = [ + { title: 'Title' }, + { title: 'Ends On', key: 'endsOn', time: true }, + { title: 'Purpose' }, + { title: 'Assignee' }, + { title: 'Created By', key: 'createdBy' }, + { title: 'Is Noteworthy', key: 'isNoteworthy' }, +]; + +const extensionRequestCardHeadings = [ + { title: 'Title' }, + { title: 'Reason' }, + { title: 'Old Ends On', key: 'oldEndsOn', time: true }, + { title: 'New Ends On', key: 'newEndsOn', time: true }, + { title: 'Status', bold: true }, + { title: 'Assignee' }, + { title: 'Created At', key: 'timestamp', time: true }, + { title: 'Task', key: 'taskId' }, +]; diff --git a/extension-requests/index.html b/extension-requests/index.html index e2ceca7e..9675032c 100644 --- a/extension-requests/index.html +++ b/extension-requests/index.html @@ -102,6 +102,7 @@

Extension Requests

+ diff --git a/extension-requests/script.js b/extension-requests/script.js index 154faa1f..b4ca3c4b 100644 --- a/extension-requests/script.js +++ b/extension-requests/script.js @@ -24,14 +24,16 @@ const render = async () => { const extensionRequests = await getExtensionRequests(); const allExtensionRequests = extensionRequests.allExtensionRequests; allExtensionRequests.forEach((data) => { - extensionRequestsContainer.appendChild(createExtensionRequestCard(data)); + extensionRequestsContainer.appendChild( + createExtensionRequestCard(data, extensionRequestCardHeadings), + ); }); } catch (error) { errorHeading.textContent = 'Something went wrong'; errorHeading.classList.add('error-visible'); reload(); } finally { - removeLoader(); + removeLoader('loader'); } }; const showTaskDetails = async (taskId, approved) => { @@ -41,27 +43,20 @@ const showTaskDetails = async (taskId, approved) => { addLoader(modalShowInfo); const taskDetails = await getTaskDetails(taskId); const taskData = taskDetails.taskData; - modalShowInfo.append(createTaskInfoModal(taskData, approved)); + modalShowInfo.append( + createTaskInfoModal(taskData, approved, taskInfoModelHeadings), + ); } catch (error) { errorHeading.textContent = 'Something went wrong'; errorHeading.classList.add('error-visible'); reload(); } finally { - removeLoader(); + removeLoader('loader'); } }; -function createTaskInfoModal(data, approved) { +function createTaskInfoModal(data, approved, dataHeadings) { if (!data) return; - const dataHeadings = [ - { title: 'Title' }, - { title: 'Ends On', key: 'endsOn', time: true }, - { title: 'Purpose' }, - { title: 'Assignee' }, - { title: 'Created By', key: 'createdBy' }, - { title: 'Is Noteworthy', key: 'isNoteworthy' }, - ]; - const updateStatus = createElement({ type: 'button', attributes: { class: 'status-form' }, @@ -84,20 +79,9 @@ function createTaskInfoModal(data, approved) { main.appendChild(closeModal); return main; } -function createExtensionRequestCard(data) { +function createExtensionRequestCard(data, dataHeadings) { if (!data) return; - const dataHeadings = [ - { title: 'Title' }, - { title: 'Reason' }, - { title: 'Old Ends On', key: 'oldEndsOn', time: true }, - { title: 'New Ends On', key: 'newEndsOn', time: true }, - { title: 'Status', bold: true }, - { title: 'Assignee' }, - { title: 'Created At', key: 'timestamp', time: true }, - { title: 'Task', key: 'taskId' }, - ]; - const updateRequestBtn = createElement({ type: 'button', attributes: { class: 'update_request' }, @@ -143,7 +127,7 @@ async function onStatusFormSubmit(e) { errorHeading.classList.add('error-visible'); reload(); } finally { - removeLoader(); + removeLoader('loader'); } } async function onUpdateFormSubmit(e) { @@ -162,7 +146,7 @@ async function onUpdateFormSubmit(e) { errorHeading.classList.add('error-visible'); reload(); } finally { - removeLoader(); + removeLoader('loader'); } } @@ -198,24 +182,23 @@ function fillStatusForm() { state.currentExtensionRequest.assignee; } function fillUpdateForm() { + const { newEndsOn, oldEndsOn, status, id, title, assignee, reason } = + state.currentExtensionRequest; + modalUpdateForm.querySelector('.extensionNewEndsOn').value = new Date( - state.currentExtensionRequest.newEndsOn * 1000, + newEndsOn * 1000, ) .toISOString() .replace('Z', ''); modalUpdateForm.querySelector('.extensionOldEndsOn').value = new Date( - state.currentExtensionRequest.oldEndsOn * 1000, + oldEndsOn * 1000, ) .toISOString() .replace('Z', ''); - modalUpdateForm.querySelector('.extensionStatus').value = - state.currentExtensionRequest.status; - modalUpdateForm.querySelector('.extensionId').value = - state.currentExtensionRequest.id; - modalUpdateForm.querySelector('.extensionTitle').value = - state.currentExtensionRequest.title; - modalUpdateForm.querySelector('.extensionAssignee').value = - state.currentExtensionRequest.assignee; - modalUpdateForm.querySelector('.extensionReason').value = - state.currentExtensionRequest.reason; + + modalUpdateForm.querySelector('.extensionStatus').value = status; + modalUpdateForm.querySelector('.extensionId').value = id; + modalUpdateForm.querySelector('.extensionTitle').value = title; + modalUpdateForm.querySelector('.extensionAssignee').value = assignee; + modalUpdateForm.querySelector('.extensionReason').value = reason; } diff --git a/utils.js b/utils.js index cb8cea2e..b7bf4176 100644 --- a/utils.js +++ b/utils.js @@ -43,6 +43,6 @@ function addLoader(container) { container.appendChild(loader); } -function removeLoader() { - document.querySelector('.loader').remove(); +function removeLoader(classname) { + document.querySelector(`.${classname}`).remove(); } From 0a88fea41b301354bfb73f5aa7498cb8f77ada6a Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Tue, 11 Apr 2023 23:05:29 +0530 Subject: [PATCH 8/9] fix formatting --- script.js | 2 -- style.css | 1 - 2 files changed, 3 deletions(-) diff --git a/script.js b/script.js index 7396dee4..b5316022 100644 --- a/script.js +++ b/script.js @@ -14,7 +14,6 @@ export async function showSuperUserOptions(...privateBtns) { } } - /* * To show the super user options only to the super user, give all those * buttons or node the class "element-display-remove" so by default they are hidden. @@ -30,4 +29,3 @@ if (params.get('dev') === 'true') { } showUserManagementButton(); - diff --git a/style.css b/style.css index 7bbcee19..36181d15 100644 --- a/style.css +++ b/style.css @@ -144,7 +144,6 @@ button { border-color: transparent; } - /* Online-members */ .info-repo { font-weight: 100; From 8b5173b5a81e0205a18f0a09138be6dc735f2db4 Mon Sep 17 00:00:00 2001 From: ivinayakg Date: Tue, 25 Apr 2023 23:59:16 +0530 Subject: [PATCH 9/9] added responsiveness --- extension-requests/style.css | 44 ++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/extension-requests/style.css b/extension-requests/style.css index 9105d0f4..5f05634e 100644 --- a/extension-requests/style.css +++ b/extension-requests/style.css @@ -63,6 +63,8 @@ body { min-width: 100vw; min-height: 100vh; background-color: var(--modal-color); + overflow-y: scroll; + padding-bottom: 1rem; } .extension-requests-modal-parent > * { @@ -70,9 +72,6 @@ body { flex-direction: column; justify-content: center; align-items: flex-start; - width: 40%; - height: 100%; - margin: 10px 0px; background-color: var(--white); padding: 1.25rem; border-radius: 5px; @@ -88,6 +87,13 @@ body { display: flex; } +.extension-requests-info { + position: absolute; + left: 30%; + right: 30%; + height: fit-content; +} + .extension-requests-info table { text-align: left; margin: 10px; @@ -113,6 +119,16 @@ body { display: flex; } +.extension-requests-form { + position: absolute; + left: 30%; + right: 30%; + height: min-content; + overflow-y: scroll; + top: 10%; + bottom: 10%; +} + .extension-requests-form input, .extension-requests-form select { margin: 5px 0px 15px 0px; @@ -171,7 +187,7 @@ body { .extension-requests { display: grid; - grid-template-columns: repeat(auto-fill, minmax(475px, 1fr)); + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); flex-wrap: wrap; } @@ -223,3 +239,23 @@ body { .error-visible { display: block; } + +@media screen and (max-width: 800px) { + .extension-request { + margin: 0; + padding: 0.8rem; + } + + .extension-request > tr > th { + max-width: fit-content; + } + + .extension-requests-info { + left: 10%; + right: 10%; + } + .extension-requests-form { + left: 10%; + right: 10%; + } +}