Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[KTP-47] Basic Front End For Course Contents Page (Student View) #27

Merged
merged 23 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c134197
Implement basic front end for Course Contents Page (student)
ahmedyoussefg Dec 16, 2024
f1b76a9
Implement basic front end for Course Contents Page (student)
ahmedyoussefg Dec 16, 2024
41be282
Merge branch 'ktp-47-student-course-page' of github.com:ahmedyoussefg…
ahmedyoussefg Dec 16, 2024
4254e7f
Change all `videoUrl` to `lessonContent`
ahmedyoussefg Dec 17, 2024
951489d
isCompleted checks appear in lessons & modules
ahmedyoussefg Dec 17, 2024
b16037d
Add progress bar
ahmedyoussefg Dec 17, 2024
1dfea79
Add non functional view of mark as completed
ahmedyoussefg Dec 17, 2024
ec26122
Change course content route to /course/content
ahmedyoussefg Dec 17, 2024
3bf5cde
Fix Mark As Completed Button
ahmedyoussefg Dec 17, 2024
d1b8bc2
Implement basic front end for Course Contents Page (student)
ahmedyoussefg Dec 16, 2024
3397912
Change all `videoUrl` to `lessonContent`
ahmedyoussefg Dec 17, 2024
3cb48c9
isCompleted checks appear in lessons & modules
ahmedyoussefg Dec 17, 2024
6bdedad
Add progress bar
ahmedyoussefg Dec 17, 2024
5679d6f
Add non functional view of mark as completed
ahmedyoussefg Dec 17, 2024
e2b377b
Change course content route to /course/content
ahmedyoussefg Dec 17, 2024
d515579
Fix Mark As Completed Button
ahmedyoussefg Dec 17, 2024
9d70af2
Merge branch 'ktp-47-student-course-page' of github.com:ahmedyoussefg…
ahmedyoussefg Dec 17, 2024
254d69f
Add API endpoint for mark lesson as completed in Front End
ahmedyoussefg Dec 17, 2024
a748d9b
Add endpoints for course content
ahmedyoussefg Dec 17, 2024
5c395c7
Merge pull request #33 from ahmedyoussefg/ktp-66-student-course-api-f…
ahmedyoussefg Dec 17, 2024
109d01c
Merge branch 'devel' into ktp-47-student-course-page
ahmedyoussefg Dec 17, 2024
f68714f
Merge branch 'devel' into ktp-47-student-course-page
ahmedyoussefg Dec 17, 2024
581f941
Make requiresAuth = true in course content route
ahmedyoussefg Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>logo.png">
<title><%= htmlWebpackPlugin.options.title %></title>
<title>Knowtopia</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
<strong>We're sorry but Knowtopia doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<template>
<div id="app">
<HeaderComponent />
<HeaderComponent/>
<router-view />
<FooterComponent />
</div>
</template>

<script>
import HeaderComponent from "./components/HeaderComponent.vue";
import FooterComponent from "./components/FooterComponent.vue";
import HeaderComponent from './components/HeaderComponent.vue';
import FooterComponent from './components/FooterComponent.vue';

export default {
components: {
Expand Down
Binary file added frontend/src/assets/img/green-check.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/src/assets/img/grey-check.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 13 additions & 4 deletions frontend/src/components/FooterComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@
<div class="footer-warp">
<div class="row">
<div class="widget-item">
<h4>Contact Info</h4>
<h4>Knowtopia Links</h4>
<ul class="contact-list">
<li>hhhhh</li>
<li>hhhhh</li>
<li>hhhhh</li>
<li>
<strong>Jira:</strong>
<a href="https://knowtopia.atlassian.net/jira" target="_blank">Jira</a>
</li>
<li>
<strong>Confluence:</strong>
<a href="https://knowtopia.atlassian.net/wiki" target="_blank">Confluence</a>
</li>
<li>
<strong>GitHub:</strong>
<a href="https://github.com/ahmedyoussef/knowtopia" target="_blank">GitHub</a>
</li>
</ul>
</div>
</div>
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/components/HeaderComponent.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<header class="header-section">
<!-- Check computed section below for header class name -->
<header :class="headerClass">
<div class="container">
<div class="row">
<div class="col-lg-3 col-md-3">
Expand Down Expand Up @@ -54,6 +55,11 @@ import { authState } from "@/services/authState";
import { logout } from "@/services/authApi";

export default {
computed : {
headerClass() {
return this.$route.name === 'CourseContentPage' ? 'thin-header-section' : 'header-section';
}
},
setup() {
return { authState, logout };
},
Expand Down
52 changes: 52 additions & 0 deletions frontend/src/components/LessonList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<template>
<ul class="lesson-list">
<LessonItem
v-for="(lesson, lessonIndex) in lessons"
:key="lessonIndex"
:lesson="lesson"
@selectLesson="$emit('selectLesson', $event)"
/>
</ul>
</template>

<script>
import LessonItem from "@/components/LessonListItem.vue";

export default {
props: {
lessons: Array,
},
components: { LessonItem },
};
</script>

<style>
.lesson-list {
list-style: none;
margin: 0;
padding-left: 20px;
}

.lesson-item {
padding: 10px 15px;
margin-bottom: 8px;
border: 1px solid #ddd;
border-radius: 6px;
transition: background-color 0.3s, transform 0.3s;
cursor: pointer;
}

.lesson-item:hover {
background-color: #f9f9f9;
transform: translateY(-2px);
}

.lesson-item:active {
transform: translateY(0);
}

.lesson-item:last-child {
margin-bottom: 0;
}
</style>

60 changes: 60 additions & 0 deletions frontend/src/components/LessonListItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<li class="lesson-item" @click="selectLesson">
<span class="lesson-status">
<img
:src="lesson.isCompleted ? require('@/assets/img/green-check.png') : require('@/assets/img/grey-check.png')"
alt="completion status"
class="status-icon"
/>
</span>
{{ lesson.title }}
</li>
</template>

<script>
export default {
props: {
lesson: Object,
},
methods: {
selectLesson() {
this.$emit("selectLesson", this.lesson);
},
},
};
</script>

<style>
.lesson-item {
margin-top: 1vh;
cursor: pointer;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 6px;
margin-bottom: 8px;
transition: background-color 0.3s ease, transform 0.2s ease;
}

.lesson-item:hover {
background-color: #f0f0f0;
transform: scale(1.02);
}

.lesson-item:active {
transform: scale(0.98);
}

.lesson-item:last-child {
margin-bottom: 0;
}

.lesson-status {
margin-right: 10px;
}

.status-icon {
width: 20px;
height: 20px;
}
</style>

35 changes: 35 additions & 0 deletions frontend/src/components/ModuleList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<template>
<div>
<ModuleListItem
v-for="(module,moduleIndex) in modules"
:key="moduleIndex"
:module="module"
@selectLesson="$emit('selectLesson', $event)"
/>
</div>
</template>

<script>
import ModuleListItem from "@/components/ModuleListItem.vue";

export default {
props: {
modules: Array,
},
components: { ModuleListItem },
};
</script>

<style scoped>
.module-list {
display: flex;
flex-direction: column;
gap: 15px;
padding: 20px;
}

.module-list .module-item:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
</style>
97 changes: 97 additions & 0 deletions frontend/src/components/ModuleListItem.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<template>
<div class="module-item">
<div class="module-header" @click="toggleExpand">
<img
v-if="allLessonsCompleted"
:src="require('@/assets/img/green-check.png')"
alt="All lessons completed"
class="module-completed-icon"
/>
<h3>{{ module.title }}</h3>
<span>{{ expanded ? "-" : "+" }}</span>
</div>
<LessonList
v-if="expanded"
:lessons="module.lessons"
@selectLesson="$emit('selectLesson', $event)"
/>
</div>
</template>

<script>
import LessonList from "@/components/LessonList.vue";

export default {
props: {
module: Object,
},
computed: {
allLessonsCompleted() {
return this.module.lessons.every((lesson) => lesson.isCompleted);
},
},
data() {
return {
expanded: false,
};
},
methods: {
toggleExpand() {
this.expanded = !this.expanded;
},
},
components: { LessonList },
};
</script>

<style>
.module-item {
margin: 15px 0;
padding: 15px; /* Increased padding for better spacing */
border: 1px solid #ddd;
border-radius: 10px; /* Slightly more rounded corners */
background-color: #fafafa;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); /* Slightly larger shadow for better depth */
transition: background-color 0.3s ease, transform 0.3s ease; /* Added transform for hover effect */
}

.module-item:hover {
background-color: #f0f0f0;
transform: translateY(-5px); /* Slight lift on hover for interactivity */
}

.module-header {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 24px; /* Adjusted padding for better balance */
background: #2196f3; /* Kept the blue for consistency */
color: white;
border-radius: 8px; /* Slightly more rounded for a softer look */
font-size: 17px; /* Slightly larger font size */
font-weight: 600;
transition: background 0.3s ease, transform 0.3s ease; /* Added transition for scaling */
}

.module-header:hover {
background: #1976d2; /* Darker blue on hover */
transform: scale(1.03); /* Subtle scaling effect on hover */
}

.module-header h3 {
color: rgb(255, 255, 255);
font-family: "verdana", sans-serif;
}
.module-header span {
font-size: 18px;
font-weight: bold;
margin-left: 12px; /* Increased spacing between text and icon */
}

.module-completed-icon {
margin-left: 10px;
width: 20px;
height: 20px;
}
</style>
27 changes: 27 additions & 0 deletions frontend/src/components/VideoPlayer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<template>
<div class="video-player">
<div v-if="lessonContent">
<p>Video URL:</p>
<a :href="lessonContent" target="_blank">{{ lessonContent }}</a>
</div>
<div v-else>
<p>Select a lesson to view the video.</p>
</div>
</div>
</template>

<script>
export default {
props: {
lessonContent: String,
},
};
</script>

<style>
.video-player {
text-align: center;
margin-top: 20px;
}
</style>

Loading
Loading