From c1341976b05a039f91b7c560e59b28d6f49882e0 Mon Sep 17 00:00:00 2001 From: ahmedyoussefg <108885178+ahmedyoussefg@users.noreply.github.com> Date: Mon, 16 Dec 2024 20:50:30 +0200 Subject: [PATCH 01/18] Implement basic front end for Course Contents Page (student) --- frontend/public/index.html | 4 +- frontend/src/App.vue | 5 +- frontend/src/components/HeaderComponent.vue | 9 +- frontend/src/components/LessonList.vue | 52 +++++++ frontend/src/components/LessonListItem.vue | 43 ++++++ frontend/src/components/ModuleList.vue | 35 +++++ frontend/src/components/ModuleListItem.vue | 80 ++++++++++ frontend/src/components/VideoPlayer.vue | 27 ++++ frontend/src/pages/CourseContentPage.vue | 141 ++++++++++++++++++ frontend/src/pages/OAuthCallback.vue | 27 ---- frontend/src/router/index.js | 9 +- frontend/src/services/courseContentService.js | 106 +++++++++++++ .../src/services/dtos/CourseContentDTO.js | 38 +++++ frontend/src/store/index.js | 18 ++- 14 files changed, 555 insertions(+), 39 deletions(-) create mode 100644 frontend/src/components/LessonList.vue create mode 100644 frontend/src/components/LessonListItem.vue create mode 100644 frontend/src/components/ModuleList.vue create mode 100644 frontend/src/components/ModuleListItem.vue create mode 100644 frontend/src/components/VideoPlayer.vue create mode 100644 frontend/src/pages/CourseContentPage.vue delete mode 100644 frontend/src/pages/OAuthCallback.vue create mode 100644 frontend/src/services/courseContentService.js create mode 100644 frontend/src/services/dtos/CourseContentDTO.js diff --git a/frontend/public/index.html b/frontend/public/index.html index c9e2a66..f1f449f 100644 --- a/frontend/public/index.html +++ b/frontend/public/index.html @@ -5,11 +5,11 @@ - <%= htmlWebpackPlugin.options.title %> + Knowtopia
diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 887e02a..49ec0ab 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,7 +1,6 @@ @@ -43,7 +44,7 @@ export default { data() { return { store: useStore(), - selectedLessonContent: null, + selectedLesson: null, }; }, computed: { @@ -78,8 +79,8 @@ export default { return; }, methods: { - selectLesson(lessonContent) { - this.selectedLessonContent = lessonContent; + selectLesson(selectedLesson) { + this.selectedLesson = selectedLesson; }, markLessonAsCompleted() { // TODO: call API endpoint to POST this change From 254d69f7afbf39a9c8f186234cfd0cc5f43be792 Mon Sep 17 00:00:00 2001 From: ahmedyoussefg <108885178+ahmedyoussefg@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:35:17 +0200 Subject: [PATCH 16/18] Add API endpoint for mark lesson as completed in Front End --- frontend/src/pages/CourseContentPage.vue | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/CourseContentPage.vue b/frontend/src/pages/CourseContentPage.vue index 21a5b6f..1be55aa 100644 --- a/frontend/src/pages/CourseContentPage.vue +++ b/frontend/src/pages/CourseContentPage.vue @@ -36,6 +36,7 @@ import { useStore } from "vuex"; import ModuleList from "@/components/ModuleList.vue"; import VideoPlayer from "@/components/VideoPlayer.vue"; +import { postData } from "@/services/api.js" export default { components: { ModuleList, VideoPlayer }, @@ -82,9 +83,19 @@ export default { selectLesson(selectedLesson) { this.selectedLesson = selectedLesson; }, - markLessonAsCompleted() { - // TODO: call API endpoint to POST this change - console.log('marked') + async markLessonAsCompleted() { + try { + // Call the API and wait for the response + const response = await postData("/course/update", this.course); + + console.log("Response from server to mark lesson as completed:", response); + + // Update it in real time + this.selectedLesson.isCompleted = true; + console.log("Marked lesson as completed."); + } catch (error) { + console.error("Error marking lesson as complete:", error); + } } }, }; From a748d9b5de3a626953088f1a2300158801249e6a Mon Sep 17 00:00:00 2001 From: ahmedyoussefg <108885178+ahmedyoussefg@users.noreply.github.com> Date: Wed, 18 Dec 2024 00:11:53 +0200 Subject: [PATCH 17/18] Add endpoints for course content --- frontend/src/pages/CourseContentPage.vue | 4 +-- frontend/src/services/api.js | 12 +++++++- .../src/services/dtos/CourseContentDTO.js | 29 ++++++++++--------- frontend/src/store/index.js | 9 +++--- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/frontend/src/pages/CourseContentPage.vue b/frontend/src/pages/CourseContentPage.vue index 1be55aa..18f3e09 100644 --- a/frontend/src/pages/CourseContentPage.vue +++ b/frontend/src/pages/CourseContentPage.vue @@ -36,7 +36,7 @@ import { useStore } from "vuex"; import ModuleList from "@/components/ModuleList.vue"; import VideoPlayer from "@/components/VideoPlayer.vue"; -import { postData } from "@/services/api.js" +import { putData } from "@/services/api.js" export default { components: { ModuleList, VideoPlayer }, @@ -86,7 +86,7 @@ export default { async markLessonAsCompleted() { try { // Call the API and wait for the response - const response = await postData("/course/update", this.course); + const response = await putData("/course/update", this.course); console.log("Response from server to mark lesson as completed:", response); diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 700d254..99595e8 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -38,7 +38,7 @@ api.interceptors.response.use( export const fetchData = async (endpoint, DTO) => { try { const response = await api.get(endpoint); - return response.data.map((item) => new DTO(item)); + return new DTO(response.data); } catch (error) { console.error(`Error fetching data from ${endpoint}:`, error); throw error; @@ -54,3 +54,13 @@ export const postData = async (endpoint, data) => { throw error; } }; + +export const putData = async (endpoint, data) => { + try { + const response = await api.put(endpoint, data); + return response.data; + } catch (error) { + console.error(`Error putting data to ${endpoint}:`, error); + throw error; + } +}; diff --git a/frontend/src/services/dtos/CourseContentDTO.js b/frontend/src/services/dtos/CourseContentDTO.js index 8bc7367..635dbad 100644 --- a/frontend/src/services/dtos/CourseContentDTO.js +++ b/frontend/src/services/dtos/CourseContentDTO.js @@ -2,38 +2,39 @@ // Define a class for the lesson class Lesson { - constructor(title, lessonContent, isCompleted) { - this.title = title; - this.lessonContent = lessonContent; - this.isCompleted = isCompleted + constructor(data) { + this.title = data.title; + this.lessonContent = data.lessonContent; + this.isCompleted = data.isCompleted; } } // Define a class for the module class Module { - constructor(title, lessons = []) { - this.title = title; - this.lessons = lessons; // Array of Lesson objects + constructor(data) { + this.title = data.title; + // Array of Lesson objects + this.lessons = data.lessons.map((lessonItem) => new Lesson(lessonItem)); } addLesson(lesson) { - console.log('Current lessons:', this.lessons); this.lessons.push(lesson); } } // Define the main course class class CourseContentDTO { - constructor(id, title, modules = []) { - this.id = id; - this.title = title; - this.modules = modules; // Array of Module objects + constructor(data) { + this.id = data.id; + this.title = data.title; + // Array of Module objects + this.modules = data.modules.map((moduleItem) => new Module(moduleItem)); } addModule(module) { this.modules.push(module); } } - // Export the DTO class - export { CourseContentDTO, Module, Lesson }; +// Export the DTO class +export { CourseContentDTO, Module, Lesson }; \ No newline at end of file diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index d717c98..af0ea36 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -1,7 +1,8 @@ import { createStore } from "vuex"; import { SearchResultDTO } from "@/services/dtos/SearchResultDTO"; import { fetchCourses } from "@/services/searchApi"; -import { fetchCourseContent } from "@/services/courseContentService"; +import { fetchData } from "@/services/api"; +import { CourseContentDTO } from "@/services/dtos/CourseContentDTO"; const store = createStore({ state: { @@ -89,10 +90,10 @@ const store = createStore({ console.error("Failed to fetch courses:", error); } }, - async fetchCourseData(state, courseId) { + async fetchCourseData({ commit }, courseId) { try { - const course = await fetchCourseContent(courseId); - this.commit('setCourseData', course); + const course = await fetchData(`/course/content/${courseId}`, CourseContentDTO); + commit('setCourseData', course); } catch (error) { console.error('Failed to fetch course data:', error); } From 581f94123048e6482ed4caa18e90abacddf3b9e5 Mon Sep 17 00:00:00 2001 From: ahmedyoussefg <108885178+ahmedyoussefg@users.noreply.github.com> Date: Wed, 18 Dec 2024 02:06:03 +0200 Subject: [PATCH 18/18] Make requiresAuth = true in course content route --- frontend/src/router/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index f99e065..633ea61 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -40,7 +40,7 @@ const routes = [ path: "/course/content/:id", name: "CourseContentPage", component: () => import("../pages/CourseContentPage.vue"), - meta: { requiresAuth: false }, // TODO: temporary + meta: { requiresAuth: true }, props: true, // To pass `id` as a prop to the component }, ];