diff --git a/frontend/src/views/CourseAssessment/CourseAssessment.vue b/frontend/src/views/CourseAssessment/CourseAssessment.vue index 6c3ccac27e17bb6ad8a85904cb195c7091c0f42c..f2b2d7c50b3f9cf67720b0e09f1ee329cb75266d 100644 --- a/frontend/src/views/CourseAssessment/CourseAssessment.vue +++ b/frontend/src/views/CourseAssessment/CourseAssessment.vue @@ -1,7 +1,7 @@ <template> <div class="row m-0 bg-primary-six"> <!-- Alert --> - <!-- <div class="d-flex justify-content-center"> + <div class="d-flex justify-content-center"> <div v-if="submitted" class="alert border-0 rounded alert-dismissible fade show" @@ -14,7 +14,7 @@ {{ alertText }} <div type="button" class="btn-close" @click="submitted = false"></div> </div> - </div> --> + </div> <div class="col-auto p-0"> <sidebar /> </div> @@ -52,47 +52,26 @@ </tr> </thead> <tbody> - <tr> - <td class="align-middle">1</td> - <td class="align-middle">IF5122</td> - <td class="align-middle">Pembangunan Perangkat Lunak</td> - <td class="text-center align-middle">01</td> + <tr + v-for="(singleClass, index) in classes" + :key="singleClass.id" + > + <td class="align-middle">{{ index + 1 }}</td> + <td class="align-middle">{{ singleClass.courseCode }}</td> + <td class="align-middle">{{ singleClass.courseName }}</td> <td class="text-center align-middle"> - Selasa / 13:00 - 15:00 + {{ singleClass.number }} </td> <td class="text-center align-middle"> - <div class="row"> - <!-- Button Edit --> - <div class="col px-1 d-flex align-items-center"> - <button - type="button" - class="btn btn-secondary-six col-12 p-2" - @click="onClickItem" - > - Sunting - </button> - </div> - <!-- Button Submit --> - <div class="col px-1 d-flex align-items-center"> - <button - type="button" - class="btn btn-primary-six col-12 p-2" - @click="openConfirmationModal" - > - Kirim - </button> - </div> + <div + v-for="schedule in singleClass.schedules" + :key="schedule.day" + > + {{ convertDay(schedule.day) }} / + {{ schedule.start.substring(0, 5) }} - + {{ schedule.end.substring(0, 5) }} </div> </td> - </tr> - <tr> - <td class="align-middle">2</td> - <td class="align-middle">IF5122</td> - <td class="align-middle">Pembangunan Perangkat Lunak</td> - <td class="text-center align-middle">01</td> - <td class="text-center align-middle"> - Selasa / 13:00 - 15:00 - </td> <td class="text-center align-middle"> <div class="row"> <!-- Button Edit --> @@ -100,7 +79,7 @@ <button type="button" class="btn btn-secondary-six col-12 p-2" - @click="onClickItem" + @click="onClickItem(singleClass.id)" > Sunting </button> @@ -109,10 +88,19 @@ <div class="col px-1 d-flex align-items-center"> <button type="button" - class="btn btn-disabled-six col-12 p-2" - @click="openConfirmationModal" + class="btn col-12 p-2" + :class=" + singleClass.scoreSent + ? 'btn-disabled-six' + : 'btn-primary-six' + " + @click=" + singleClass.scoreSent + ? '' + : openConfirmationModal(singleClass.id, index) + " > - Terkirim + {{ singleClass.scoreSent ? "Terkirim" : "Kirim" }} </button> </div> </div> @@ -162,6 +150,7 @@ type="button" class="btn btn-primary-six col-12" data-dismiss="modal" + @click="submit" > Kirim </button> @@ -177,6 +166,9 @@ <script> import Sidebar from "@/components/Sidebar/Sidebar"; import { Modal } from "bootstrap"; +import axios from "axios"; +import { getAllClassNumber } from "../../store/classNumber"; +import { getClassNumberById } from "../../store/classNumber"; export default { components: { Sidebar }, @@ -185,9 +177,26 @@ export default { return { semester: 1, year: 2021, - confirmationModal: null + confirmationModal: null, + userId: null, + classes: [], + allClasses: [], + allCourses: [], + choosenClassIndex: null, + choosenClassId: null, + submitted: false, + alertText: null, + isAlertSuccess: false, + isAlertDanger: false }; }, + async mounted() { + this.userId = localStorage.getItem("uid"); + await this.getAllCourses(); + await this.getAllClasses(); + await this.getClasses(); + await this.getClassScoreSent(); + }, methods: { GetHeaderString() { return ( @@ -199,21 +208,187 @@ export default { (this.year + 1) ); }, - openConfirmationModal() { + openConfirmationModal(classId, index) { + this.choosenClassId = classId; + this.choosenClassIndex = index; this.confirmationModal = new Modal( document.getElementById("confirmationModal") ); this.confirmationModal.show(); }, - /* Use This for Integration - onClickItem(e) { + onClickItem(classId) { this.$router.push({ path: "/create-edit-assessment", - query: { id: e.id } + query: { id: classId } }); - }, */ - onClickItem() { - this.$router.push("/create-edit-assessment"); + }, + submit() { + let params = { + courseClassId: this.choosenClassId + }; + + let body = { + scoreStatus: "FINAL" + }; + + axios + .put(process.env.VUE_APP_API_ENDPOINT + "/score/status/", body, { + params: params + }) + .then(() => { + this.showAlert(1); + this.classes[this.choosenClassIndex].scoreSent = true; + }) + .catch((error) => { + console.error(error); + this.showAlert(0); + }); + }, + async getClasses() { + const params = { + semester: this.semester, + startYear: this.year, + include: ["Course", "Lecturer", "Students"] + }; + await axios + .get(process.env.VUE_APP_API_ENDPOINT + "/course-class/", { + params: params + }) + .then((response) => { + for (let i = 0; i < response.data.length; i++) { + if (this.userId === response.data[i].Lecturer.userId) { + let schedules = []; + + for ( + let j = 0; + j < response.data[i].courseClassDefaultSchedules.length; + j++ + ) { + schedules.push({ + day: response.data[i].courseClassDefaultSchedules[j].day, + start: response.data[i].courseClassDefaultSchedules[j].start, + end: response.data[i].courseClassDefaultSchedules[j].end + }); + } + + this.classes.push({ + id: response.data[i].id, + courseCode: response.data[i].Course.code, + courseName: response.data[i].Course.name, + number: getClassNumberById( + response.data[i].id, + this.allClasses + ), + schedules: schedules, + student: response.data[i].students[0], + scoreSent: false + }); + } + } + }) + .catch((error) => { + console.error(error); + }); + }, + async getClassScoreSent() { + for (let i = 0; i < this.classes.length; i++) { + if (this.classes[i].student) { + let params = { + studentId: this.classes[i].student.id, + semester: this.semester, + startYear: this.year + }; + + await axios + .get(process.env.VUE_APP_API_ENDPOINT + "/study-plan/", { + params: params + }) + .then((response) => { + for (let j = 0; j < response.data.studyPlanCourses.length; j++) { + if ( + response.data.studyPlanCourses[j].courseClassId === + this.classes[i].id + ) { + if ( + response.data.studyPlanCourses[j].scoreStatus === "FINAL" + ) { + this.classes[i].scoreSent = true; + } + break; + } + } + }) + .catch((error) => { + console.error(error); + }); + } + } + }, + showAlert(alertType) { + this.isAlertSuccess = false; + this.isAlertDanger = false; + if (alertType === 0) { + this.isAlertDanger = true; + this.alertText = "Nilai Gagal Dikirim"; + } else { + this.alertText = "Nilai Berhasil Dikirim"; + this.isAlertSuccess = true; + } + this.submitted = true; + }, + convertDay(engDay) { + let idDay = null; + + if (engDay === "SUNDAY") { + idDay = "Minggu"; + } else if (engDay === "MONDAY") { + idDay = "Senin"; + } else if (engDay === "TUESDAY") { + idDay = "Selasa"; + } else if (engDay === "WEDNESDAY") { + idDay = "Rabu"; + } else if (engDay === "THURSDAY") { + idDay = "Kamis"; + } else if (engDay === "FRIDAY") { + idDay = "Jumat"; + } else { + idDay = "Sabtu"; + } + + return idDay; + }, + async getAllCourses() { + await axios + .get(process.env.VUE_APP_API_ENDPOINT + "/course") + .then((response) => { + if (response.status == 200) { + this.allCourses = response.data; + } + }) + .catch((error) => { + console.error(error); + }); + }, + async getAllClasses() { + const params = { + status: "OPEN" + }; + await axios + .get(process.env.VUE_APP_API_ENDPOINT + "/course-class", { + params: params + }) + .then((response) => { + if (response.status == 200) { + this.allClasses = response.data; + this.allClasses = getAllClassNumber( + this.allCourses, + this.allClasses + ); + } + }) + .catch((error) => { + console.error(error); + }); } } }; diff --git a/frontend/src/views/CourseAssessment/CreateEditAssessment.vue b/frontend/src/views/CourseAssessment/CreateEditAssessment.vue index 3186e17fe21ffaa9f8d1988984dcf755e206f230..bff79ded4f239198a8b4d8a4c4508af31ed37cbd 100644 --- a/frontend/src/views/CourseAssessment/CreateEditAssessment.vue +++ b/frontend/src/views/CourseAssessment/CreateEditAssessment.vue @@ -1,12 +1,44 @@ <template> <div class="row m-0 bg-primary-six"> + <!-- Alert Create Edit Class Result --> + <div class="d-flex justify-content-center"> + <div + v-if="submitted" + class="alert border-0 rounded alert-dismissible fade show" + role="alert" + :class="{ + 'alert-success': isAlertSuccess, + 'alert-danger': isAlertDanger + }" + > + {{ alertText }} + <div type="button" class="btn-close" @click="submitted = false"></div> + </div> + </div> <div class="col-auto p-0"> <sidebar /> </div> - <div class="col p-4 container-create-edit-assessment"> - <h1 data-aos="fade-down" data-aos-duration="1500" class="mb-4"> - Penilaian Mata Kuliah - </h1> + <div v-if="isClassExist" class="col p-4 container-create-edit-assessment"> + <div class="row"> + <div class="col"> + <h1 data-aos="fade-down" data-aos-duration="1500" class="mb-4"> + Penilaian Mata Kuliah + </h1> + </div> + <div class="col-auto"> + <div> + <button + type="button" + class="btn btn-primary-six col-12 w-auto" + data-aos="fade-down" + data-aos-duration="1500" + @click="$router.push('/course-assessment')" + > + Kembali ke Daftar Kelas + </button> + </div> + </div> + </div> <!-- Container List of Peserta & Informasi Kuliah --> <div class="row mt-2 container-lecturer-course-enrollment"> <!-- Card List of Peserta --> @@ -37,17 +69,25 @@ </tr> </thead> <tbody> - <tr> - <td class="align-middle">1</td> - <td class="align-middle">23520051</td> - <td class="align-middle">Dimas Aditia Pratikto</td> - <!-- @TODO: modify code in here --> + <tr + v-for="(student, index) in classParticipants" + :key="student.id" + > + <td class="align-middle">{{ index + 1 }}</td> + <td class="align-middle">{{ student.nim }}</td> + <td class="align-middle">{{ student.name }}</td> <td class="text-center"> <div class="col-auto"> <div class="form-group mb-0"> - <select class="form-select" aria-label="attendance"> + <select + class="form-select" + aria-label="attendance" + v-model="student.score" + > <option value="A">A</option> + <option value="AB">AB</option> <option value="B">B</option> + <option value="BC">BC</option> <option value="C">C</option> <option value="D">D</option> <option value="E">E</option> @@ -59,6 +99,18 @@ </tr> </tbody> </table> + <!-- Submit Button --> + <div + class="mt-4 col d-flex align-items-center justify-content-end" + > + <button + type="button" + class="btn btn-primary-six col-4" + @click="submit" + > + Simpan + </button> + </div> </div> </div> </div> @@ -85,35 +137,45 @@ <div class="row"> <div class="form-group col-12"> <label><b>Kode Mata Kuliah</b></label> - <p class="mb-0">IF5123</p> + <p class="mb-0">{{ courseCode }}</p> </div> </div> <!-- Nama --> <div class="row"> <div class="form-group col-12"> <label><b>Nama Mata Kuliah</b></label> - <p class="mb-0">Pembangunan Perangkat Lunak</p> + <p class="mb-0">{{ courseName }}</p> </div> </div> <!-- Kelas --> <div class="row"> <div class="form-group col-12"> <label><b>Kelas</b></label> - <p class="mb-0">01</p> + <p class="mb-0">{{ classNumber }}</p> </div> </div> <!-- Jadwal Rutin --> <div class="row"> <div class="form-group col-12"> <label><b>Jadwal Rutin</b></label> - <p class="mb-0">Selasa / 13:00 - 15:00</p> + <p + class="mb-0" + v-for="schedule in classSchedules" + :key="schedule.day" + > + {{ convertDay(schedule.day) }} / + {{ schedule.start.substring(0, 5) }} - + {{ schedule.end.substring(0, 5) }} + </p> </div> </div> <!-- Peserta --> <div class="row"> <div class="form-group col-12"> <label><b>Peserta</b></label> - <p class="mb-0">10 / 30</p> + <p class="mb-0"> + {{ classParticipantCount }} / {{ classMaxParticipant }} + </p> </div> </div> </div> @@ -122,15 +184,231 @@ </div> </div> </div> + <div v-else class="col p-4 container-create-edit-assessment"> + Kelas tidak ditemukan + </div> </div> </template> <script> import Sidebar from "@/components/Sidebar/Sidebar"; +import axios from "axios"; +import { getAllClassNumber } from "../../store/classNumber"; +import { getClassNumberById } from "../../store/classNumber"; export default { components: { Sidebar }, - name: "CreateEditAssessment" + name: "CreateEditAssessment", + data() { + return { + isClassExist: false, + courseClassId: null, + courseCode: null, + courseName: null, + classNumber: null, + classSchedules: [], + classParticipantCount: null, + classMaxParticipant: null, + classParticipants: [], + allClasses: [], + allCourses: [], + submitted: false, + alertText: null, + isAlertSuccess: false, + isAlertDanger: false + }; + }, + async mounted() { + this.courseClassId = this.$route.query.id; + await this.getAllCourses(); + await this.getAllClasses(); + this.getClassDetail(); + }, + methods: { + getClassDetail() { + function compare(a, b) { + if (a.nim < b.nim) { + return -1; + } + if (a.nim > b.nim) { + return 1; + } + return 0; + } + + const params = { + include: ["Course", "Lecturer", "Students"] + }; + axios + .get( + process.env.VUE_APP_API_ENDPOINT + + "/course-class/" + + this.courseClassId, + { params: params } + ) + .then((response) => { + this.isClassExist = true; + + this.courseCode = response.data.Course.code; + this.courseName = response.data.Course.name; + this.classNumber = getClassNumberById( + this.courseClassId, + this.allClasses + ); + this.classParticipantCount = response.data.participantCount; + this.classMaxParticipant = response.data.capacity; + + for ( + let i = 0; + i < response.data.courseClassDefaultSchedules.length; + i++ + ) { + this.classSchedules.push({ + day: response.data.courseClassDefaultSchedules[i].day, + start: response.data.courseClassDefaultSchedules[i].start, + end: response.data.courseClassDefaultSchedules[i].end + }); + } + + for (let i = 0; i < response.data.students.length; i++) { + this.classParticipants.push({ + id: response.data.students[i].id, + nim: response.data.students[i].nim, + name: response.data.students[i].fullName, + score: "" + }); + } + + this.classParticipants.sort(compare); + + this.getStudentsScore( + response.data.startYear, + response.data.semester + ); + }) + .catch((error) => { + console.error(error); + }); + }, + async getStudentsScore(year, semester) { + for (let i = 0; i < this.classParticipants.length; i++) { + let params = { + studentId: this.classParticipants[i].id, + semester: semester, + startYear: year + }; + + await axios + .get(process.env.VUE_APP_API_ENDPOINT + "/study-plan/", { + params: params + }) + .then((response) => { + for (let j = 0; j < response.data.studyPlanCourses.length; j++) { + if ( + response.data.studyPlanCourses[j].courseClassId === + this.courseClassId + ) { + this.classParticipants[i].score = + response.data.studyPlanCourses[j].score; + } + } + }) + .catch((error) => { + console.error(error); + }); + } + }, + submit() { + for (let i = 0; i < this.classParticipants.length; i++) { + let params = { + studentId: this.classParticipants[i].id, + courseClassId: this.courseClassId + }; + + let body = { + score: this.classParticipants[i].score + }; + + axios + .put(process.env.VUE_APP_API_ENDPOINT + "/score/", body, { + params: params + }) + .then(() => { + this.showAlert(1); + }) + .catch((error) => { + console.error(error); + this.showAlert(0); + }); + } + }, + showAlert(alertType) { + this.isAlertSuccess = false; + this.isAlertDanger = false; + if (alertType === 0) { + this.isAlertDanger = true; + this.alertText = "Nilai Gagal Disimpan"; + } else { + this.alertText = "Nilai Berhasil Disimpan"; + this.isAlertSuccess = true; + } + this.submitted = true; + }, + convertDay(engDay) { + let idDay = null; + + if (engDay === "SUNDAY") { + idDay = "Minggu"; + } else if (engDay === "MONDAY") { + idDay = "Senin"; + } else if (engDay === "TUESDAY") { + idDay = "Selasa"; + } else if (engDay === "WEDNESDAY") { + idDay = "Rabu"; + } else if (engDay === "THURSDAY") { + idDay = "Kamis"; + } else if (engDay === "FRIDAY") { + idDay = "Jumat"; + } else { + idDay = "Sabtu"; + } + + return idDay; + }, + async getAllCourses() { + await axios + .get(process.env.VUE_APP_API_ENDPOINT + "/course") + .then((response) => { + if (response.status == 200) { + this.allCourses = response.data; + } + }) + .catch((error) => { + console.error(error); + }); + }, + async getAllClasses() { + const params = { + status: "OPEN" + }; + await axios + .get(process.env.VUE_APP_API_ENDPOINT + "/course-class", { + params: params + }) + .then((response) => { + if (response.status == 200) { + this.allClasses = response.data; + this.allClasses = getAllClassNumber( + this.allCourses, + this.allClasses + ); + } + }) + .catch((error) => { + console.error(error); + }); + } + } }; </script>