diff --git a/__tests__/task-requests/task-requestDetails.test.js b/__tests__/task-requests/task-requestDetails.test.js
index 88be744e..beba12b7 100644
--- a/__tests__/task-requests/task-requestDetails.test.js
+++ b/__tests__/task-requests/task-requestDetails.test.js
@@ -3,6 +3,67 @@ const {
urlMappings,
defaultMockResponseHeaders,
} = require('../../mock-data/taskRequests');
+const { user } = require('../../mock-data/users/index.js');
+
+describe('Request container for non-super users', () => {
+ let browser;
+ let page;
+ jest.setTimeout(60000);
+
+ beforeAll(async () => {
+ browser = await puppeteer.launch({
+ headless: 'new',
+ ignoreHTTPSErrors: true,
+ args: ['--incognito', '--disable-web-security'],
+ devtools: false,
+ });
+ page = await browser.newPage();
+ await page.setRequestInterception(true);
+ page.on('request', (interceptedRequest) => {
+ const url = interceptedRequest.url();
+ if (url == 'https://staging-api.realdevsquad.com/users/self') {
+ interceptedRequest.respond({
+ ...defaultMockResponseHeaders,
+ body: JSON.stringify(user),
+ });
+ } else if (urlMappings.hasOwnProperty(url)) {
+ interceptedRequest.respond({
+ ...defaultMockResponseHeaders,
+ body: JSON.stringify(urlMappings[url]),
+ });
+ } else {
+ interceptedRequest.continue();
+ }
+ });
+ await page.goto(
+ 'http://localhost:8000/task-requests/details/?id=dM5wwD9QsiTzi7eG7Oq5',
+ );
+ });
+
+ afterAll(async () => {
+ await browser.close();
+ });
+
+ it('Approve and Reject buttons should not render for non-super users', async function () {
+ await page.goto(
+ 'http://localhost:8000/task-requests/details/?id=dM5wwD9QsiTzi7eG7Oq5&&dev=true',
+ );
+ const approveButton = await page.$('[data-testid="task-approve-button"]');
+ const rejectButton = await page.$('[data-testid="task-reject-button"]');
+ expect(approveButton).toBeNull();
+ expect(rejectButton).toBeNull();
+ });
+
+ it('Should render task status for non-super users', async function () {
+ await page.goto(
+ 'http://localhost:8000/task-requests/details/?id=dM5wwD9QsiTzi7eG7Oq5&&dev=true',
+ );
+ const taskRequestStatus = await page.$(
+ '[data-testid="requestors-task-status"]',
+ );
+ expect(taskRequestStatus).toBeTruthy();
+ });
+});
describe('Task request details page', () => {
let browser;
@@ -89,9 +150,12 @@ describe('Task request details page', () => {
);
});
- it('Should contain Approve and Reject buttons', async function () {
- const approveButton = await page.$('.requestors__conatainer__list__button');
- const rejectButton = await page.$('.request-details__reject__button');
+ it('Should render Approve and Reject buttons for super users', async function () {
+ await page.goto(
+ 'http://localhost:8000/task-requests/details/?id=dM5wwD9QsiTzi7eG7Oq5&&dev=true',
+ );
+ const approveButton = await page.$('[data-testid="task-approve-button"]');
+ const rejectButton = await page.$('[data-testid="task-reject-button"]');
expect(approveButton).toBeTruthy();
expect(rejectButton).toBeTruthy();
});
@@ -180,9 +244,12 @@ describe('Task request details page with markdown support in description', () =>
expect(descriptionHtmlValue).toContain('
Heading
');
});
- it('Should contain Approve and Reject buttons', async function () {
- const approveButton = await page.$('.requestors__conatainer__list__button');
- const rejectButton = await page.$('.request-details__reject__button');
+ it('Should render Approve and Reject buttons for super users', async function () {
+ await page.goto(
+ 'http://localhost:8000/task-requests/details/?id=dM5wwD9QsiTzi7eG7Oq5&&dev=true',
+ );
+ const approveButton = await page.$('[data-testid="task-approve-button"]');
+ const rejectButton = await page.$('[data-testid="task-reject-button"]');
expect(approveButton).toBeTruthy();
expect(rejectButton).toBeTruthy();
});
diff --git a/mock-data/taskRequests/index.js b/mock-data/taskRequests/index.js
index 3b5d184d..c17e92ca 100644
--- a/mock-data/taskRequests/index.js
+++ b/mock-data/taskRequests/index.js
@@ -1,3 +1,5 @@
+const { superUserDetails } = require('../users/mockdata.js');
+
const fetchedTaskRequests = [
{
id: '123CCXSDF123',
@@ -260,7 +262,6 @@ const githubIssue = {
performed_via_github_app: null,
state_reason: 'completed',
};
-
const individualTaskDetail = {
message: 'task returned successfully',
taskData: {
@@ -306,7 +307,6 @@ const userInformationTaskCreation = {
},
},
};
-
const userInformation = {
message: 'User returned successfully!',
user: {
@@ -351,6 +351,7 @@ const defaultMockResponseHeaders = {
};
const urlMappings = {
+ 'https://staging-api.realdevsquad.com/users/self': superUserDetails.user,
'https://api.realdevsquad.com/taskRequests/dM5wwD9QsiTzi7eG7Oq5':
individualTaskReqDetail,
'https://api.realdevsquad.com/taskRequests/dM5wwD9QsiTzi7eG7Oq6':
diff --git a/task-requests/details/index.html b/task-requests/details/index.html
index 5dc02fbb..7543e635 100644
--- a/task-requests/details/index.html
+++ b/task-requests/details/index.html
@@ -24,13 +24,13 @@
crossorigin="anonymous"
referrerpolicy="no-referrer"
>
-
+
-
-
-
diff --git a/task-requests/details/script.js b/task-requests/details/script.js
index acab0c50..757c0697 100644
--- a/task-requests/details/script.js
+++ b/task-requests/details/script.js
@@ -2,8 +2,9 @@ const API_BASE_URL =
window.location.hostname === 'localhost'
? 'https://staging-api.realdevsquad.com'
: window.API_BASE_URL;
-
+import { getIsSuperUser } from '../../applications/utils.js';
let taskRequest;
+let isSuperUser;
const taskRequestSkeleton = document.querySelector('.taskRequest__skeleton');
const container = document.querySelector('.container');
@@ -11,17 +12,18 @@ const taskSkeleton = document.querySelector('.task__skeleton');
const requestorSkeleton = document.querySelector(
'.requestors__container__list__skeleton',
);
-
const taskRequestContainer = document.getElementById('task-request-details');
+const requestDetailContainer =
+ document.getElementsByClassName('request-details');
const taskContainer = document.getElementById('task-details');
const toast = document.getElementById('toast_task_details');
-const rejectButton = document.getElementById('reject-button');
const requestorsContainer = document.getElementById('requestors-details');
const taskRequestId = new URLSearchParams(window.location.search).get('id');
history.pushState({}, '', window.location.href);
const errorMessage =
'The requested operation could not be completed. Please try again later.';
-let taskId;
+const params = new URLSearchParams(window.location.search);
+const isDev = params.get('dev') === 'true';
function renderTaskRequestDetails(taskRequest) {
taskRequestContainer.append(
@@ -200,30 +202,65 @@ async function updateTaskRequest(action, userId) {
}
}
-function getActionButton(requestor) {
- if (taskRequest?.status === taskRequestStatus.APPROVED) {
- if (taskRequest.approvedTo === requestor?.user?.id) {
+function renderActionButton(requestor, taskRequest) {
+ if (isDev) {
+ if (isSuperUser) {
+ if (taskRequest?.status === taskRequestStatus.APPROVED) {
+ return taskRequest.approvedTo === requestor?.user?.id
+ ? createCustomElement({
+ tagName: 'p',
+ textContent: 'Approved',
+ class: ['requestors__container__list__status'],
+ })
+ : '';
+ }
return createCustomElement({
- tagName: 'p',
- textContent: 'Approved',
- class: ['requestors__container__list__approved'],
+ tagName: 'button',
+ textContent: 'Approve',
+ class: 'requestors__conatainer__list__button',
+ 'data-testid': 'task-approve-button',
+ eventListeners: [
+ {
+ event: 'click',
+ func: () =>
+ updateTaskRequest(TaskRequestAction.APPROVE, requestor.user?.id),
+ },
+ ],
});
- } else {
- return '';
}
+ return createCustomElement({
+ tagName: 'p',
+ textContent:
+ taskRequest.status[0].toUpperCase() +
+ taskRequest.status.slice(1).toLowerCase(),
+ class: ['requestors__container__list__status'],
+ 'data-testid': 'requestors-task-status',
+ });
+ } else {
+ if (taskRequest?.status === taskRequestStatus.APPROVED) {
+ if (taskRequest.approvedTo === requestor?.user?.id) {
+ return createCustomElement({
+ tagName: 'p',
+ textContent: 'Approved',
+ class: ['requestors__container__list__status'],
+ });
+ } else {
+ return '';
+ }
+ }
+ return createCustomElement({
+ tagName: 'button',
+ textContent: 'Approve',
+ class: 'requestors__conatainer__list__button',
+ eventListeners: [
+ {
+ event: 'click',
+ func: () =>
+ updateTaskRequest(TaskRequestAction.APPROVE, requestor.user?.id),
+ },
+ ],
+ });
}
- return createCustomElement({
- tagName: 'button',
- textContent: 'Approve',
- class: 'requestors__conatainer__list__button',
- eventListeners: [
- {
- event: 'click',
- func: () =>
- updateTaskRequest(TaskRequestAction.APPROVE, requestor.user?.id),
- },
- ],
- });
}
async function renderRequestors(taskRequest) {
@@ -279,14 +316,22 @@ async function renderRequestors(taskRequest) {
createCustomElement({
tagName: 'div',
child: [
- taskRequest.status !== 'DENIED' ? getActionButton(requestor) : '',
+ isDev
+ ? taskRequest.status !== 'DENIED'
+ ? renderActionButton(requestor, taskRequest)
+ : createCustomElement({
+ tagName: 'p',
+ textContent: 'Denied',
+ class: ['requestors__container__list__status'],
+ 'data-testid': 'requestor-container-task-status',
+ })
+ : taskRequest.status !== 'DENIED'
+ ? renderActionButton(requestor, taskRequest)
+ : '',
],
}),
],
});
- const avatarDiv = userDetailsDiv.querySelector(
- '.requestors__container__list__userDetails__avatar',
- );
requestorsContainer.append(userDetailsDiv);
});
}
@@ -305,7 +350,7 @@ async function fetchTaskRequest() {
}
const renderGithubIssue = async () => {
- converter = new showdown.Converter({
+ const converter = new showdown.Converter({
tables: true,
simplifiedAutoLink: true,
tasklists: true,
@@ -344,7 +389,7 @@ const renderGithubIssue = async () => {
}),
);
const body = DOMPurify.sanitize(res?.body ?? '');
- html = converter.makeHtml(body);
+ const html = converter.makeHtml(body);
taskContainer.appendChild(
createCustomElement({
tagName: 'div',
@@ -410,22 +455,82 @@ const renderGithubIssue = async () => {
);
};
const renderRejectButton = (taskRequest) => {
- if (taskRequest?.status !== 'PENDING') {
- rejectButton.disabled = true;
- }
+ if (isDev) {
+ if (!isSuperUser) return;
+ if (taskRequest?.status === 'PENDING') {
+ const rejectContainer = createCustomElement({
+ tagName: 'div',
+ class: 'reject__container',
+ child: [
+ createCustomElement({
+ tagName: 'button',
+ textContent: 'Reject',
+ id: 'reject-button',
+ class: 'request-details__reject__button',
+ 'data-testid': 'task-reject-button',
+ }),
+ ],
+ });
+
+ requestDetailContainer[0].appendChild(rejectContainer);
+ const rejectButton = rejectContainer.querySelector('#reject-button');
+
+ rejectButton.addEventListener('click', async () => {
+ const res = await updateTaskRequest(TaskRequestAction.REJECT);
+ if (res?.ok) {
+ rejectButton.remove();
+ }
+ });
+ } else {
+ const existingRejectContainer =
+ document.querySelector('.reject__container');
+ if (existingRejectContainer) {
+ const rejectButton =
+ existingRejectContainer.querySelector('#reject-button');
+ if (rejectButton) {
+ rejectButton.remove();
+ }
+ }
+ }
+ } else {
+ const rejectContainer = document.querySelector('.reject__container');
+ if (!rejectContainer) {
+ const rejectContainer = createCustomElement({
+ tagName: 'div',
+ class: 'reject__container',
+ child: [
+ createCustomElement({
+ tagName: 'button',
+ textContent: 'Reject',
+ id: 'reject-button',
+ class: 'request-details__reject__button',
+ 'data-testid': 'task-reject-button',
+ }),
+ ],
+ });
- rejectButton.addEventListener('click', async () => {
- const res = await updateTaskRequest(TaskRequestAction.REJECT);
- if (res?.ok) {
+ requestDetailContainer[0].appendChild(rejectContainer);
+ }
+ const rejectButton = document.querySelector('#reject-button');
+ if (taskRequest?.status !== 'PENDING') {
rejectButton.disabled = true;
}
- });
+
+ rejectButton.addEventListener('click', async () => {
+ const res = await updateTaskRequest(TaskRequestAction.REJECT);
+ if (res?.ok) {
+ rejectButton.disabled = true;
+ }
+ });
+ }
};
+
const renderTaskRequest = async () => {
taskRequestSkeleton.classList.remove('hidden');
taskContainer.classList.remove('hidden');
try {
taskRequest = await fetchTaskRequest();
+ isSuperUser = await getIsSuperUser();
taskRequestSkeleton.classList.add('hidden');
renderRejectButton(taskRequest);
renderTaskRequestDetails(taskRequest);
@@ -568,7 +673,7 @@ function populateModalContent(index) {
);
if (userData?.markdownEnabled ?? false) {
- converter = new showdown.Converter({
+ const converter = new showdown.Converter({
tables: true,
simplifiedAutoLink: true,
tasklists: true,
@@ -577,7 +682,7 @@ function populateModalContent(index) {
openLinksInNewWindow: true,
});
const sanitizedDescription = DOMPurify.sanitize(userData.description ?? '');
- html = converter.makeHtml(sanitizedDescription);
+ const html = converter.makeHtml(sanitizedDescription);
descriptionValue.innerHTML = html;
descriptionValue.className = 'requestor_description_details';
} else {
diff --git a/task-requests/details/style.css b/task-requests/details/style.css
index 6083751f..f5ddd3a2 100644
--- a/task-requests/details/style.css
+++ b/task-requests/details/style.css
@@ -248,7 +248,7 @@ body {
background: #19805e;
transition: 0.3s ease-in-out;
}
-.requestors__container__list__approved {
+.requestors__container__list__status {
background: transparent;
border: none;
color: #c3c3c3;
diff --git a/task-requests/util.js b/task-requests/util.js
index ad50c912..d13fb0b9 100644
--- a/task-requests/util.js
+++ b/task-requests/util.js
@@ -17,6 +17,8 @@ function createCustomElement(domObjectMap) {
}
} else if (key === 'child') {
el.append(...value);
+ } else if (key.startsWith('data-')) {
+ el.setAttribute(key, value);
} else {
el[key] = value;
}