Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: overdue tasks #419

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules/
coverage/
coverage/
.vscode
1 change: 1 addition & 0 deletions constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const REPO_SYNC_API_URL =
'https://staging-sync.staging-realdevsquad-com.workers.dev';
const USER_MANAGEMENT_LINK = 'user-management-link';
const EXTENSION_REQUESTS_LINK = 'extension-requests-link';
const OVERDUE_TASKS_LINK = 'overdue-tasks-link';
const SYNC_USERS_STATUS = 'sync-users-status';
const SYNC_EXTERNAL_ACCOUNTS = 'sync-external-accounts';
const SYNC_UNVERIFIED_USERS = 'sync-unverified-users';
Expand Down
1 change: 1 addition & 0 deletions extension-requests/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ function fillUpdateForm() {
)
.toISOString()
.replace('Z', '');

modalUpdateForm.querySelector('.extensionOldEndsOn').value = new Date(
oldEndsOn * 1000,
)
Expand Down
7 changes: 7 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@
>
Extension Requests
</a>
<a
id="overdue-tasks-link"
class="element-display-remove"
href="overdue-tasks"
>
Overdue Tasks
</a>
<a href="/online-members/online-members.html" class="action-button">
Online Members
</a>
Expand Down
19 changes: 19 additions & 0 deletions overdue-tasks/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const taskInfoModelHeadings = [
{ title: 'Title' },
{ title: 'Overdue From', 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' },
];
96 changes: 96 additions & 0 deletions overdue-tasks/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Overdue Tasks</title>
</head>

<body>
<div state="" class="overdue-tasks-modal-parent">
<div class="overdue-tasks-prompt">
<h2>Prompt Heading</h2>
<button class="prompt_success">Continue</button>
<button class="prompt_failure">Cancel</button>
</div>
<form class="extension-requests-form">
<h3>Create Extension Request</h3>
<label for="title">Title</label>
<input
required
type="text"
id="title"
name="title"
class="extensionTitle"
/>
<label for="reason">Reason</label>
<input
required
type="text"
id="reason"
name="reason"
class="extensionReason"
/>
<label for="newEndsOn">New Ends On</label>
<input
required
type="datetime-local"
id="newEndsOn"
name="newEndsOn"
class="extensionNewEndsOn"
/>
<label for="oldEndsOn">Old Ends On</label>
<input
required
type="datetime-local"
id="oldEndsOn"
class="extensionOldEndsOn"
name="oldEndsOn"
readonly
/>
<label for="status">Status</label>
<input
required
type="text"
id="status"
class="extensionStatus"
name="status"
readonly
/>
<label for="Task Id">Task Id</label>
<input
required
type="text"
id="Task Id"
class="extensionId"
readonly
name="taskId"
/>
<label for="assignee">Assignee</label>
<input
required
type="text"
id="assignee"
class="extensionAssignee"
readonly
name="assignee"
/>
<button type="submit">Submit</button>
<button id="close-modal" type="button">Cancel</button>
</form>
</div>
<header class="header">
<h1>Overdue Tasks</h1>
</header>
<div class="container">
<div class="overdue-tasks"></div>
</div>
<h2 id="error"></h2>
<script src="/constants.js"></script>
<script src="constants.js"></script>
<script src="/utils.js"></script>
<script src="local-utils.js"></script>
<script src="script.js"></script>
</body>
</html>
115 changes: 115 additions & 0 deletions overdue-tasks/local-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
async function getCurrentOverdueTasks(query = {}) {
const url = new URL(`${API_BASE_URL}/tasks?dev=true&status=overdue`);

const res = await fetch(url, {
credentials: 'include',
method: 'GET',
headers: {
'Content-type': 'application/json',
},
});
return await res.json();
}

async function getExtensionRequests(query = {}) {
const url = new URL(`${API_BASE_URL}/extension-requests`);

queryParams = ['assignee', 'status', 'taskId'];
queryParams.forEach(
(key) => query[key] && url.searchParams.set(key, query[key]),
);

const res = await fetch(url, {
credentials: 'include',
method: 'GET',
headers: {
'Content-type': 'application/json',
},
});
return await res.json();
}

async function createExtensionRequest(extensionObject) {
const url = `${API_BASE_URL}/extension-requests/`;
const res = await fetch(url, {
credentials: 'include',
method: 'POST',
body: JSON.stringify(extensionObject),
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();
}

async function unassignTask(taskId) {
if (!taskId) return;
const url = `${API_BASE_URL}/tasks/${taskId}/`;
const res = await fetch(url, {
credentials: 'include',
method: 'PATCH',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({ assignee: null, status: 'AVAILABLE', endsOn: 0 }),
});
return res.status === 204;
}

function getTimeFromTimestamp(timestamp) {
return new Date(timestamp * 1000).toLocaleString();
}

function createTable(headings, data, className = '') {
const table = createElement({
type: 'table',
attributes: {
class: className,
},
});
const tableBody = createElement({ type: 'tbody' });
headings.forEach(({ title, key, time, bold }) => {
let row = createElement({ type: 'tr' });
let rowHeading = createElement({ type: 'th', innerText: title });

let contentText = '';
if (time) contentText = getTimeFromTimestamp(data[key]);
else contentText = key ? data[key] : data[title.toLowerCase()];

let tableData = createElement({
type: 'td',
innerText: contentText,
attributes: {
class: bold ? 'bold' : '',
},
});
row.appendChild(rowHeading);
row.appendChild(tableData);
tableBody.appendChild(row);
});

table.appendChild(tableBody);
return table;
}

function formDataToObject(formData) {
if (!formData) return;
const result = {};
for (const [key, value] of formData.entries()) {
result[key] = value;
}
return result;
}
Loading
Loading