diff --git a/frontend/www/goal.html b/frontend/www/goal.html new file mode 100644 index 0000000000000000000000000000000000000000..97d2088fa1a1ccd9635746b9e95bb53c9b4adca9 --- /dev/null +++ b/frontend/www/goal.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Exercise</title> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> + + <script src="https://kit.fontawesome.com/0ce6c392ca.js" crossorigin="anonymous"></script> + <link rel="stylesheet" href="styles/style.css"> + <script src="scripts/navbar.js" type="text/javascript" defer></script> +</head> +<body> +<navbar-el></navbar-el> + +<div class="container"> + <div class="row"> + <div class="col-lg"> + <h3 class="mt-3">View/Edit Exercise</h3> + </div> + </div> + <form class="row g-3" id="form-exercise"> + <div class="col-lg-6 "> + <label for="inputName" class="form-label">Name</label> + <input type="text" class="form-control" id="inputName" name="name" readonly> + </div> + <div class="col-lg-6"></div> + <div class="col-lg-6"> + <label for="inputDescription" class="form-label">Description</label> + <textarea class="form-control" id="inputDescription" name="description" readonly></textarea> + </div> + <div class="col-lg-6"></div> + <div class="col-lg-6"> + <label for="inputUnit" class="form-label">Unit (Reps, time, etc.)</label> + <input type="text" class="form-control" id="inputUnit" name="unit" readonly> + </div> + <div class="col-lg-6"></div> + <div class="col-lg-6"> + <label for="inputDuration" class="form-label"> Duration(Expects a positive integer)</label> + <input type="number" class="form-control" id="inputDuration" name="duration" readonly></input> + </div> + <div class="col-lg-6"></div> + <div class="col-lg-6"> + <label for="inputCalories" class="form-label"> Calories burned (Expects a positive integer)</label> + <input type="number" class="form-control" id="inputCalories" name="calories" readonly></input> + </div> + <div class="col-lg-6"></div> + <div class="col-lg-6"> + <label for="inputMuscles" class="form-label">Muscle group used</label> + <select class="form-select" name="muscleGroup" disabled="true"> + <option value="Legs">Legs</option> + <option value="Chest">Chest</option> + <option value="Back">Back</option> + <option value="Arms">Arms</option> + <option value="Abdomen">Abdominals</option> + <option value="Shoulders">Shoulders</option> + </select> + </div> + <div class="col-lg-6"></div> + <div class="col-lg-6"> + <input type="button" class="btn btn-primary hide" id="btn-ok-exercise" value=" OK "> + <input type="button" class="btn btn-primary" id="btn-edit-exercise" value=" Edit "> + <input type="button" class="btn btn-secondary hide" id="btn-cancel-exercise" value="Cancel"> + <input type="button" class="btn btn-danger float-end hide" id="btn-delete-exercise" value="Delete"> + </div> + <div class="col-lg-6"> + + </div> + </form> +</div> +<script src="scripts/defaults.js"></script> +<script src="scripts/scripts.js"></script> +<script src="scripts/goal.js"></script> +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> +</body> +</html> diff --git a/frontend/www/goals.html b/frontend/www/goals.html index 43b056cc128edf67bf9e341dc72d1486e0067093..ede323df8a50740e85521387712e3a13c075b859 100644 --- a/frontend/www/goals.html +++ b/frontend/www/goals.html @@ -17,26 +17,22 @@ <div class="row"> <div class="col-lg text-center"> <h3 class="mt-5">View Goals</h3> - <p>Here you can view, create, and edit exercise types defined by you and other athletes.</p> - <input type="button" class="btn btn-primary" id="btn-create-exercise" value="Create new exercise"> - </div> - <div class="row"> - <div class="col-lg text-center"> - <div class="list-group mt-1" id="div-content"></div> - </div> + <p>Here you can view, create, and edit goals</p> + <input type="button" class="btn btn-primary" id="btn-create-goal" value="Create new goal"> </div> + <div class="row mt-3 justify-content-center" id="div-content"></div> </div> + + <template id="template-exercise"> - <a class="list-group-item list-group-item-action flex-column align-items-start my-1 exercise" href=""> - <div class="d-flex w-100 justify-content-between align-items-center"> - <h5 class="mb-1"></h5> - </div> - <div class="d-flex"> - <p class="mb-1"> - </p> + <div class="card ml-1" style="width: 24rem;"> + <div class="card-body"> + <h5 class="card-title"></h5> + <p class="card-text"></p> + <a href="#" class="card-link">Edit goal</a> </div> - </a> + </div> </template> <script src="scripts/defaults.js"></script> diff --git a/frontend/www/scripts/goal.js b/frontend/www/scripts/goal.js new file mode 100644 index 0000000000000000000000000000000000000000..f845fe1844b633cf1b0bf1365eee4323c4c84bcc --- /dev/null +++ b/frontend/www/scripts/goal.js @@ -0,0 +1,211 @@ +let cancelButton; +let okButton; +let deleteButton; +let editButton; +let oldFormData; + +class MuscleGroup { + constructor(type) { + this.isValidType = false; + this.validTypes = ["Legs", "Chest", "Back", "Arms", "Abdomen", "Shoulders"] + + this.type = this.validTypes.includes(type) ? type : undefined; + }; + + setMuscleGroupType = (newType) => { + this.isValidType = false; + + if(this.validTypes.includes(newType)){ + this.isValidType = true; + this.type = newType; + } + else{ + alert("Invalid muscle group!"); + } + + }; + + getMuscleGroupType = () => { + console.log(this.type, "SWIOEFIWEUFH") + return this.type; + } +} + +function handleCancelButtonDuringEdit() { + setReadOnly(true, "#form-exercise"); + document.querySelector("select").setAttribute("disabled", "") + okButton.className += " hide"; + deleteButton.className += " hide"; + cancelButton.className += " hide"; + editButton.className = editButton.className.replace(" hide", ""); + + cancelButton.removeEventListener("click", handleCancelButtonDuringEdit); + + let form = document.querySelector("#form-exercise"); + if (oldFormData.has("name")) form.name.value = oldFormData.get("name"); + if (oldFormData.has("description")) form.description.value = oldFormData.get("description"); + if (oldFormData.has("duration")) form.duration.value = oldFormData.get("duration"); + if (oldFormData.has("calories")) form.calories.value = oldFormData.get("calories"); + if (oldFormData.has("muscleGroup")) form.muscleGroup.value = oldFormData.get("muscleGroup"); + if (oldFormData.has("unit")) form.unit.value = oldFormData.get("unit"); + + oldFormData.delete("name"); + oldFormData.delete("description"); + oldFormData.delete("duration"); + oldFormData.delete("calories"); + oldFormData.delete("muscleGroup"); + oldFormData.delete("unit"); + +} + +function handleCancelButtonDuringCreate() { + window.location.replace("exercises.html"); +} + +async function createExercise() { + document.querySelector("select").removeAttribute("disabled") + let form = document.querySelector("#form-exercise"); + let formData = new FormData(form); + let body = {"name": formData.get("name"), + "description": formData.get("description"), + "duration": formData.get("duration"), + "calories": formData.get("calories"), + "muscleGroup": formData.get("muscleGroup"), + "unit": formData.get("unit")}; + + let response = await sendRequest("POST", `${HOST}/api/exercises/`, body); + + if (response.ok) { + window.location.replace("exercises.html"); + } else { + let data = await response.json(); + let alert = createAlert("Could not create new exercise!", data); + document.body.prepend(alert); + } +} + +function handleEditExerciseButtonClick() { + setReadOnly(false, "#form-exercise"); + + document.querySelector("select").removeAttribute("disabled") + + editButton.className += " hide"; + okButton.className = okButton.className.replace(" hide", ""); + cancelButton.className = cancelButton.className.replace(" hide", ""); + deleteButton.className = deleteButton.className.replace(" hide", ""); + + cancelButton.addEventListener("click", handleCancelButtonDuringEdit); + + let form = document.querySelector("#form-exercise"); + oldFormData = new FormData(form); +} + +async function deleteExercise(id) { + let response = await sendRequest("DELETE", `${HOST}/api/exercises/${id}/`); + if (!response.ok) { + let data = await response.json(); + let alert = createAlert(`Could not delete exercise ${id}`, data); + document.body.prepend(alert); + } else { + window.location.replace("exercises.html"); + } +} + +async function retrieveExercise(id) { + let response = await sendRequest("GET", `${HOST}/api/exercises/${id}/`); + + console.log(response.ok) + + if (!response.ok) { + let data = await response.json(); + let alert = createAlert("Could not retrieve exercise data!", data); + document.body.prepend(alert); + } else { + document.querySelector("select").removeAttribute("disabled") + let exerciseData = await response.json(); + let form = document.querySelector("#form-exercise"); + let formData = new FormData(form); + + for (let key of formData.keys()) { + let selector + key !== "muscleGroup" ? selector = `input[name="${key}"], textarea[name="${key}"]` : selector = `select[name=${key}]` + let input = form.querySelector(selector); + let newVal = exerciseData[key]; + input.value = newVal; + } + document.querySelector("select").setAttribute("disabled", "") + } +} + +async function updateExercise(id) { + let form = document.querySelector("#form-exercise"); + let formData = new FormData(form); + + let muscleGroupSelector = document.querySelector("select") + muscleGroupSelector.removeAttribute("disabled") + + let selectedMuscleGroup = new MuscleGroup(formData.get("muscleGroup")); + + let body = {"name": formData.get("name"), + "description": formData.get("description"), + "duration": formData.get("duration"), + "calories": formData.get("calories"), + "muscleGroup": selectedMuscleGroup.getMuscleGroupType(), + "unit": formData.get("unit")}; + let response = await sendRequest("PUT", `${HOST}/api/exercises/${id}/`, body); + + if (!response.ok) { + let data = await response.json(); + let alert = createAlert(`Could not update exercise ${id}`, data); + document.body.prepend(alert); + } else { + muscleGroupSelector.setAttribute("disabled", "") + // duplicate code from handleCancelButtonDuringEdit + // you should refactor this + setReadOnly(true, "#form-exercise"); + okButton.className += " hide"; + deleteButton.className += " hide"; + cancelButton.className += " hide"; + editButton.className = editButton.className.replace(" hide", ""); + + cancelButton.removeEventListener("click", handleCancelButtonDuringEdit); + + oldFormData.delete("name"); + oldFormData.delete("description"); + oldFormData.delete("duration"); + oldFormData.delete("calories"); + oldFormData.delete("muscleGroup"); + oldFormData.delete("unit"); + } +} + +window.addEventListener("DOMContentLoaded", async () => { + cancelButton = document.querySelector("#btn-cancel-exercise"); + okButton = document.querySelector("#btn-ok-exercise"); + deleteButton = document.querySelector("#btn-delete-exercise"); + editButton = document.querySelector("#btn-edit-exercise"); + oldFormData = null; + + const urlParams = new URLSearchParams(window.location.search); + + // view/edit + if (urlParams.has('id')) { + const exerciseId = urlParams.get('id'); + await retrieveExercise(exerciseId); + + editButton.addEventListener("click", handleEditExerciseButtonClick); + deleteButton.addEventListener("click", (async (id) => await deleteExercise(id)).bind(undefined, exerciseId)); + okButton.addEventListener("click", (async (id) => await updateExercise(id)).bind(undefined, exerciseId)); + } + //create + else { + setReadOnly(false, "#form-exercise"); + + editButton.className += " hide"; + okButton.className = okButton.className.replace(" hide", ""); + cancelButton.className = cancelButton.className.replace(" hide", ""); + + okButton.addEventListener("click", async () => await createExercise()); + cancelButton.addEventListener("click", handleCancelButtonDuringCreate); + } +}); \ No newline at end of file diff --git a/frontend/www/scripts/goals.js b/frontend/www/scripts/goals.js index 5ffe2c7ec9c68ad2c41adb496590686257af6e45..9a3ab387979bb6b6d341a9ff300f858e1ec6b932 100644 --- a/frontend/www/scripts/goals.js +++ b/frontend/www/scripts/goals.js @@ -17,6 +17,9 @@ async function fetchExerciseTypes(request) { const p = exerciseAnchor.querySelector("p"); p.textContent = exercise.description; + const a = exerciseAnchor.querySelector("a"); + a.href = `exercise.html?id=${exercise.id}`; + container.appendChild(exerciseAnchor); }); } @@ -25,11 +28,11 @@ async function fetchExerciseTypes(request) { } function createExercise() { - window.location.replace("goals.html"); + window.location.replace("goal.html"); } window.addEventListener("DOMContentLoaded", async () => { - let createButton = document.querySelector("#btn-create-exercise"); + let createButton = document.querySelector("#btn-create-goal"); createButton.addEventListener("click", createExercise); let response = await fetchExerciseTypes();