refactor: goodbye Vue 👋
This commit is contained in:
parent
e94e9d2b06
commit
253a2bd260
@ -54,8 +54,5 @@
|
||||
"stock/dashboard/item_dashboard.html",
|
||||
"stock/dashboard/item_dashboard_list.html",
|
||||
"stock/dashboard/item_dashboard.js"
|
||||
],
|
||||
"js/lms.min.js": [
|
||||
"public/js/education/lms/lms.js"
|
||||
]
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
frappe.ready(() => {
|
||||
frappe.provide('lms');
|
||||
|
||||
lms.call = (method, args) => {
|
||||
const method_path = 'erpnext.www.lms_legacy.' + method;
|
||||
return new Promise((resolve, reject) => {
|
||||
return frappe.call({
|
||||
method: method_path,
|
||||
args,
|
||||
})
|
||||
.then(r => resolve(r.message))
|
||||
.fail(reject);
|
||||
});
|
||||
};
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<ContentTitle :title="contentData.title" :author="contentData.author" :publishDate="contentData.publish_date">
|
||||
<slot></slot>
|
||||
</ContentTitle>
|
||||
<section class="article-content-section">
|
||||
<div>
|
||||
<div class="content" v-html="contentData.content"></div>
|
||||
<div class="text-right">
|
||||
</div>
|
||||
<div class="mt-3 text-right">
|
||||
<a class="text-muted" href="/report"><i class="octicon octicon-issue-opened" title="Report"></i> Report a
|
||||
Mistake</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ContentTitle from './ContentTitle.vue'
|
||||
export default {
|
||||
props: ['content', 'type'],
|
||||
name: 'Article',
|
||||
data() {
|
||||
return {
|
||||
contentData: ''
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getContent().then(data => this.contentData = data);
|
||||
},
|
||||
methods: {
|
||||
getContent() {
|
||||
return lms.call('get_content', {
|
||||
content_type: this.type,
|
||||
content: this.content
|
||||
})
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ContentTitle
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,56 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li v-for="(route, index) in routeData" class="breadcrumb-item active" aria-current="page">
|
||||
<router-link v-if="index != routeData.length - 1" :to="route.route">
|
||||
{{ route.label }}
|
||||
</router-link>
|
||||
<span v-else>{{ route.label }}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/javascript">
|
||||
export default {
|
||||
name: "Breadcrumb",
|
||||
data() {
|
||||
return {
|
||||
routeName: this.$route.name,
|
||||
routeParams: this.$route.params,
|
||||
routeData: [{
|
||||
label: "All Programs",
|
||||
route: "/List/Program"
|
||||
}]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.buildBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
buildBreadcrumb() {
|
||||
if(this.routeName == 'program') {
|
||||
return
|
||||
}
|
||||
if(this.routeName == 'course') {
|
||||
let routeObject = {
|
||||
label: this.routeParams.program_name,
|
||||
route: `/Program/${this.routeParams.program_name}`
|
||||
}
|
||||
this.routeData.push(routeObject)
|
||||
}
|
||||
if(this.routeName == 'content') {
|
||||
this.routeData.push({
|
||||
label: this.routeParams.program_name,
|
||||
route: `/Program/${this.routeParams.program_name}`
|
||||
})
|
||||
this.routeData.push({
|
||||
label: this.routeParams.course_name,
|
||||
route: `/Program/${this.routeParams.program_name}/${this.routeParams.course_name}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<button :class="classList" v-on="$listeners" v-bind="$attrs" @click="goToRoute">
|
||||
<slot></slot>
|
||||
</button>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'AButton',
|
||||
props: ['type', 'size', 'route'],
|
||||
computed: {
|
||||
classList() {
|
||||
return [
|
||||
'btn',
|
||||
'btn-' + this.type,
|
||||
'btn-' + this.size
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToRoute() {
|
||||
this.$router.push(this.route);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -1,28 +0,0 @@
|
||||
<template>
|
||||
<div class="featured-products-section py-3">
|
||||
<h5 class='featured-heading' v-html="title"></h5>
|
||||
<div class="featured-products row">
|
||||
<!-- <p class='lead text-center' v-html="description"></p> -->
|
||||
<slot name="card-list-slot"></slot>
|
||||
</div>
|
||||
<div class='mt-4 text-center'>
|
||||
<slot name="list-bottom"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props:['title', 'description'],
|
||||
name: "CardList",
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
.featured-heading {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,40 +0,0 @@
|
||||
<template>
|
||||
<div class="nav-buttons">
|
||||
<button class='btn btn-outline-secondary' @click="$router.go(-1)">Back</button>
|
||||
<button v-if="nextContent" class='btn btn-primary' @click="goNext()">Next</button>
|
||||
<button v-else class='btn btn-primary' @click="finish()">Finish Topic</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['nextContent', 'nextContentType'],
|
||||
name: 'ContentNavigation',
|
||||
methods: {
|
||||
addActivity() {
|
||||
if(this.$route.params.type != "Quiz"){
|
||||
console.log("Adding Activity")
|
||||
lms.call("add_activity",
|
||||
{
|
||||
course: this.$route.params.course_name,
|
||||
content_type: this.$route.params.type,
|
||||
content: this.$route.params.content,
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
goNext() {
|
||||
this.addActivity()
|
||||
this.$router.push({ name: 'content', params: { course: this.$route.params.course_name, type:this.nextContentType, content:this.nextContent }})
|
||||
},
|
||||
finish() {
|
||||
this.addActivity()
|
||||
this.$router.push({ name: 'course', params: { program_name: this.$route.params.program_name, course_name: this.$route.params.course_name}})
|
||||
lms.trigger('course-completed', course_name);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
@ -1,29 +0,0 @@
|
||||
<template>
|
||||
<section class='article-top-section video-section-bg'>
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2>{{ title }}</h2>
|
||||
<span v-if="typeof author !== 'undefined' || author !== null" class="text-muted">
|
||||
<span v-if="publishDate">Published on {{ publishDate }}</span>
|
||||
<span v-if="author">— {{ author }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-4 text-right">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['title', 'publishDate', 'author'],
|
||||
name: 'ContentTitle',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
@ -1,87 +0,0 @@
|
||||
<template>
|
||||
<div class="py-3 col-md-4 col-sm-12">
|
||||
<div class="card h-100">
|
||||
<div class="card-hero-img" v-if="course.hero_image" v-bind:style="{ 'background-image': 'url(' + image + ')' }"></div>
|
||||
<div v-else class="card-image-wrapper">
|
||||
<div class="image-body">{{ course.course_name }}</div>
|
||||
</div>
|
||||
<div class='card-body'>
|
||||
<h5 class="card-title">{{ course.course_name }}</h5>
|
||||
<span class="course-list text-muted" id="getting-started">
|
||||
{{ course.course_intro.substring(0,120) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class='p-3' style="display: flex; justify-content: space-between;">
|
||||
<div>
|
||||
<span v-if="complete"><i class="mr-2 text-success fa fa-check-circle" aria-hidden="true"></i>Course Complete</span>
|
||||
</div>
|
||||
<div class='text-right'>
|
||||
<a-button
|
||||
:type="'primary'"
|
||||
size="sm"
|
||||
:route="courseRoute"
|
||||
>
|
||||
{{ buttonName }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AButton from './Button.vue';
|
||||
|
||||
export default {
|
||||
props: ['course', 'program_name'],
|
||||
name: "CourseCard",
|
||||
components: {
|
||||
AButton
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
courseDetails: {},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if(lms.store.checkLogin()) this.getCourseDetails().then(data => this.courseDetails = data)
|
||||
},
|
||||
computed: {
|
||||
courseRoute() {
|
||||
return `${this.program_name}/${this.course.name}`
|
||||
},
|
||||
complete() {
|
||||
if(lms.store.checkProgramEnrollment(this.program_name)){
|
||||
if (this.courseDetails.flag === "Completed" ) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
isLogin() {
|
||||
return lms.store.checkLogin()
|
||||
},
|
||||
buttonName() {
|
||||
if(lms.store.checkProgramEnrollment(this.program_name)){
|
||||
return "Start Course"
|
||||
}
|
||||
else {
|
||||
return "Explore"
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCourseDetails() {
|
||||
return lms.call('get_student_course_details', {
|
||||
course_name: this.course.name,
|
||||
program_name: this.program_name
|
||||
})
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,85 +0,0 @@
|
||||
<template>
|
||||
<nav class="navbar navbar-light bg-white navbar-expand-lg sticky-top shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/lms">
|
||||
<span>{{ portal.title }}</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="lms#/List/Program">
|
||||
All Programs
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/lms#/Profile">
|
||||
Profile
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<!-- post login tools -->
|
||||
<li v-if="isLogin" class="nav-item dropdown logged-in" id="website-post-login" data-label="website-post-login">
|
||||
<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
||||
<span class="user-image-wrapper">
|
||||
<span class="avatar avatar-small" :title="fullName">
|
||||
<span class="avatar-frame" :style="avatarStyle" :title="fullName"></span>
|
||||
</span>
|
||||
</span>
|
||||
<span class="full-name">{{ fullName }}</span>
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<a class="dropdown-item" href="/me" rel="nofollow"> My Account </a>
|
||||
<a class="dropdown-item" href="/?cmd=web_logout" rel="nofollow"> Logout </a>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li v-else class="nav-item">
|
||||
<a class="nav-link btn-login-area" href="/login">Login</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "Home",
|
||||
data() {
|
||||
return{
|
||||
portal: {},
|
||||
avatar: frappe.user_image,
|
||||
fullName: frappe.full_name,
|
||||
isLogin: frappe.is_user_logged_in()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getPortalDetails().then(data => this.portal = data);
|
||||
},
|
||||
methods: {
|
||||
getPortalDetails() {
|
||||
return lms.call("get_portal_details")
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
avatarStyle() {
|
||||
return `background-image: url("${this.avatar}")`
|
||||
},
|
||||
// isLogin() {
|
||||
// return frappe.is_user_logged_in()
|
||||
// },
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
@ -1,83 +0,0 @@
|
||||
<template>
|
||||
<div class="py-5">
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div>
|
||||
<h3>{{ fullName }}</h3>
|
||||
<ul>
|
||||
<li class="row">
|
||||
<div class="col-md-3 col-sm-4 pr-0 text-muted">Email:</div>
|
||||
<div class="col-md-9 col-sm-8">{{ email }}</div>
|
||||
</li>
|
||||
<li v-if="joiningDate" class="row">
|
||||
<div class="col-md-3 col-sm-4 pr-0 text-muted">Date of Joining:</div>
|
||||
<div class="col-md-9 col-sm-8">{{ joiningDate }}</div>
|
||||
</li>
|
||||
<li class="row">
|
||||
<div class="col-md-3 col-sm-4 pr-0 text-muted">Programs Enrolled:</div>
|
||||
<div class="col-md-9 col-sm-8">
|
||||
<ul v-if="enrolledPrograms">
|
||||
<li v-for="program in enrolledPrograms" :key="program">{{ program }}</li>
|
||||
</ul>
|
||||
<span v-else>None</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="/update-profile" class="edit-button text-muted">Edit Profile</a>
|
||||
</div>
|
||||
</div>
|
||||
<div ></div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: ['enrolledPrograms'],
|
||||
name: "ProfileInfo",
|
||||
data() {
|
||||
return {
|
||||
avatar: frappe.user_image,
|
||||
fullName: frappe.full_name,
|
||||
abbr: frappe.get_abbr(frappe.get_cookie("full_name")),
|
||||
email: frappe.session.user,
|
||||
joiningDate: ''
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.getJoiningDate().then(data => {
|
||||
if(data) {
|
||||
this.joiningDate = lms.moment(String(data)).format('D MMMM YYYY')
|
||||
}
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
avatarStyle() {
|
||||
return `background-image: url("${this.avatar}")`
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getJoiningDate() {
|
||||
return lms.call("get_joining_date")
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.edit-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.standard-image {
|
||||
font-size: 72px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0
|
||||
}
|
||||
</style>
|
@ -1,82 +0,0 @@
|
||||
<template>
|
||||
<div class='py-3 col-md-4 col-sm-12'>
|
||||
<div class="card h-100">
|
||||
<router-link :to="'/Program/' + program.name">
|
||||
<div class="card-hero-img" v-if="program.hero_image" v-bind:style="{ 'background-image': 'url(' + image + ')' }"></div>
|
||||
<div v-else class="card-image-wrapper text-center">
|
||||
<div class="image-body">{{ program.program_name }}</div>
|
||||
</div>
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>{{ program.program_name }}</h5>
|
||||
<div class="text-muted">{{ program.description.substring(0,120) }}...</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<div class='text-right p-3'>
|
||||
<button v-if="program.intro_video" class='btn btn-light btn-sm' data-toggle="modal" data-target="#videoModal">Watch Intro</button>
|
||||
<a-button v-if="enrolled" type="dark" size="sm" :route="programPageRoute">
|
||||
{{ buttonName }}
|
||||
</a-button>
|
||||
<button v-else-if="isLogin" class='btn btn-dark btn-sm' @click="enroll()">{{ enrollButton }}</button>
|
||||
<a v-else class='btn btn-secondary btn-sm' href="/login#signup">Sign Up</a>
|
||||
</div>
|
||||
<VideoModal v-if="program.intro_video" :title="program.program_name" :video="program.intro_video"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import AButton from './Button.vue';
|
||||
import VideoModal from './VideoModal.vue';
|
||||
export default {
|
||||
props: ['program', 'enrolled'],
|
||||
name: "ProgramCard",
|
||||
data() {
|
||||
return {
|
||||
isLogin: frappe.is_user_logged_in(),
|
||||
enrollButton: 'Enroll Now',
|
||||
programRoute: { name: 'program', params: { program_name: this.program.name }},
|
||||
image: "'" + this.program.hero_image + "'"
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
enroll() {
|
||||
this.enrollButton = 'Enrolling...'
|
||||
lms.call('enroll_in_program', {
|
||||
program_name: this.program.name,
|
||||
}).then(data => {
|
||||
lms.store.updateEnrolledPrograms()
|
||||
this.$router.push(this.programRoute)
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
buttonName() {
|
||||
if(this.enrolled){
|
||||
return "Start Program"
|
||||
}
|
||||
else {
|
||||
return "Enroll"
|
||||
}
|
||||
},
|
||||
programPageRoute() {
|
||||
return this.programRoute
|
||||
},
|
||||
isEnrolled() {
|
||||
return lms.store.enrolledPrograms.includes(this.program.name)
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AButton,
|
||||
VideoModal
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
a.btn-secondary {
|
||||
color: white !important;
|
||||
}
|
||||
</style>
|
@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<div class='py-3 col-md-4 col-sm-12'>
|
||||
<div class="card h-100">
|
||||
<div class='card-body'>
|
||||
<router-link :to="'/Program/' + programData.name">
|
||||
<h5 class='card-title'>{{ programData.program }}</h5>
|
||||
</router-link>
|
||||
<span class="course-list text-muted" id="getting-started">
|
||||
Courses
|
||||
<ul class="mb-0 mt-1 list-unstyled" style="padding-left: 1.5em;">
|
||||
<li v-for="item in programData.progress" :key="item.name">
|
||||
<span v-if="item.is_complete"><i class="text-success fa fa-check-circle" aria-hidden="true"></i></span>
|
||||
<span v-else><i class="text-secondary fa fa-circle-o" aria-hidden="true"></i></span>
|
||||
{{ item.course_name }}
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<div class='p-3' style="display: flex; justify-content: space-between;">
|
||||
<div></div>
|
||||
<div class='text-right'>
|
||||
<a-button
|
||||
:type="buttonType"
|
||||
size="sm btn-block"
|
||||
:route="programRoute"
|
||||
>
|
||||
{{ buttonName }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import AButton from './Button.vue';
|
||||
export default {
|
||||
props: ['program'],
|
||||
name: "ProgressCard",
|
||||
data() {
|
||||
return {
|
||||
programData: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getProgramProgress().then(data => this.programData = data)
|
||||
},
|
||||
methods: {
|
||||
getProgramProgress() {
|
||||
return lms.call('get_program_progress', {
|
||||
program_name: this.program
|
||||
})
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
programRoute() {
|
||||
return {name: 'program', params: {program_name: this.program}}
|
||||
},
|
||||
buttonType() {
|
||||
if (this.programData.percentage == 100 ){
|
||||
return "success"
|
||||
}
|
||||
else if (this.programData.percentage == "0" ) {
|
||||
return "secondary"
|
||||
}
|
||||
else {
|
||||
return "info"
|
||||
}
|
||||
},
|
||||
buttonName() {
|
||||
if (this.programData.percentage == 100 ){
|
||||
return "Program Complete"
|
||||
}
|
||||
else {
|
||||
return `${this.programData.percentage}% Completed`
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AButton
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
@ -1,119 +0,0 @@
|
||||
<template>
|
||||
<section class="quiz-section">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2>{{ content }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<hr>
|
||||
<div id="quiz" :name="content">
|
||||
<div id="quiz-body">
|
||||
<component v-for="question in quizData" :key="question.name" v-bind:is="question.type" :question="question" @updateResponse="updateResponse" :isDisabled="isDisabled"></component>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div>
|
||||
<div v-if="isDisabled || submitted" id="post-quiz-actions" class="row">
|
||||
<div class="col-md-8 text-left">
|
||||
<span v-html="message"></span>
|
||||
</div>
|
||||
<div class="col-md-4 text-right">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else id="quiz-actions" class="text-right">
|
||||
<button class='btn btn-outline-secondary' type="reset" :disabled="isDisabled">Reset</button>
|
||||
<button class='btn btn-primary' @click="submitQuiz" type="button" :disabled="isDisabled">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 text-right">
|
||||
<a class="text-muted" href="/report"><i class="octicon octicon-issue-opened" title="Report"></i> Report a
|
||||
Mistake</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QuizSingleChoice from "./Quiz/QuizSingleChoice.vue"
|
||||
import QuizMultipleChoice from "./Quiz/QuizMultipleChoice.vue"
|
||||
|
||||
export default {
|
||||
props: ['content', 'type'],
|
||||
name: 'Quiz',
|
||||
data() {
|
||||
return {
|
||||
quizData: '',
|
||||
quizResponse: {},
|
||||
score: '',
|
||||
submitted: false,
|
||||
isDisabled: false,
|
||||
quizStatus: {},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getQuizWithoutAnswers().then(data => {
|
||||
this.quizData = data.quizData
|
||||
this.quizStatus = data.status
|
||||
this.isDisabled = data.status.is_complete
|
||||
});
|
||||
},
|
||||
components: {
|
||||
'SingleChoice': QuizSingleChoice,
|
||||
'MultipleChoice': QuizMultipleChoice
|
||||
},
|
||||
methods: {
|
||||
getQuizWithoutAnswers() {
|
||||
return lms.call("get_quiz_without_answers",
|
||||
{
|
||||
quiz_name: this.content,
|
||||
course_name: this.$route.params.course_name
|
||||
}
|
||||
)
|
||||
},
|
||||
updateResponse(res) {
|
||||
this.quizResponse[res.question] = res.option
|
||||
},
|
||||
submitQuiz() {
|
||||
lms.call("evaluate_quiz",
|
||||
{
|
||||
quiz_response: this.quizResponse,
|
||||
quiz_name: this.content,
|
||||
course: this.$route.params.course_name
|
||||
}
|
||||
).then(data => {
|
||||
this.score = data
|
||||
this.submitted = true
|
||||
this.quizResponse = null
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentComponent: function() {
|
||||
if(this.quizData.type === "MultipleChoice") {
|
||||
return 'QuizMultipleChoice'
|
||||
}
|
||||
else {
|
||||
return 'QuizSingleChoice'
|
||||
}
|
||||
},
|
||||
message: function() {
|
||||
if(this.submitted) {
|
||||
return '<h3>Your Score: <span id="result">'+ this.score +'</span></h3>'
|
||||
}
|
||||
let message = '<h4>You have exhausted all attempts for this quiz.</h4>'
|
||||
if(this.quizStatus.result == 'Pass') {
|
||||
message = "<h4>You have successfully completed this quiz.</h4>Score: " + this.quizStatus.score
|
||||
}
|
||||
return message
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
@ -1,34 +0,0 @@
|
||||
<template>
|
||||
<div class="question mt-4">
|
||||
<h5>{{ question.question }}</h5>
|
||||
<div class="options ml-2">
|
||||
<div v-for="option in question.options" :key="option.name" class="form-check pb-1">
|
||||
<input v-model="checked" class="form-check-input" type="checkbox" :name="question.name" :id="option.name" :value="option.name" @change="emitResponse(question.name, option.name)" :disabled="isDisabled">
|
||||
<label class="form-check-label" :for="option.name">
|
||||
{{ option.option }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['question', 'isDisabled'],
|
||||
name: 'QuizSingleChoice',
|
||||
data() {
|
||||
return {
|
||||
checked: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
emitResponse(q, o) {
|
||||
console.log(this.checked)
|
||||
this.$emit('updateResponse', {'question':q , 'option': this.checked, 'type': this.question.type})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
@ -1,28 +0,0 @@
|
||||
<template>
|
||||
<div class="question mt-4">
|
||||
<h5>{{ question.question }}</h5>
|
||||
<div class="options ml-2">
|
||||
<div v-for="option in question.options" :key="option.name" class="form-check pb-1">
|
||||
<input class="form-check-input" type="radio" :name="question.name" :id="option.name" :value="option.name" @change="emitResponse(question.name, option.name)" :disabled="isDisabled">
|
||||
<label class="form-check-label" :for="option.name">
|
||||
{{ option.option }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['question', 'isDisabled'],
|
||||
name: 'QuizSingleChoice',
|
||||
methods: {
|
||||
emitResponse(q, o) {
|
||||
this.$emit('updateResponse', {'question':q , 'option': o, 'type': this.question.type})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
</style>
|
@ -1,60 +0,0 @@
|
||||
<template>
|
||||
<div v-if="quizData" class='py-3 col-md-4 col-sm-12'>
|
||||
<div class="card h-100">
|
||||
<div class='card-body'>
|
||||
<h5 class='card-title'>{{ quizData.program }}</h5>
|
||||
<div v-for="attempt in quizData.quiz_attempt" :key="attempt.content" class="course-list" id="getting-started">
|
||||
<div>
|
||||
{{ attempt.content }}
|
||||
<ul v-if="attempt.is_complete">
|
||||
<li><span class="text-muted">Score: </span>{{ attempt.score }}</li>
|
||||
<li><span class="text-muted">Status: </span>{{attempt.result }}</li>
|
||||
</ul>
|
||||
<span v-else>- Unattempted</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='p-3' style="display: flex; justify-content: space-between;">
|
||||
<div></div>
|
||||
<div class='text-right'>
|
||||
<a-button
|
||||
:type="'primary'"
|
||||
size="sm btn-block"
|
||||
:route="programRoute"
|
||||
>
|
||||
Go To Program
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import AButton from './Button.vue';
|
||||
export default {
|
||||
props: ['program'],
|
||||
name: "ScoreCard",
|
||||
data() {
|
||||
return {
|
||||
quizData: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.getQuizProgress().then(data => this.quizData = data)
|
||||
},
|
||||
methods: {
|
||||
getQuizProgress() {
|
||||
return lms.call('get_quiz_progress_of_program', {
|
||||
program_name: this.program
|
||||
})
|
||||
},
|
||||
programRoute() {
|
||||
return {name: 'program', params: {program_name: this.program}}
|
||||
},
|
||||
},
|
||||
components: {
|
||||
AButton
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,27 +0,0 @@
|
||||
<template>
|
||||
<div class="hero">
|
||||
<h1 class="text-center" v-html="title"></h1>
|
||||
<p class='text-center' v-html="description"></p>
|
||||
<p class="text-center padding">
|
||||
<slot></slot>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: ['title', 'description'],
|
||||
name: "TopSection",
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.hero {
|
||||
padding-top: 50px;
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 40px;
|
||||
font-weight: 200;
|
||||
}
|
||||
</style>
|
@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<button v-if="isLoggedIn" class='btn btn-primary btn-md' @click="primaryAction()">{{ buttonName }}</button>
|
||||
<a v-else class='btn btn-primary btn-md' href="/login#signup">{{ buttonName }}</a>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "TopSectionButton",
|
||||
data() {
|
||||
return {
|
||||
buttonName: '',
|
||||
isLoggedIn: lms.store.checkLogin(),
|
||||
nextContent: '',
|
||||
nextContentType: '',
|
||||
nextCourse: '',
|
||||
link: '',
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.computeButtons()
|
||||
},
|
||||
methods: {
|
||||
computeButtons(){
|
||||
if(this.isLoggedIn){
|
||||
this.buttonName = 'Explore Programs'
|
||||
}
|
||||
else{
|
||||
this.buttonName = 'Sign Up'
|
||||
}
|
||||
},
|
||||
primaryAction() {
|
||||
if(this.$route.name == 'home'){
|
||||
this.$router.push('List/Program');
|
||||
}
|
||||
else if(this.$route.name == 'program' && lms.store.enrolledPrograms.includes(this.$route.params.program_name)){
|
||||
this.$router.push({ name: 'content', params: { program_name: this.$route.params.program_name, course: this.nextCourse, type: this.nextContentType, content: this.nextContent}})
|
||||
}
|
||||
else {
|
||||
lms.call("enroll_in_program",
|
||||
{
|
||||
program_name: this.$route.params.program_name,
|
||||
student_email_id: frappe.session.user
|
||||
}
|
||||
)
|
||||
lms.store.updateEnrolledPrograms()
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,112 +0,0 @@
|
||||
|
||||
<template>
|
||||
<div class="py-3 col-md-4 col-sm-12">
|
||||
<div class="card h-100">
|
||||
<div class="card-hero-img" v-if="topic.hero_image" v-bind:style="{ 'background-image': 'url(' + image + ')' }"></div>
|
||||
<div v-else class="card-image-wrapper">
|
||||
<div class="image-body">{{ topic.topic_name }}</div>
|
||||
</div>
|
||||
<div class='card-body'>
|
||||
<h5 class="card-title">{{ topic.topic_name }}</h5>
|
||||
<span class="course-list text-muted" id="getting-started">
|
||||
Content
|
||||
<ul class="mb-0 mt-1" style="padding-left: 1.5em;">
|
||||
<li v-for="content in topic.topic_content" :key="content.name">
|
||||
<router-link v-if="isLogin" tag="a" :class="'text-muted'" :to="{name: 'content', params:{program_name: program_name, topic:topic.name, course_name: course_name, type:content.content_type, content: content.content} }">
|
||||
{{ content.content }}
|
||||
</router-link>
|
||||
<div v-else><span style="padding-right: 0.4em"></span>{{ content.content }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="isLogin" class='p-3' style="display: flex; justify-content: space-between;">
|
||||
<div>
|
||||
<span v-if="complete"><i class="mr-2 text-success fa fa-check-circle" aria-hidden="true"></i>Course Complete</span>
|
||||
</div>
|
||||
<div class='text-right'>
|
||||
<a-button
|
||||
:type="'primary'"
|
||||
size="sm"
|
||||
:route="firstContentRoute"
|
||||
>
|
||||
{{ buttonName }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AButton from './Button.vue';
|
||||
|
||||
export default {
|
||||
props: ['topic', 'course_name', 'program_name'],
|
||||
name: "TopicCard",
|
||||
data() {
|
||||
return {
|
||||
topicDetails: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if(lms.store.checkLogin()) this.gettopicDetails().then(data => this.topicDetails = data)
|
||||
},
|
||||
components: {
|
||||
AButton
|
||||
},
|
||||
computed: {
|
||||
firstContentRoute() {
|
||||
if(lms.store.checkLogin()){
|
||||
return `/Program/${this.program_name}/${this.course_name}/${this.topic.name}/${this.topicDetails.content_type}/${this.topicDetails.content}`
|
||||
}
|
||||
else {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
complete() {
|
||||
if(lms.store.checkProgramEnrollment(this.program_name)){
|
||||
if (this.topicDetails.flag === "Completed" ) {
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
isLogin() {
|
||||
// return lms.store.checkProgramEnrollment(this.program_name)
|
||||
return lms.store.checkLogin()
|
||||
},
|
||||
buttonName() {
|
||||
if(lms.store.checkProgramEnrollment(this.program_name)){
|
||||
if (this.topicDetails.flag == 'Continue'){
|
||||
return 'Continue'
|
||||
}
|
||||
else {
|
||||
return 'Start Topic'
|
||||
}
|
||||
}
|
||||
else {
|
||||
return "Explore"
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
iconClass(content_type) {
|
||||
if(content_type == 'Video') return 'fa fa-play'
|
||||
if(content_type == 'Article') return 'fa fa-file-text-o'
|
||||
if(content_type == 'Quiz') return 'fa fa-question-circle-o'
|
||||
},
|
||||
gettopicDetails() {
|
||||
return lms.call('get_student_topic_details', {
|
||||
topic_name: this.topic.name,
|
||||
course_name: this.course_name,
|
||||
})
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,63 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class='mt-2'>
|
||||
<div>
|
||||
<div class="mt-3 row">
|
||||
<div class="col-md-8">
|
||||
<h2>{{ contentData.name }}</h2>
|
||||
<span class="text-muted">
|
||||
<i class="octicon octicon-clock" title="Duration"></i> <span v-if="contentData.duration"> {{ contentData.duration }} Mins — </span><span v-if="contentData.publish_date"> Published on {{ contentData.publish_date }}. </span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-4 text-right">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<youtube-player :url="contentData.url" class="mt-3"/>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-description-section">
|
||||
<div>
|
||||
<div class="content" v-html="contentData.description">
|
||||
</div>
|
||||
<div class="text-right hidden">
|
||||
<a class='btn btn-outline-secondary' href="/classrooms/module">Previous</a>
|
||||
<a class='btn btn-primary' href="/classrooms/module">Next</a>
|
||||
</div>
|
||||
<div class="mt-3 text-right">
|
||||
<a class="text-muted" href="/report"><i class="octicon octicon-issue-opened" title="Report"></i> Report a
|
||||
Mistake</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import YoutubePlayer from './YoutubePlayer.vue'
|
||||
|
||||
export default {
|
||||
props: ['content', 'type'],
|
||||
name: 'Video',
|
||||
data() {
|
||||
return {
|
||||
contentData: '',
|
||||
}
|
||||
},
|
||||
components: {
|
||||
YoutubePlayer
|
||||
},
|
||||
mounted() {
|
||||
this.getContent()
|
||||
.then(data => this.contentData = data)
|
||||
},
|
||||
methods: {
|
||||
getContent() {
|
||||
return lms.call('get_content', {
|
||||
content_type: this.type,
|
||||
content: this.content
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,35 +0,0 @@
|
||||
<template>
|
||||
<div class="modal" id="videoModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{{ title }}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span id="close_modal" aria-hidden="true" @click="stopVideo()">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<youtube-player :url="video"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/javascript">
|
||||
import YoutubePlayer from './YoutubePlayer.vue'
|
||||
|
||||
export default {
|
||||
name: 'VideoModal',
|
||||
props: ['title', 'video'],
|
||||
components: {
|
||||
YoutubePlayer
|
||||
},
|
||||
methods: {
|
||||
stopVideo() {
|
||||
$('.yvideo').each(function() {
|
||||
this.contentWindow.postMessage('{"event":"command","func":"stopVideo","args":""}', '*')
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<iframe class="embed-responsive-item yvideo" :src="'https://www.youtube.com/embed/' + videoID + '?version=3&enablejsapi=1'" allowfullscreen></iframe>
|
||||
</div>
|
||||
</template>
|
||||
<script type="text/javascript">
|
||||
export default {
|
||||
name: 'YoutubePlayer',
|
||||
props: ['url'],
|
||||
data() {
|
||||
return {
|
||||
videoID: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
url() {
|
||||
this.videoID = this.getVideoID(this.url)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getVideoID(link) {
|
||||
if (!Array.prototype.last){
|
||||
Array.prototype.last = function(){
|
||||
return this[this.length - 1];
|
||||
};
|
||||
};
|
||||
if (link.includes('v=')){
|
||||
return link.split('v=')[1].split('&')[0]
|
||||
}
|
||||
else if (link.includes('youtu.be')) {
|
||||
return link.split('/').last().split('?')[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,81 +0,0 @@
|
||||
import Vue from 'vue/dist/vue.js';
|
||||
import VueRouter from 'vue-router/dist/vue-router.js';
|
||||
import moment from 'moment/min/moment.min.js';
|
||||
|
||||
import lmsRoot from "./lmsRoot.vue";
|
||||
import routes from './routes';
|
||||
import './call';
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
var store = {
|
||||
enrolledPrograms: [],
|
||||
enrolledCourses: []
|
||||
};
|
||||
|
||||
// let profile_page = `<a class="dropdown-item" href="/lms#/Profile" rel="nofollow"> LMS Profile </a>`
|
||||
// document.querySelector('#website-post-login > ul').innerHTML += profile_page
|
||||
|
||||
frappe.ready(() => {
|
||||
frappe.provide('lms');
|
||||
|
||||
lms.moment = moment;
|
||||
|
||||
lms.store = new Vue({
|
||||
data: store,
|
||||
methods: {
|
||||
updateEnrolledPrograms() {
|
||||
if(this.checkLogin()) {
|
||||
lms.call("get_program_enrollments").then(data => {
|
||||
this.enrolledPrograms = data;
|
||||
});
|
||||
}
|
||||
},
|
||||
updateEnrolledCourses() {
|
||||
if(this.checkLogin()) {
|
||||
lms.call("get_all_course_enrollments").then(data => {
|
||||
this.enrolledCourses = data;
|
||||
});
|
||||
}
|
||||
},
|
||||
checkLogin() {
|
||||
return frappe.is_user_logged_in();
|
||||
},
|
||||
updateState() {
|
||||
this.checkLogin();
|
||||
this.updateEnrolledPrograms();
|
||||
this.updateEnrolledCourses();
|
||||
},
|
||||
checkProgramEnrollment(programName) {
|
||||
if(this.checkLogin()){
|
||||
if(this.enrolledPrograms) {
|
||||
if(this.enrolledPrograms.includes(programName)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
lms.view = new Vue({
|
||||
el: "#lms-app",
|
||||
router: new VueRouter({ routes }),
|
||||
template: "<lms-root/>",
|
||||
components: { lmsRoot },
|
||||
mounted() {
|
||||
lms.store.updateState();
|
||||
}
|
||||
});
|
||||
lms.view.$router.afterEach((to, from) => {
|
||||
window.scrollTo(0,0);
|
||||
});
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
<template>
|
||||
<div id="lms-root">
|
||||
<navbar></navbar>
|
||||
<main class="container my-5">
|
||||
<div class="page_content">
|
||||
<router-view :key="$route.fullPath"></router-view>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Navbar from "./components/Navbar.vue"
|
||||
export default {
|
||||
name: "lmsRoot",
|
||||
components: {
|
||||
Navbar
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
div.card-hero-img {
|
||||
height: 220px;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: rgb(250, 251, 252);
|
||||
}
|
||||
|
||||
.card-image-wrapper {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
height: 220px;
|
||||
background-color: rgb(250, 251, 252);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.image-body {
|
||||
align-self: center;
|
||||
color: #d1d8dd;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
@ -1,84 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<component v-bind:is="currentComponent" :content="content" :type="type">
|
||||
<ContentNavigation :nextContent="nextContent" :nextContentType="nextContentType"/>
|
||||
</component>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Article from "../components/Article.vue"
|
||||
import Quiz from "../components/Quiz.vue"
|
||||
import Video from "../components/Video.vue"
|
||||
import ContentNavigation from "../components/ContentNavigation.vue"
|
||||
|
||||
export default {
|
||||
props:['program_name', 'course_name', 'topic', 'type', 'content'],
|
||||
name: "ContentPage",
|
||||
data() {
|
||||
return{
|
||||
nextContent: '',
|
||||
nextContentType: '',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentComponent: function() {
|
||||
if(this.type === "Article") {
|
||||
return 'Article'
|
||||
}
|
||||
else if(this.type === "Quiz") {
|
||||
return 'Quiz'
|
||||
}
|
||||
else if(this.type === "Video") {
|
||||
return 'Video'
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getNextContent().then(data => {
|
||||
this.nextContent = data.content,
|
||||
this.nextContentType = data.content_type
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
getNextContent(){
|
||||
return lms.call("get_next_content",
|
||||
{
|
||||
current_content: this.content,
|
||||
current_content_type: this.type,
|
||||
topic: this.topic,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Article,
|
||||
Video,
|
||||
Quiz,
|
||||
ContentNavigation
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.footer-message {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.video-description-section {
|
||||
padding-top: 0em !important;
|
||||
}
|
||||
|
||||
.article-top-section {
|
||||
padding-top: 0.5em !important;
|
||||
padding-bottom: 0rem !important;
|
||||
}
|
||||
|
||||
.article-content-section {
|
||||
padding-top: 0em !important;
|
||||
}
|
||||
|
||||
.quiz-section {
|
||||
padding-top: 0.5em !important;
|
||||
padding-bottom: 0rem !important;
|
||||
}
|
||||
</style>
|
@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<breadcrumb></breadcrumb>
|
||||
<TopSection v-bind:title="course.course_name" v-bind:description="course.course_intro">
|
||||
</TopSection>
|
||||
<CardList :title="'Topics'" :description="''">
|
||||
<TopicCard slot="card-list-slot" v-for="topic in topicData" :topic="topic" :course_name="course_name" :program_name="program_name" :key="topic.name"/>
|
||||
</CardList>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import TopSection from "../components/TopSection.vue"
|
||||
import CardList from "../components/CardList.vue"
|
||||
import TopicCard from "../components/TopicCard.vue"
|
||||
import Breadcrumb from "../components/Breadcrumb.vue"
|
||||
|
||||
export default {
|
||||
props: ['program_name','course_name'],
|
||||
name: "CoursePage",
|
||||
components: {
|
||||
TopSection,
|
||||
CardList,
|
||||
TopicCard,
|
||||
Breadcrumb
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
course: {},
|
||||
topicData: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getCourseDetails().then(data => this.course = data);
|
||||
this.getTopics().then(data => this.topicData = data);
|
||||
},
|
||||
methods: {
|
||||
getCourseDetails() {
|
||||
return lms.call('get_course_details', {
|
||||
course_name: this.course_name
|
||||
});
|
||||
},
|
||||
getTopics() {
|
||||
return lms.call('get_topics', {
|
||||
course_name: this.course_name
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,48 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<TopSection :title="portal.title" :description="portal.description">
|
||||
<TopSectionButton/>
|
||||
</TopSection>
|
||||
<CardList :title="'Featured Programs'" :description="'Master ERPNext'">
|
||||
<ProgramCard slot="card-list-slot" v-for="item in featuredPrograms" :key="item.program.name" :program="item.program" :enrolled="item.is_enrolled"/>
|
||||
<AButton slot="list-bottom" :type="'primary'" :size="'md'" :route="'List/Program'">View All</AButton>
|
||||
</CardList>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Button from '../components/Button.vue';
|
||||
import TopSection from "../components/TopSection.vue"
|
||||
import CardList from "../components/CardList.vue"
|
||||
import ProgramCard from "../components/ProgramCard.vue"
|
||||
import TopSectionButton from "../components/TopSectionButton.vue"
|
||||
|
||||
export default {
|
||||
name: "Home",
|
||||
data() {
|
||||
return{
|
||||
portal: {},
|
||||
featuredPrograms: {},
|
||||
// enrolledPrograms: new Set()
|
||||
}
|
||||
},
|
||||
components: {
|
||||
AButton: Button,
|
||||
TopSection,
|
||||
CardList,
|
||||
ProgramCard,
|
||||
TopSectionButton
|
||||
},
|
||||
mounted() {
|
||||
this.getPortalDetails().then(data => this.portal = data);
|
||||
this.getFeaturedPrograms().then(data => this.featuredPrograms = data);
|
||||
},
|
||||
methods: {
|
||||
getPortalDetails() {
|
||||
return lms.call("get_portal_details")
|
||||
},
|
||||
getFeaturedPrograms() {
|
||||
return lms.call("get_featured_programs")
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<TopSection :title="'Programs at ' + portal.title" :description="portal.description">
|
||||
<AButton v-if="isLogin" :type="'primary'" :size="'lg'" :route="{ name: 'signup'}">Sign Up</AButton>
|
||||
</TopSection>
|
||||
<CardList :title="'All Programs'" :description="''">
|
||||
<ProgramCard slot="card-list-slot" v-for="item in masterData" :key="item.program.name" :program="item.program" :enrolled="item.is_enrolled"/>
|
||||
</CardList>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import ProgramCard from '../components/ProgramCard.vue';
|
||||
import CourseCard from "../components/CourseCard.vue"
|
||||
import Button from '../components/Button.vue';
|
||||
import TopSection from "../components/TopSection.vue"
|
||||
import CardList from "../components/CardList.vue"
|
||||
|
||||
|
||||
export default {
|
||||
props: ['master'],
|
||||
name: "ListPage",
|
||||
components: {
|
||||
AButton: Button,
|
||||
CourseCard,
|
||||
ProgramCard,
|
||||
CardList,
|
||||
TopSection
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
portal: {},
|
||||
masterData: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getPortalDetails().then(data => this.portal = data);
|
||||
this.getMaster().then(data => this.masterData = data);
|
||||
},
|
||||
methods: {
|
||||
getPortalDetails() {
|
||||
return lms.call("get_portal_details")
|
||||
},
|
||||
getMaster() {
|
||||
return lms.call("get_all_programs")
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isLogin() {
|
||||
return !lms.store.checkLogin()
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<ProfileInfo :enrolledPrograms="enrolledPrograms"></ProfileInfo>
|
||||
<div v-if="enrolledPrograms">
|
||||
<CardList :title="'Your Progress'" :description="''">
|
||||
<ProgressCard slot="card-list-slot" v-for="program in enrolledPrograms" :program="program" :key="program"/>
|
||||
</CardList>
|
||||
<CardList :title="''" :description="''">
|
||||
<ScoreCard slot="card-list-slot" v-for="program in enrolledPrograms" :program="program" :key="program"/>
|
||||
</CardList>
|
||||
</div>
|
||||
<div v-else>
|
||||
You haven't enrolled in any programs yet.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Button from '../components/Button.vue';
|
||||
import TopSection from "../components/TopSection.vue"
|
||||
import CardList from "../components/CardList.vue"
|
||||
import ProgressCard from "../components/ProgressCard.vue"
|
||||
import ProfileInfo from "../components/ProfileInfo.vue"
|
||||
import ScoreCard from "../components/ScoreCard.vue"
|
||||
|
||||
export default {
|
||||
name: "ProfilePage",
|
||||
components: {
|
||||
AButton: Button,
|
||||
TopSection,
|
||||
CardList,
|
||||
ProfileInfo,
|
||||
ProgressCard,
|
||||
ScoreCard
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
enrolledPrograms: {},
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getEnrolledPrograms().then(data => this.enrolledPrograms = data);
|
||||
},
|
||||
methods: {
|
||||
getEnrolledPrograms() {
|
||||
return lms.call("get_program_enrollments")
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<breadcrumb></breadcrumb>
|
||||
<TopSection v-bind:title="program.program_name" v-bind:description="program.description">
|
||||
</TopSection>
|
||||
<CardList :title="'Courses'" :description="''">
|
||||
<CourseCard slot="card-list-slot" v-for="course in courseData" :course="course" :program_name="program_name" :key="course.name"/>
|
||||
</CardList>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import TopSection from "../components/TopSection.vue"
|
||||
import CardList from "../components/CardList.vue"
|
||||
import CourseCard from "../components/CourseCard.vue"
|
||||
import Breadcrumb from "../components/Breadcrumb.vue"
|
||||
|
||||
export default {
|
||||
props: ['program_name'],
|
||||
name: "ProgramPage",
|
||||
components: {
|
||||
TopSection,
|
||||
CardList,
|
||||
CourseCard,
|
||||
Breadcrumb
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
program: {},
|
||||
courseData: [],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getProgramDetails().then(data => this.program = data);
|
||||
this.getCourses().then(data => this.courseData = data);
|
||||
},
|
||||
methods: {
|
||||
getProgramDetails() {
|
||||
return lms.call('get_program', {
|
||||
program_name: this.program_name
|
||||
});
|
||||
},
|
||||
getCourses() {
|
||||
return lms.call('get_courses', {
|
||||
program_name: this.program_name
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -1,92 +0,0 @@
|
||||
import Home from "./pages/Home.vue";
|
||||
import ProgramPage from "./pages/ProgramPage.vue";
|
||||
import CoursePage from "./pages/CoursePage.vue";
|
||||
import ContentPage from "./pages/ContentPage.vue";
|
||||
import ListPage from "./pages/ListPage.vue";
|
||||
import ProfilePage from "./pages/ProfilePage.vue";
|
||||
|
||||
const routes = [{
|
||||
name: 'home',
|
||||
path: '',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
name: 'program',
|
||||
path: '/Program/:program_name',
|
||||
component: ProgramPage,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
name: 'course',
|
||||
path: '/Program/:program_name/:course_name/',
|
||||
component: CoursePage,
|
||||
props: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
path: '/Program/:program_name/:course_name/:topic/:type/:content',
|
||||
component: ContentPage,
|
||||
props: true,
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
if (lms.store.checkProgramEnrollment(to.params.program_name)) {
|
||||
next();
|
||||
} else {
|
||||
next({
|
||||
name: 'program',
|
||||
params: {
|
||||
program_name: to.params.program_name
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'list',
|
||||
path: '/List/:master',
|
||||
component: ListPage,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
name: 'signup',
|
||||
path: '/Signup',
|
||||
beforeEnter(to, from, next) {
|
||||
window.location = window.location.origin.toString() + '/login#signup';
|
||||
},
|
||||
component: Home,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
name: 'login',
|
||||
path: '/Login',
|
||||
beforeEnter(to, from, next) {
|
||||
window.location = window.location.origin.toString() + '/login#login';
|
||||
},
|
||||
component: Home,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
name: 'logout',
|
||||
path: '/Logout',
|
||||
beforeEnter(to, from, next) {
|
||||
window.location = window.location.origin.toString() + '/?cmd=web_logout';
|
||||
},
|
||||
component: Home,
|
||||
props: true
|
||||
},
|
||||
{
|
||||
name: 'profile',
|
||||
path: '/Profile',
|
||||
component: ProfilePage,
|
||||
props: true,
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (!lms.store.checkLogin()) {
|
||||
next({
|
||||
name: 'home'
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
export default routes;
|
Loading…
x
Reference in New Issue
Block a user