mirror of
https://github.com/frappe/lms.git
synced 2026-05-02 13:39:31 +03:00
refactor: sidebar visibility of programs
This commit is contained in:
@@ -196,7 +196,7 @@ import { usersStore } from '@/stores/user'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
import { useSidebar } from '@/stores/sidebar'
|
||||
import { useSettings } from '@/stores/settings'
|
||||
import { Button, createResource, Tooltip } from 'frappe-ui'
|
||||
import { Button, call, createResource, Tooltip } from 'frappe-ui'
|
||||
import PageModal from '@/components/Modals/PageModal.vue'
|
||||
import { capture } from '@/telemetry'
|
||||
import LMSLogo from '@/components/Icons/LMSLogo.vue'
|
||||
@@ -214,6 +214,7 @@ import {
|
||||
Users,
|
||||
BookText,
|
||||
Zap,
|
||||
Check,
|
||||
} from 'lucide-vue-next'
|
||||
import {
|
||||
TrialBanner,
|
||||
@@ -360,7 +361,9 @@ const addProgrammingExercises = () => {
|
||||
}
|
||||
}
|
||||
|
||||
const addPrograms = () => {
|
||||
const addPrograms = async () => {
|
||||
let canAddProgram = await checkIfCanAddProgram()
|
||||
if (!canAddProgram) return
|
||||
let activeFor = ['Programs', 'ProgramDetail']
|
||||
let index = 1
|
||||
|
||||
@@ -372,6 +375,14 @@ const addPrograms = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const checkIfCanAddProgram = async () => {
|
||||
if (isModerator.value || isInstructor.value) {
|
||||
return true
|
||||
}
|
||||
const programs = await call('lms.lms.utils.get_programs')
|
||||
return programs.enrolled.length > 0 || programs.published.length > 0
|
||||
}
|
||||
|
||||
const openPageModal = (link) => {
|
||||
showPageModal.value = true
|
||||
pageToEdit.value = link
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
<script setup>
|
||||
import { getSidebarLinks } from '@/utils'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { call } from 'frappe-ui'
|
||||
import { watch, ref, onMounted } from 'vue'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
import { useSettings } from '@/stores/settings'
|
||||
@@ -71,6 +72,8 @@ const sidebarLinks = ref(getSidebarLinks())
|
||||
const otherLinks = ref([])
|
||||
const showMenu = ref(false)
|
||||
const menu = ref(null)
|
||||
const isModerator = ref(false)
|
||||
const isInstructor = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
sidebarSettings.reload(
|
||||
@@ -134,12 +137,15 @@ const addOtherLinks = () => {
|
||||
}
|
||||
|
||||
watch(userResource, () => {
|
||||
if (
|
||||
userResource.data &&
|
||||
(userResource.data.is_moderator || userResource.data.is_instructor)
|
||||
) {
|
||||
addQuizzes()
|
||||
addAssignments()
|
||||
if (userResource.data) {
|
||||
isModerator.value = userResource.data.is_moderator
|
||||
isInstructor.value = userResource.data.is_instructor
|
||||
addPrograms()
|
||||
if (isModerator.value || isInstructor.value) {
|
||||
addProgrammingExercises()
|
||||
addQuizzes()
|
||||
addAssignments()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -159,6 +165,28 @@ const addAssignments = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const addPrograms = async () => {
|
||||
let canAddProgram = await checkIfCanAddProgram()
|
||||
if (!canAddProgram) return
|
||||
let activeFor = ['Programs', 'ProgramDetail']
|
||||
let index = 1
|
||||
|
||||
sidebarLinks.value.splice(index, 0, {
|
||||
label: 'Programs',
|
||||
icon: 'Route',
|
||||
to: 'Programs',
|
||||
activeFor: activeFor,
|
||||
})
|
||||
}
|
||||
|
||||
const checkIfCanAddProgram = async () => {
|
||||
if (isModerator.value || isInstructor.value) {
|
||||
return true
|
||||
}
|
||||
const programs = await call('lms.lms.utils.get_programs')
|
||||
return programs.enrolled.length > 0 || programs.published.length > 0
|
||||
}
|
||||
|
||||
let isActive = (tab) => {
|
||||
return tab.activeFor?.includes(router.currentRoute.value.name)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="text-lg font-semibold text-ink-gray-9 mb-5">
|
||||
{{ __('{0} Programs').format(programs.data.length) }}
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-5">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-5">
|
||||
<div
|
||||
v-for="program in programs.data"
|
||||
@click="openForm(program.name)"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="py-10 w-3/4 mx-auto">
|
||||
<div class="py-5 px-5 w-full lg:w-3/4 lg:px-0 mx-auto">
|
||||
<div class="flex items-center justify-between mb-5">
|
||||
<div class="text-lg text-ink-gray-9 font-semibold">
|
||||
{{ __('All Programs') }}
|
||||
@@ -8,7 +8,10 @@
|
||||
</div>
|
||||
<div v-for="(data, category) in programs.data">
|
||||
<div v-if="category == currentTab">
|
||||
<div v-if="data.length > 0" class="grid grid-cols-3 gap-5">
|
||||
<div
|
||||
v-if="data.length > 0"
|
||||
class="grid grid-cols-1 lg:grid-cols-3 gap-5"
|
||||
>
|
||||
<div
|
||||
v-for="program in data"
|
||||
@click="openDetails(program.name, category)"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
from lms.lms.doctype.lms_enrollment.lms_enrollment import update_program_progress
|
||||
from lms.lms.utils import get_course_progress
|
||||
|
||||
|
||||
@@ -19,3 +20,4 @@ class LMSCourseProgress(Document):
|
||||
"name",
|
||||
)
|
||||
frappe.db.set_value("LMS Enrollment", membership, "progress", progress)
|
||||
update_program_progress(self.member)
|
||||
|
||||
@@ -13,7 +13,7 @@ class LMSEnrollment(Document):
|
||||
self.validate_membership_in_different_batch_same_course()
|
||||
|
||||
def on_update(self):
|
||||
self.update_program_progress()
|
||||
update_program_progress(self.member)
|
||||
|
||||
def validate_membership_in_same_batch(self):
|
||||
filters = {"member": self.member, "course": self.course, "name": ["!=", self.name]}
|
||||
@@ -59,21 +59,20 @@ class LMSEnrollment(Document):
|
||||
)
|
||||
)
|
||||
|
||||
def update_program_progress(self):
|
||||
programs = frappe.get_all("LMS Program Member", {"member": self.member}, ["parent", "name"])
|
||||
|
||||
for program in programs:
|
||||
total_progress = 0
|
||||
courses = frappe.get_all("LMS Program Course", {"parent": program.parent}, pluck="course")
|
||||
for course in courses:
|
||||
progress = frappe.db.get_value(
|
||||
"LMS Enrollment", {"course": course, "member": self.member}, "progress"
|
||||
)
|
||||
progress = progress or 0
|
||||
total_progress += progress
|
||||
def update_program_progress(member):
|
||||
programs = frappe.get_all("LMS Program Member", {"member": member}, ["parent", "name"])
|
||||
|
||||
average_progress = ceil(total_progress / len(courses))
|
||||
frappe.db.set_value("LMS Program Member", program.name, "progress", average_progress)
|
||||
for program in programs:
|
||||
total_progress = 0
|
||||
courses = frappe.get_all("LMS Program Course", {"parent": program.parent}, pluck="course")
|
||||
for course in courses:
|
||||
progress = frappe.db.get_value("LMS Enrollment", {"course": course, "member": member}, "progress")
|
||||
progress = progress or 0
|
||||
total_progress += progress
|
||||
|
||||
average_progress = ceil(total_progress / len(courses))
|
||||
frappe.db.set_value("LMS Program Member", program.name, "progress", average_progress)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"published",
|
||||
"title",
|
||||
"published",
|
||||
"column_break_cwjx",
|
||||
"enforce_course_order",
|
||||
"column_break_mikl",
|
||||
@@ -44,12 +44,16 @@
|
||||
"default": "0",
|
||||
"fieldname": "published",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Published"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enforce_course_order",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Enforce Course Order"
|
||||
},
|
||||
{
|
||||
@@ -67,6 +71,7 @@
|
||||
{
|
||||
"fieldname": "course_count",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Course Count"
|
||||
},
|
||||
{
|
||||
@@ -76,6 +81,7 @@
|
||||
{
|
||||
"fieldname": "member_count",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Member Count"
|
||||
},
|
||||
{
|
||||
@@ -86,7 +92,7 @@
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-08-19 17:31:23.516060",
|
||||
"modified": "2025-08-20 12:28:57.238902",
|
||||
"modified_by": "sayali@frappe.io",
|
||||
"module": "LMS",
|
||||
"name": "LMS Program",
|
||||
@@ -143,5 +149,6 @@
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
|
||||
+3
-1
@@ -1937,9 +1937,11 @@ def get_programs():
|
||||
["name", "course_count", "member_count"],
|
||||
)
|
||||
|
||||
programs_to_remove = []
|
||||
for program in published_programs:
|
||||
if program.name in [p.name for p in enrolled_programs]:
|
||||
published_programs.remove(program)
|
||||
programs_to_remove.append(program)
|
||||
published_programs = [program for program in published_programs if program not in programs_to_remove]
|
||||
|
||||
return {
|
||||
"enrolled": enrolled_programs,
|
||||
|
||||
Reference in New Issue
Block a user