From 4ee3e4d30fffda129977171b2c45e05449655390 Mon Sep 17 00:00:00 2001 From: Simen <simen_opedal@hotmail.com> Date: Mon, 7 Mar 2022 18:26:10 +0100 Subject: [PATCH] Added functionality for editing groups, and added groups to navbar --- backend/secfit/groups/serializers.py | 4 +- backend/secfit/groups/urls.py | 3 +- backend/secfit/groups/views.py | 25 +++++-- frontend/www/group.html | 5 +- frontend/www/scripts/group.js | 108 +++++++++++++++++++++++++-- frontend/www/scripts/groups.js | 2 +- frontend/www/scripts/navbar.js | 1 + frontend/www/scripts/scripts.js | 3 + 8 files changed, 133 insertions(+), 18 deletions(-) diff --git a/backend/secfit/groups/serializers.py b/backend/secfit/groups/serializers.py index d58a16e..8cbed78 100644 --- a/backend/secfit/groups/serializers.py +++ b/backend/secfit/groups/serializers.py @@ -8,7 +8,7 @@ class GroupSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Group - fields = ["owner", "name", "description"] + fields = ["id", "owner", "name", "description"] class MembershipSerializer(serializers.ModelSerializer): @@ -16,4 +16,4 @@ class MembershipSerializer(serializers.ModelSerializer): class Meta: model = Membership - fields = ["member", "group"] + fields = ["id", "member", "group"] diff --git a/backend/secfit/groups/urls.py b/backend/secfit/groups/urls.py index ee77e41..32d8282 100644 --- a/backend/secfit/groups/urls.py +++ b/backend/secfit/groups/urls.py @@ -1,8 +1,9 @@ from django.urls import path -from .views import GroupView, MembershipView +from .views import GroupView, MembershipView, getGroup urlpatterns = [ path("api/groups/", GroupView.as_view(), name="group-view"), path("api/members/", MembershipView.as_view(), name="membership-view"), + path("api/groups/<int:pk>/", getGroup.as_view(), name="updateGroup-view"), ] diff --git a/backend/secfit/groups/views.py b/backend/secfit/groups/views.py index 75cd8a5..6bc8ec3 100644 --- a/backend/secfit/groups/views.py +++ b/backend/secfit/groups/views.py @@ -9,7 +9,7 @@ from rest_framework.filters import OrderingFilter class GroupView( - mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView + mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, generics.GenericAPIView, ): queryset = Group.objects.all() serializer_class = GroupSerializer @@ -26,21 +26,34 @@ class GroupView( serializer.save(owner=self.request.user) -class MembershipView( +class getGroup( mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.ListModelMixin, generics.GenericAPIView, ): - queryset = Membership.objects.all() - serializer_class = MembershipSerializer + queryset = Group.objects.all() + serializer_class = GroupSerializer # permission_classes = [permissions.IsAuthenticated] - """ def get(self, request, *args, **kwargs): return self.retrieve(request, *args, **kwargs) - """ + + def put(self, request, *args, **kwargs): + return self.update(request, *args, **kwargs) + + +class MembershipView( + mixins.RetrieveModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + mixins.ListModelMixin, + generics.GenericAPIView, +): + queryset = Membership.objects.all() + serializer_class = MembershipSerializer + # permission_classes = [permissions.IsAuthenticated] def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) diff --git a/frontend/www/group.html b/frontend/www/group.html index f491a0a..4ab650e 100644 --- a/frontend/www/group.html +++ b/frontend/www/group.html @@ -31,8 +31,9 @@ </div> <div class="col-lg-6"></div> <div class="col-lg-6"> - <input type="button" class="btn btn-primary" id="btn-ok-group" value=" OK "> - <input type="button" class="btn btn-secondary" id="btn-cancel-group" value="Cancel"> + <input type="button" class="btn btn-primary hide" id="btn-ok-group" value=" OK "> + <input type="button" class="btn btn-secondary hide" id="btn-cancel-group" value="Cancel"> + <input type="button" class="btn btn-primary" id="btn-edit-group" value=" Edit "> </div> <div class="col-lg-6"> diff --git a/frontend/www/scripts/group.js b/frontend/www/scripts/group.js index adb7772..b8c716d 100644 --- a/frontend/www/scripts/group.js +++ b/frontend/www/scripts/group.js @@ -1,12 +1,29 @@ let cancelButton; let okButton; +let editButton; let oldFormData; function handleCancelButtonDuringCreate() { window.location.replace("groups.html"); } -async function createExercise() { +function handleCancelButtonDuringEdit() { + setReadOnly(true, "#form-group"); + okButton.className += " hide"; + cancelButton.className += " hide"; + editButton.className = editButton.className.replace(" hide", ""); + + cancelButton.removeEventListener("click", handleCancelButtonDuringEdit); + + let form = document.querySelector("#form-group"); + if (oldFormData.has("name")) form.name.value = oldFormData.get("name"); + if (oldFormData.has("description")) form.description.value = oldFormData.get("description"); + + oldFormData.delete("name"); + oldFormData.delete("description"); +} + +async function createGroup() { let form = document.querySelector("#form-group"); let formData = new FormData(form); let body = {"name": formData.get("name"), @@ -24,16 +41,95 @@ async function createExercise() { } } + +function handleEditGroupButtonClick() { + setReadOnly(false, "#form-group"); + + editButton.className += " hide"; + okButton.className = okButton.className.replace(" hide", ""); + cancelButton.className = cancelButton.className.replace(" hide", ""); + + cancelButton.addEventListener("click", handleCancelButtonDuringEdit); + + let form = document.querySelector("#form-group"); + oldFormData = new FormData(form); +} + +async function retrieveGroup(id) { + let response = await sendRequest("GET", `${HOST}/api/groups/${id}/`); + + console.log(response.ok) + + if (!response.ok) { + let data = await response.json(); + let alert = createAlert("Could not retrieve group data!", data); + document.body.prepend(alert); + } else { + let groupData = await response.json(); + let form = document.querySelector("#form-group"); + let formData = new FormData(form); + + for (let key of formData.keys()) { + let selector + selector = `input[name="${key}"], textarea[name="${key}"]`; + let input = form.querySelector(selector); + let newVal = groupData[key]; + input.value = newVal; + } + } +} + +async function updateGroup(id) { + let form = document.querySelector("#form-group"); + let formData = new FormData(form); + + let body = {"name": formData.get("name"), + "description": formData.get("description"), + }; + let response = await sendRequest("PUT", `${HOST}/api/groups/${id}/`, body); + + if (!response.ok) { + let data = await response.json(); + let alert = createAlert(`Could not update group ${id}`, data); + document.body.prepend(alert); + } else { + setReadOnly(true, "#form-group"); + okButton.className += " hide"; + cancelButton.className += " hide"; + editButton.className = editButton.className.replace(" hide", ""); + + cancelButton.removeEventListener("click", handleCancelButtonDuringEdit); + + oldFormData.delete("name"); + oldFormData.delete("description"); + } +} + window.addEventListener("DOMContentLoaded", async () => { cancelButton = document.querySelector("#btn-cancel-group"); okButton = document.querySelector("#btn-ok-group"); + editButton = document.querySelector("#btn-edit-group"); oldFormData = null; - setReadOnly(false, "#form-group"); + const urlParams = new URLSearchParams(window.location.search); - okButton.className = okButton.className.replace(" hide", ""); - cancelButton.className = cancelButton.className.replace(" hide", ""); + // view/edit + if (urlParams.has('id')) { + const groupId = urlParams.get('id'); + await retrieveGroup(groupId); + + editButton.addEventListener("click", handleEditGroupButtonClick); + okButton.addEventListener("click", (async (id) => await updateGroup(id)).bind(undefined, groupId)); + } + //create + else { + setReadOnly(false, "#form-group"); - okButton.addEventListener("click", async () => await createExercise()); - cancelButton.addEventListener("click", handleCancelButtonDuringCreate); + editButton.className += " hide"; + okButton.className = okButton.className.replace(" hide", ""); + cancelButton.className = cancelButton.className.replace(" hide", ""); + + okButton.addEventListener("click", async () => await createGroup()); + cancelButton.addEventListener("click", handleCancelButtonDuringCreate); + } }); \ No newline at end of file diff --git a/frontend/www/scripts/groups.js b/frontend/www/scripts/groups.js index b15df62..4e839b7 100644 --- a/frontend/www/scripts/groups.js +++ b/frontend/www/scripts/groups.js @@ -9,7 +9,7 @@ async function fetchGroups(request) { let exerciseTemplate = document.querySelector("#template-group"); groups.forEach(group => { const exerciseAnchor = exerciseTemplate.content.firstElementChild.cloneNode(true); - exerciseAnchor.href = `exercise.html?id=${group.id}`; + exerciseAnchor.href = `group.html?id=${group.id}`; const h5 = exerciseAnchor.querySelector("h5"); h5.textContent = group.name; diff --git a/frontend/www/scripts/navbar.js b/frontend/www/scripts/navbar.js index 8dec8c1..15bf24e 100644 --- a/frontend/www/scripts/navbar.js +++ b/frontend/www/scripts/navbar.js @@ -19,6 +19,7 @@ class NavBar extends HTMLElement { <a class="nav-link hide" id="nav-mycoach" href="mycoach.html">Coach</a> <a class="nav-link hide" id="nav-myathletes" href="myathletes.html">Athletes</a> <a class="nav-link hide" id="nav-meals" href="meals.html">Meal registration</a> + <a class="nav-link hide" id="nav-groups" href="groups.html">Groups</a> <hr> </div> <div class="my-2 my-lg-0 me-5"> diff --git a/frontend/www/scripts/scripts.js b/frontend/www/scripts/scripts.js index 9bfc1ef..1cd1744 100644 --- a/frontend/www/scripts/scripts.js +++ b/frontend/www/scripts/scripts.js @@ -24,6 +24,8 @@ function updateNavBar() { makeNavLinkActive("nav-myathletes"); } else if (window.location.pathname == "/meals.html") { makeNavLinkActive("nav-myathletes"); + } else if (window.location.pathname == "/groups.html") { + makeNavLinkActive("nav-groups"); } if (isUserAuthenticated()) { @@ -35,6 +37,7 @@ function updateNavBar() { document.querySelector('a[href="exercises.html"').classList.remove("hide"); document.querySelector('a[href="myathletes.html"').classList.remove("hide"); document.querySelector('a[href="meals.html"').classList.remove("hide"); + document.querySelector('a[href="groups.html"').classList.remove("hide"); } else { document.getElementById("btn-login-nav").classList.remove("hide"); document.getElementById("btn-register").classList.remove("hide"); -- GitLab