feat: broke down sidebar into categories

This commit is contained in:
Jannat Patel
2025-12-12 12:30:16 +05:30
parent 820ea7e2a4
commit 819318de37
4 changed files with 203 additions and 171 deletions

View File

@@ -9,11 +9,21 @@
>
<UserDropdown :isCollapsed="sidebarStore.isSidebarCollapsed" />
<div class="flex flex-col" v-if="sidebarSettings.data">
<div v-for="link in sidebarLinks" class="mx-2 my-0.5">
<SidebarLink
:link="link"
:isCollapsed="sidebarStore.isSidebarCollapsed"
/>
<div v-for="link in sidebarLinks" class="mx-2 my-2.5">
<div
v-if="!link.hideLabel"
class="mb-2 mt-3 flex cursor-pointer gap-1.5 px-1 text-base font-medium text-ink-gray-5 transition-all duration-300 ease-in-out"
>
<span>{{ __(link.label) }}</span>
</div>
<nav class="space-y-1">
<div v-for="item in link.items">
<SidebarLink
:link="item"
:isCollapsed="sidebarStore.isSidebarCollapsed"
/>
</div>
</nav>
</div>
</div>
<div
@@ -235,18 +245,13 @@ const { userResource } = usersStore()
let sidebarStore = useSidebar()
const socket = inject('$socket')
const unreadCount = ref(0)
const sidebarLinks = ref(getSidebarLinks())
const sidebarLinks = ref(null)
const showPageModal = ref(false)
const isModerator = ref(false)
const isInstructor = ref(false)
const pageToEdit = ref(null)
const {
settings,
sidebarSettings,
activeTab,
isSettingsOpen,
isCommandPaletteOpen,
} = useSettings()
const { settings, sidebarSettings, activeTab, isSettingsOpen, programs } =
useSettings()
const settingsStore = useSettings()
const showOnboarding = ref(false)
const showIntermediateModal = ref(false)
@@ -262,8 +267,6 @@ const iconProps = {
}
onMounted(() => {
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()
}
})

View File

@@ -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,
}

View File

@@ -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,