diff --git a/frontend/src/components/Sidebar/AppSidebar.vue b/frontend/src/components/Sidebar/AppSidebar.vue index b51e72a5..cdc8c94e 100644 --- a/frontend/src/components/Sidebar/AppSidebar.vue +++ b/frontend/src/components/Sidebar/AppSidebar.vue @@ -9,11 +9,21 @@ >
-
- +
+
+ {{ __(link.label) }} +
+
{ - addNotifications() - setSidebarLinks() setUpOnboarding() addKeyboardShortcut() socket.on('publish_lms_notifications', (data) => { @@ -278,9 +281,14 @@ const setSidebarLinks = () => { onSuccess(data) { Object.keys(data).forEach((key) => { if (!parseInt(data[key])) { - sidebarLinks.value = sidebarLinks.value.filter( + sidebarLinks.value.forEach((link) => { + link.items = link.items.filter( + (item) => item.label.toLowerCase().split(' ').join('_') !== key + ) + }) + /* sidebarLinks.value = sidebarLinks.value?.items.filter( (link) => link.label.toLowerCase().split(' ').join('_') !== key - ) + ) */ } }) }, @@ -319,85 +327,16 @@ const unreadNotifications = createResource({ }, onSuccess(data) { unreadCount.value = data - sidebarLinks.value = sidebarLinks.value.map((link) => { + /* sidebarLinks.value = sidebarLinks.value.map((link) => { if (link.label === 'Notifications') { link.count = data } return link - }) + }) */ }, auto: user ? true : false, }) -const addNotifications = () => { - if (user) { - sidebarLinks.value.push({ - label: 'Notifications', - icon: 'Bell', - to: 'Notifications', - activeFor: ['Notifications'], - count: unreadCount.value, - }) - } -} - -const addQuizzes = () => { - if (!isInstructor.value && !isModerator.value) return - - const quizzesLinkExists = sidebarLinks.value.some( - (link) => link.label === 'Quizzes' - ) - if (quizzesLinkExists) return - - sidebarLinks.value.splice(4, 0, { - label: 'Quizzes', - icon: 'CircleHelp', - to: 'Quizzes', - activeFor: ['Quizzes', 'QuizForm', 'QuizSubmissionList', 'QuizSubmission'], - }) -} - -const addAssignments = () => { - if (!isInstructor.value && !isModerator.value) return - - const assignmentsLinkExists = sidebarLinks.value.some( - (link) => link.label === 'Assignments' - ) - if (assignmentsLinkExists) return - - sidebarLinks.value.splice(5, 0, { - label: 'Assignments', - icon: 'Pencil', - to: 'Assignments', - activeFor: [ - 'Assignments', - 'AssignmentForm', - 'AssignmentSubmissionList', - 'AssignmentSubmission', - ], - }) -} - -const addProgrammingExercises = () => { - if (!isInstructor.value && !isModerator.value) return - const programmingExercisesLinkExists = sidebarLinks.value.some( - (link) => link.label === 'Programming Exercises' - ) - if (programmingExercisesLinkExists) return - - sidebarLinks.value.splice(3, 0, { - label: 'Programming Exercises', - icon: 'Code', - to: 'ProgrammingExercises', - activeFor: [ - 'ProgrammingExercises', - 'ProgrammingExerciseForm', - 'ProgrammingExerciseSubmissions', - 'ProgrammingExerciseSubmission', - ], - }) -} - const addPrograms = async () => { const programsLinkExists = sidebarLinks.value.some( (link) => link.label === 'Programs' @@ -417,45 +356,6 @@ const addPrograms = async () => { }) } -const addContactUsDetails = () => { - if (!settings?.data?.contact_us_email && !settings?.data?.contact_us_url) - return - - const contactUsLinkExists = sidebarLinks.value.some( - (link) => link.label === 'Contact Us' - ) - if (contactUsLinkExists) return - - sidebarLinks.value.push({ - label: 'Contact Us', - icon: settings.data?.contact_us_url ? 'Headset' : 'Mail', - to: settings.data?.contact_us_url - ? settings.data?.contact_us_url - : settings.data?.contact_us_email, - }) -} - -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 addHome = () => { - const homeLinkExists = sidebarLinks.value.some( - (link) => link.label === 'Home' - ) - if (homeLinkExists) return - sidebarLinks.value.unshift({ - label: 'Home', - icon: 'Home', - to: 'Home', - activeFor: ['Home'], - }) -} - const openPageModal = (link) => { showPageModal.value = true pageToEdit.value = link @@ -700,16 +600,15 @@ const setUpOnboarding = () => { } } -watch(userResource, () => { - addContactUsDetails() +watch(userResource, async () => { + await userResource.promise + sidebarLinks.value = getSidebarLinks() + setSidebarLinks() if (userResource.data) { isModerator.value = userResource.data.is_moderator isInstructor.value = userResource.data.is_instructor - addHome() - addPrograms() - addProgrammingExercises() - addQuizzes() - addAssignments() + await programs.promise + sidebarLinks.value = getSidebarLinks() setUpOnboarding() } }) diff --git a/frontend/src/stores/settings.js b/frontend/src/stores/settings.js index f1689f0d..b0cf32f0 100644 --- a/frontend/src/stores/settings.js +++ b/frontend/src/stores/settings.js @@ -1,7 +1,6 @@ import { defineStore } from 'pinia' import { ref } from 'vue' import { createResource } from 'frappe-ui' -import { sessionStore } from './session' export const useSettings = defineStore('settings', () => { const isSettingsOpen = ref(false) @@ -20,10 +19,16 @@ export const useSettings = defineStore('settings', () => { auto: false, }) + const programs = createResource({ + url: 'lms.lms.utils.get_programs', + auto: false, + }) + return { + activeTab, isSettingsOpen, isCommandPaletteOpen, - activeTab, + programs, settings, sidebarSettings, } diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index 6b46946c..d18bc98a 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -403,51 +403,177 @@ export function getUserTimezone() { } export function getSidebarLinks() { + let links = getSidebarItems() + + links.forEach((link) => { + link.items = link.items.filter((item) => { + return item.condition ? item.condition() : true + }) + }) + + links = links.filter((link) => { + return link.items.length > 0 + }) + + return links +} + +const getSidebarItems = () => { + const { userResource } = usersStore() + const { settings } = useSettings() + return [ { - label: 'Search', - icon: 'Search', - to: 'Search', - }, - { - label: 'Courses', - icon: 'BookOpen', - to: 'Courses', - activeFor: [ - 'Courses', - 'CourseDetail', - 'Lesson', - 'CourseForm', - 'LessonForm', + label: 'General', + hideLabel: true, + items: [ + { + label: 'Home', + icon: 'Home', + to: 'Home', + condition: () => { + return userResource?.data + }, + }, + { + label: 'Search', + icon: 'Search', + to: 'Search', + condition: () => { + return userResource?.data + }, + }, + { + label: 'Notifications', + icon: 'Bell', + to: 'Notifications', + condition: () => { + return userResource?.data + }, + }, ], }, { - label: 'Batches', - icon: 'Users', - to: 'Batches', - activeFor: ['Batches', 'BatchDetail', 'Batch', 'BatchForm'], + label: 'Learning', + hideLabel: true, + items: [ + { + label: 'Courses', + icon: 'BookOpen', + to: 'Courses', + activeFor: [ + 'Courses', + 'CourseDetail', + 'Lesson', + 'CourseForm', + 'LessonForm', + ], + }, + { + label: 'Programs', + icon: 'Route', + to: 'Programs', + activeFor: ['Programs', 'ProgramDetail'], + await: true, + condition: () => { + return checkIfCanAddProgram() + }, + }, + { + label: 'Batches', + icon: 'Users', + to: 'Batches', + activeFor: ['Batches', 'BatchDetail', 'Batch', 'BatchForm'], + }, + { + label: 'Certifications', + icon: 'GraduationCap', + to: 'CertifiedParticipants', + activeFor: ['CertifiedParticipants'], + }, + { + label: 'Jobs', + icon: 'Briefcase', + to: 'Jobs', + activeFor: ['Jobs', 'JobDetail'], + }, + { + label: 'Statistics', + icon: 'TrendingUp', + to: 'Statistics', + activeFor: ['Statistics'], + }, + { + label: 'Contact Us', + icon: settings.data?.contact_us_url ? 'Headset' : 'Mail', + to: settings.data?.contact_us_url + ? settings.data?.contact_us_url + : settings.data?.contact_us_email, + condition: () => { + return ( + settings?.data?.contact_us_email || + settings?.data?.contact_us_url + ) + }, + }, + ], }, { - label: 'Certifications', - icon: 'GraduationCap', - to: 'CertifiedParticipants', - activeFor: ['CertifiedParticipants'], - }, - { - label: 'Jobs', - icon: 'Briefcase', - to: 'Jobs', - activeFor: ['Jobs', 'JobDetail'], - }, - { - label: 'Statistics', - icon: 'TrendingUp', - to: 'Statistics', - activeFor: ['Statistics'], + label: 'Assessments', + hideLabel: true, + items: [ + { + label: 'Quizzes', + icon: 'CircleHelp', + to: 'Quizzes', + condition: () => { + return isAdmin() + }, + }, + { + label: 'Assignments', + icon: 'Pencil', + to: 'Assignments', + condition: () => { + return isAdmin() + }, + }, + { + label: 'Programming Exercises', + icon: 'Code', + to: 'ProgrammingExercises', + condition: () => { + return isAdmin() + }, + }, + ], }, ] } +const isAdmin = () => { + const { userResource } = usersStore() + return ( + userResource?.data?.is_instructor || + userResource?.data?.is_moderator || + userResource.data?.is_evaluator + ) +} + +const checkIfCanAddProgram = () => { + const { userResource } = usersStore() + const { programs } = useSettings() + if (!userResource.data) return false + if (userResource?.data?.is_moderator || userResource?.data?.is_instructor) { + return true + } + console.log('programs.data', programs.data) + return ( + programs.data?.enrolled.length > 0 || + programs.data?.published.length > 0 + ) +} + export function getFormattedDateRange( startDate, endDate, diff --git a/lms/lms/doctype/lms_course/lms_course.json b/lms/lms/doctype/lms_course/lms_course.json index b30ed240..f4b03ffa 100644 --- a/lms/lms/doctype/lms_course/lms_course.json +++ b/lms/lms/doctype/lms_course/lms_course.json @@ -313,7 +313,7 @@ } ], "make_attachments_public": 1, - "modified": "2025-11-25 11:35:17.924569", + "modified": "2025-12-11 17:21:05.231761", "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Course", @@ -336,6 +336,7 @@ "delete": 1, "email": 1, "export": 1, + "import": 1, "print": 1, "read": 1, "report": 1, @@ -348,6 +349,7 @@ "delete": 1, "email": 1, "export": 1, + "import": 1, "print": 1, "read": 1, "report": 1,