feat: program restrictions

This commit is contained in:
Jannat Patel
2024-11-21 17:10:24 +05:30
parent 582c7af12d
commit 64ed0b3e94
14 changed files with 190 additions and 137 deletions

View File

@@ -99,6 +99,7 @@ import { getSidebarLinks } from '../utils'
import { usersStore } from '@/stores/user'
import { sessionStore } from '@/stores/session'
import { useSidebar } from '@/stores/sidebar'
import { useSettings } from '@/stores/settings'
import { ChevronRight, Plus } from 'lucide-vue-next'
import { createResource, Button } from 'frappe-ui'
import PageModal from '@/components/Modals/PageModal.vue'
@@ -114,6 +115,7 @@ const isModerator = ref(false)
const isInstructor = ref(false)
const pageToEdit = ref(null)
const showWebPages = ref(false)
const settingsStore = useSettings()
onMounted(() => {
socket.on('publish_lms_notifications', (data) => {
@@ -184,12 +186,23 @@ const addQuizzes = () => {
}
const addPrograms = () => {
if (isInstructor.value || isModerator.value) {
sidebarLinks.value.push({
if (settingsStore.learningPaths.data) {
let activeFor = ['Programs', 'ProgramForm']
let index = 1
if (!isInstructor.value && !isModerator.value) {
sidebarLinks.value = sidebarLinks.value.filter(
(link) => link.label !== 'Courses'
)
activeFor.push('CourseDetail')
activeFor.push('Lesson')
index = 0
}
sidebarLinks.value.splice(index, 0, {
label: 'Programs',
icon: 'Route',
to: 'Programs',
activeFor: ['Programs', 'ProgramForm'],
activeFor: activeFor,
})
}
}

View File

@@ -303,9 +303,9 @@ const trashChapter = (chapterName) => {
}
const redirectToChapter = (chapter) => {
if (!chapter.is_scorm_package) return
event.preventDefault()
if (props.allowEdit) return
if (!chapter.is_scorm_package) return
if (!user.data) {
showToast(
__('You are not enrolled'),

View File

@@ -397,6 +397,9 @@ const attempts = createResource({
watch(
() => quiz.data,
() => {
if (quiz.data) {
populateQuestions()
}
if (quiz.data && quiz.data.max_attempts) {
attempts.reload()
resetQuiz()

View File

@@ -173,12 +173,14 @@ import { BookOpen, Plus, Search } from 'lucide-vue-next'
import { ref, computed, inject, onMounted, watch } from 'vue'
import { updateDocumentTitle } from '@/utils'
import { useRouter } from 'vue-router'
import { useSettings } from '@/stores/settings'
const user = inject('$user')
const searchQuery = ref('')
const currentCategory = ref(null)
const hasCourses = ref(false)
const router = useRouter()
const settings = useSettings()
onMounted(() => {
checkLearningPath()
@@ -189,14 +191,12 @@ onMounted(() => {
})
const checkLearningPath = () => {
call('frappe.client.get_single_value', {
doctype: 'LMS Settings',
field: 'enable_learning_paths',
}).then((res) => {
if (res && !user.data?.is_moderator && !user.data?.is_instructor) {
router.push({ name: 'Programs' })
}
})
if (
settings.learningPaths.data &&
(!user.data?.is_moderator || !user.data?.is_instructor)
) {
router.push({ name: 'Programs' })
}
}
const courses = createResource({

View File

@@ -211,8 +211,6 @@ const program = createDocumentResource({
cache: ['program', props.programName],
})
console.log(program)
const addProgramCourse = () => {
program.setValue.submit(
{
@@ -288,7 +286,6 @@ const updateOrder = (e) => {
course.idx = index + 1
})
console.log(courses)
program.setValue.submit(
{
program_courses: courses,

View File

@@ -15,15 +15,27 @@
</Button>
</header>
<div v-if="programs.data?.length" class="pt-5 px-5">
<div v-for="program in programs.data" class="mb-10">
<div v-for="program in programs.data" class="mb-20">
<div class="flex items-center justify-between">
<div class="text-xl font-semibold">
{{ program.name }}
</div>
<div class="flex items-center space-x-2">
<Badge v-if="program.members" variant="subtle" theme="green">
{{ program.members }} {{ __('Members') }}
<Badge
v-if="program.members"
variant="subtle"
theme="green"
size="lg"
>
{{ program.members }}
{{
program.members == 1 ? __(singularize('members')) : __('members')
}}
</Badge>
<Badge variant="subtle" theme="blue" size="lg">
{{ program.progress }}{{ __('% completed') }}
</Badge>
<router-link
v-if="user.data?.is_moderator || user.data?.is_instructor"
:to="{
@@ -44,35 +56,12 @@
v-if="program.courses?.length"
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 mt-5"
>
<router-link
<CourseCard
v-for="course in program.courses"
:to="
course.membership && course.current_lesson
? {
name: 'Lesson',
params: {
courseName: course.name,
chapterNumber: course.current_lesson.split('-')[0],
lessonNumber: course.current_lesson.split('-')[1],
},
}
: course.membership
? {
name: 'Lesson',
params: {
courseName: course.name,
chapterNumber: 1,
lessonNumber: 1,
},
}
: {
name: 'CourseDetail',
params: { courseName: course.name },
}
"
>
<CourseCard :course="course" />
</router-link>
:course="course"
@click="enrollMember(program.name, course.name)"
class="cursor-pointer"
/>
</div>
<div v-else class="text-sm italic text-gray-600 mt-4">
{{ __('No courses in this program') }}
@@ -128,6 +117,7 @@ import { computed, inject, ref } from 'vue'
import { BookOpen, Edit, Plus } from 'lucide-vue-next'
import CourseCard from '@/components/CourseCard.vue'
import { useRouter } from 'vue-router'
import { showToast, singularize } from '@/utils'
const user = inject('$user')
const showDialog = ref(false)
@@ -140,8 +130,6 @@ const programs = createResource({
cache: 'programs',
})
console.log(programs)
const createProgram = (close) => {
call('frappe.client.insert', {
doc: {
@@ -153,6 +141,37 @@ const createProgram = (close) => {
})
}
const enrollMember = (program, course) => {
call('lms.lms.utils.enroll_in_program_course', {
program: program,
course: course,
})
.then((data) => {
if (data.current_lesson) {
router.push({
name: 'Lesson',
params: {
courseName: course,
chapterNumber: data.current_lesson.split('-')[0],
lessonNumber: data.current_lesson.split('-')[1],
},
})
} else if (data) {
router.push({
name: 'Lesson',
params: {
courseName: course,
chapterNumber: 1,
lessonNumber: 1,
},
})
}
})
.catch((err) => {
showToast('Error', err.messages?.[0] || err, 'x')
})
}
const breadbrumbs = computed(() => [
{
label: 'Programs',

View File

@@ -1,12 +1,25 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { createResource } from 'frappe-ui'
export const useSettings = defineStore('settings', () => {
const isSettingsOpen = ref(false)
const activeTab = ref(null)
const learningPaths = createResource({
url: 'frappe.client.get_single_value',
makeParams(values) {
return {
doctype: 'LMS Settings',
field: 'enable_learning_paths',
}
},
auto: true,
cache: ['learningPaths'],
})
return {
isSettingsOpen,
activeTab,
learningPaths,
}
})

View File

@@ -438,8 +438,6 @@ export function getSidebarLinks() {
'Lesson',
'CourseForm',
'LessonForm',
'Programs',
'ProgramForm',
],
},
{