diff --git a/backend/secfit/groups/serializers.py b/backend/secfit/groups/serializers.py index d58a16e01cb9c5ea34b0b6dd2ad2429b4d43ccc2..8cbed7890ff29ac028934f974bc038e4c8689133 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 ee77e415f3d108f7d5ce09930a6655df906b0c6e..32d8282ff3fc2c084290855c61f61facc1bd1eae 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 75cd8a5a4602726c5aba430044eb83313ee474e8..6bc8ec3e2b1ca90e847e1971fcdd18a8d4603212 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 f491a0a8e8776415332c240d1a8113f065ff7d58..4ab650e465b98e14ae9c35da2e8a1d7689f6bbfb 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 adb777226b7ea76fda839b0cc098315a2e9543c2..b8c716d3b7a1fd8abf3026c8bd125358f04e2de2 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 b15df62715851ccd568fa700a7f4a20e9cf56eed..4e839b7635c2d8091dfbaf4b37a4507edfba15fb 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 8dec8c1a20089ea9bbb85e5df99001473ec64c2c..15bf24e7fcb91a549370f050eb9c53e5a284d97b 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 9bfc1efb688400bcabfa9457b05be97f8dbd9c92..1cd174452b91bba96cb5840dd42a2ee9996e923e 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");