Forked from
Åsmund Haugse / tdt4242-base
29 commits behind, 37 commits ahead of the upstream repository.
-
Pernille Nødtvedt Welle-Watne authoredPernille Nødtvedt Welle-Watne authored
workout.js 16.67 KiB
let cancelWorkoutButton;
let okWorkoutButton;
let deleteWorkoutButton;
let editWorkoutButton;
let exportWorkoutButton;
let postCommentButton;
async function retrieveWorkout(id) {
let workoutData = null;
let response = await sendRequest("GET", `${HOST}/api/workouts/${id}/`);
if (!response.ok) {
let data = await response.json();
let alert = createAlert("Could not retrieve workout data!", data);
document.body.prepend(alert);
} else {
workoutData = await response.json();
let form = document.querySelector("#form-workout");
let formData = new FormData(form);
for (let key of formData.keys()) {
let selector = `input[name="${key}"], textarea[name="${key}"]`;
let input = form.querySelector(selector);
let newVal = workoutData[key];
if (key == "date") {
// Creating a valid datetime-local string with the correct local time
let date = new Date(newVal);
date = new Date(date.getTime() - (date.getTimezoneOffset() * 60 * 1000)).toISOString(); // get ISO format for local time
newVal = date.substring(0, newVal.length - 1); // remove Z (since this is a local time, not UTC)
}
if (key != "files") {
input.value = newVal;
}
}
let input = form.querySelector("select:disabled");
input.value = workoutData["visibility"];
// files
let filesDiv = document.querySelector("#uploaded-files");
for (let file of workoutData.files) {
let a = document.createElement("a");
a.href = file.file;
let pathArray = file.file.split("/");
a.text = pathArray[pathArray.length - 1];
a.className = "me-2";
filesDiv.appendChild(a);
}
// create exercises
// fetch exercise types
let exerciseTypeResponse = await sendRequest("GET", `${HOST}/api/exercises/`);
let exerciseTypes = await exerciseTypeResponse.json();
//TODO: This should be in its own method.
for (let i = 0; i < workoutData.exercise_instances.length; i++) {
let templateExercise = document.querySelector("#template-exercise");
let divExerciseContainer = templateExercise.content.firstElementChild.cloneNode(true);
let exerciseTypeLabel = divExerciseContainer.querySelector('.exercise-type');
exerciseTypeLabel.for = `inputExerciseType${i}`;
let exerciseTypeSelect = divExerciseContainer.querySelector("select");
exerciseTypeSelect.id = `inputExerciseType${i}`;
exerciseTypeSelect.disabled = true;
let splitUrl = workoutData.exercise_instances[i].exercise.split("/");
let currentExerciseTypeId = splitUrl[splitUrl.length - 2];
let currentExerciseType = "";
for (let j = 0; j < exerciseTypes.count; j++) {
let option = document.createElement("option");
option.value = exerciseTypes.results[j].id;
if (currentExerciseTypeId == exerciseTypes.results[j].id) {
currentExerciseType = exerciseTypes.results[j];
}
option.innerText = exerciseTypes.results[j].name;
exerciseTypeSelect.append(option);
}
exerciseTypeSelect.value = currentExerciseType.id;
let exerciseSetLabel = divExerciseContainer.querySelector('.exercise-sets');
exerciseSetLabel.for = `inputSets${i}`;
let exerciseSetInput = divExerciseContainer.querySelector("input[name='sets']");
exerciseSetInput.id = `inputSets${i}`;
exerciseSetInput.value = workoutData.exercise_instances[i].sets;
exerciseSetInput.readOnly = true;
let exerciseNumberLabel = divExerciseContainer.querySelector('.exercise-number');
exerciseNumberLabel.for = "for", `inputNumber${i}`;
exerciseNumberLabel.innerText = currentExerciseType.unit;
let exerciseNumberInput = divExerciseContainer.querySelector("input[name='number']");
exerciseNumberInput.id = `inputNumber${i}`;
exerciseNumberInput.value = workoutData.exercise_instances[i].number;
exerciseNumberInput.readOnly = true;
let exercisesDiv = document.querySelector("#div-exercises");
exercisesDiv.appendChild(divExerciseContainer);
}
}
return workoutData;
}
function handleCancelDuringWorkoutEdit() {
location.reload();
}
function handleEditWorkoutButtonClick() {
let addExerciseButton = document.querySelector("#btn-add-exercise");
let removeExerciseButton = document.querySelector("#btn-remove-exercise");
setReadOnly(false, "#form-workout");
document.querySelector("#inputOwner").readOnly = true; // owner field should still be readonly
editWorkoutButton.className += " hide";
exportWorkoutButton.className += " hide";
okWorkoutButton.className = okWorkoutButton.className.replace(" hide", "");
cancelWorkoutButton.className = cancelWorkoutButton.className.replace(" hide", "");
deleteWorkoutButton.className = deleteWorkoutButton.className.replace(" hide", "");
addExerciseButton.className = addExerciseButton.className.replace(" hide", "");
removeExerciseButton.className = removeExerciseButton.className.replace(" hide", "");
cancelWorkoutButton.addEventListener("click", handleCancelDuringWorkoutEdit);
}
//Taken from github: https://gist.github.com/dannypule/48418b4cd8223104c6c92e3016fc0f61
function handleExportToCalendarClick(workoutData) {
const headers = {
subject: "Subject",
startDate: "Start date",
startTime: "Start time",
description: "Description"
}
const dataFormatted = []
const startTime = new Date(workoutData.date).toLocaleTimeString("en-us")
const startDate = new Date(workoutData.date).toLocaleString('en-us', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}).replace(/(\d+)\/(\d+)\/(\d+)/, '$1/$2/$3')
dataFormatted.push({
subject: workoutData.name,
startDate: startDate,
startTime: startTime,
description: workoutData.notes
})
console.log(dataFormatted)
exportCSVFile(headers, dataFormatted, "event")
}
//Taken from github: https://gist.github.com/dannypule/48418b4cd8223104c6c92e3016fc0f61
function convertToCSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
for (var i = 0; i < array.length; i++) {
var line = '';
for (var index in array[i]) {
if (line != '') line += ','
line += array[i][index];
}
str += line + '\r\n';
}
return str;
}
//Taken from github: https://gist.github.com/dannypule/48418b4cd8223104c6c92e3016fc0f61
function exportCSVFile(headers, items, fileTitle) {
console.log(items, headers)
if (headers) {
items.unshift(headers);
}
// Convert Object to JSON
var jsonObject = JSON.stringify(items);
var csv = this.convertToCSV(jsonObject);
var exportedFilenmae = fileTitle + '.csv' || 'export.csv';
var blob = new Blob([csv], {type: 'text/csv;charset=utf-8;'});
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, exportedFilenmae);
} else {
var link = document.createElement("a");
if (link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", exportedFilenmae);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
async function deleteWorkout(id) {
let response = await sendRequest("DELETE", `${HOST}/api/workouts/${id}/`);
if (!response.ok) {
let data = await response.json();
let alert = createAlert(`Could not delete workout ${id}!`, data);
document.body.prepend(alert);
} else {
window.location.replace("workouts.html");
}
}
async function updateWorkout(id) {
let submitForm = generateWorkoutForm();
let response = await sendRequest("PUT", `${HOST}/api/workouts/${id}/`, submitForm, "");
if (!response.ok) {
let data = await response.json();
let alert = createAlert("Could not update workout!", data);
document.body.prepend(alert);
} else {
location.reload();
}
}
function generateWorkoutForm() {
let form = document.querySelector("#form-workout");
let formData = new FormData(form);
let submitForm = new FormData();
submitForm.append("name", formData.get('name'));
let date = new Date(formData.get('date')).toISOString();
submitForm.append("date", date);
submitForm.append("notes", formData.get("notes"));
submitForm.append("visibility", formData.get("visibility"));
// adding exercise instances
let exerciseInstances = [];
let exerciseInstancesTypes = formData.getAll("type");
let exerciseInstancesSets = formData.getAll("sets");
let exerciseInstancesNumbers = formData.getAll("number");
for (let i = 0; i < exerciseInstancesTypes.length; i++) {
exerciseInstances.push({
exercise: `${HOST}/api/exercises/${exerciseInstancesTypes[i]}/`,
number: exerciseInstancesNumbers[i],
sets: exerciseInstancesSets[i]
});
}
submitForm.append("exercise_instances", JSON.stringify(exerciseInstances));
// adding files
for (let file of formData.getAll("files")) {
submitForm.append("files", file);
}
return submitForm;
}
async function createWorkout() {
let submitForm = generateWorkoutForm();
let response = await sendRequest("POST", `${HOST}/api/workouts/`, submitForm, "");
if (response.ok) {
window.location.replace("workouts.html");
} else {
let data = await response.json();
let alert = createAlert("Could not create new workout!", data);
document.body.prepend(alert);
}
}
function handleCancelDuringWorkoutCreate() {
window.location.replace("workouts.html");
}
async function createBlankExercise() {
let form = document.querySelector("#form-workout");
let exerciseTypeResponse = await sendRequest("GET", `${HOST}/api/exercises/`);
let exerciseTypes = await exerciseTypeResponse.json();
let exerciseTemplate = document.querySelector("#template-exercise");
let divExerciseContainer = exerciseTemplate.content.firstElementChild.cloneNode(true);
let exerciseTypeSelect = divExerciseContainer.querySelector("select");
for (let i = 0; i < exerciseTypes.count; i++) {
let option = document.createElement("option");
option.value = exerciseTypes.results[i].id;
option.innerText = exerciseTypes.results[i].name;
exerciseTypeSelect.append(option);
}
let currentExerciseType = exerciseTypes.results[0];
exerciseTypeSelect.value = currentExerciseType.name;
let divExercises = document.querySelector("#div-exercises");
divExercises.appendChild(divExerciseContainer);
}
function removeExercise(event) {
let divExerciseContainers = document.querySelectorAll(".div-exercise-container");
if (divExerciseContainers && divExerciseContainers.length > 0) {
divExerciseContainers[divExerciseContainers.length - 1].remove();
}
}
function addComment(author, text, date, append) {
/* Taken from https://www.bootdey.com/snippets/view/Simple-Comment-panel#css*/
let commentList = document.querySelector("#comment-list");
let listElement = document.createElement("li");
listElement.className = "media";
let commentBody = document.createElement("div");
commentBody.className = "media-body";
let dateSpan = document.createElement("span");
dateSpan.className = "text-muted pull-right me-1";
let smallText = document.createElement("small");
smallText.className = "text-muted";
if (date != "Now") {
let localDate = new Date(date);
smallText.innerText = localDate.toLocaleString();
} else {
smallText.innerText = date;
}
dateSpan.appendChild(smallText);
commentBody.appendChild(dateSpan);
let strong = document.createElement("strong");
strong.className = "text-success";
strong.innerText = author;
commentBody.appendChild(strong);
let p = document.createElement("p");
p.innerHTML = text;
commentBody.appendChild(strong);
commentBody.appendChild(p);
listElement.appendChild(commentBody);
if (append) {
commentList.append(listElement);
} else {
commentList.prepend(listElement);
}
}
async function createComment(workoutid) {
let commentArea = document.querySelector("#comment-area");
let content = commentArea.value;
let body = {workout: `${HOST}/api/workouts/${workoutid}/`, content: content};
let response = await sendRequest("POST", `${HOST}/api/comments/`, body);
if (response.ok) {
addComment(sessionStorage.getItem("username"), content, "Now", false);
} else {
let data = await response.json();
let alert = createAlert("Failed to create comment!", data);
document.body.prepend(alert);
}
}
async function retrieveComments(workoutid) {
let response = await sendRequest("GET", `${HOST}/api/comments/`);
if (!response.ok) {
let data = await response.json();
let alert = createAlert("Could not retrieve comments!", data);
document.body.prepend(alert);
} else {
let data = await response.json();
let comments = data.results;
for (let comment of comments) {
let splitArray = comment.workout.split("/");
if (splitArray[splitArray.length - 2] == workoutid) {
addComment(comment.owner, comment.content, comment.timestamp, true);
}
}
}
}
window.addEventListener("DOMContentLoaded", async () => {
cancelWorkoutButton = document.querySelector("#btn-cancel-workout");
okWorkoutButton = document.querySelector("#btn-ok-workout");
deleteWorkoutButton = document.querySelector("#btn-delete-workout");
editWorkoutButton = document.querySelector("#btn-edit-workout");
exportWorkoutButton = document.querySelector("#btn-export-workout");
let postCommentButton = document.querySelector("#post-comment");
let divCommentRow = document.querySelector("#div-comment-row");
let buttonAddExercise = document.querySelector("#btn-add-exercise");
let buttonRemoveExercise = document.querySelector("#btn-remove-exercise");
buttonAddExercise.addEventListener("click", createBlankExercise);
buttonRemoveExercise.addEventListener("click", removeExercise);
const urlParams = new URLSearchParams(window.location.search);
let currentUser = await getCurrentUser();
if (urlParams.has('id')) {
const id = urlParams.get('id');
let workoutData = await retrieveWorkout(id);
await retrieveComments(id);
if (workoutData["owner"] == currentUser.url) {
editWorkoutButton.classList.remove("hide");
exportWorkoutButton.classList.remove("hide");
editWorkoutButton.addEventListener("click", handleEditWorkoutButtonClick);
exportWorkoutButton.addEventListener("click", ((workoutData) => handleExportToCalendarClick(workoutData)).bind(undefined, workoutData));
deleteWorkoutButton.addEventListener("click", (async (id) => await deleteWorkout(id)).bind(undefined, id));
okWorkoutButton.addEventListener("click", (async (id) => await updateWorkout(id)).bind(undefined, id));
postCommentButton.addEventListener("click", (async (id) => await createComment(id)).bind(undefined, id));
divCommentRow.className = divCommentRow.className.replace(" hide", "");
}
} else {
await createBlankExercise();
let ownerInput = document.querySelector("#inputOwner");
ownerInput.value = currentUser.username;
setReadOnly(false, "#form-workout");
ownerInput.readOnly = !ownerInput.readOnly;
okWorkoutButton.className = okWorkoutButton.className.replace(" hide", "");
cancelWorkoutButton.className = cancelWorkoutButton.className.replace(" hide", "");
buttonAddExercise.className = buttonAddExercise.className.replace(" hide", "");
buttonRemoveExercise.className = buttonRemoveExercise.className.replace(" hide", "");
okWorkoutButton.addEventListener("click", async () => await createWorkout());
cancelWorkoutButton.addEventListener("click", handleCancelDuringWorkoutCreate);
divCommentRow.className += " hide";
}
});