import { Dialog, createDocumentResource } from 'frappe-ui'
import { ref, computed, watch } from 'vue'
+import { useSettings } from '@/stores/settings'
import SettingDetails from '../SettingDetails.vue'
import SidebarLink from '@/components/SidebarLink.vue'
import Members from '@/components/Members.vue'
-import Categories from '../Categories.vue'
+import Categories from '@/components/Categories.vue'
const show = defineModel()
const doctype = ref('LMS Settings')
const activeTab = ref(null)
+const settingsStore = useSettings()
const data = createDocumentResource({
doctype: doctype.value,
@@ -75,8 +79,8 @@ const data = createDocumentResource({
auto: true,
})
-const tabs = computed(() => {
- let _tabs = [
+const tabsStructure = computed(() => {
+ return [
{
label: 'Settings',
hideLabel: true,
@@ -86,11 +90,23 @@ const tabs = computed(() => {
description: 'Manage the members of your learning system',
icon: 'UserRoundPlus',
},
+ ],
+ },
+ {
+ label: 'Settings',
+ hideLabel: true,
+ items: [
{
label: 'Categories',
description: 'Manage the members of your learning system',
icon: 'Network',
},
+ ],
+ },
+ {
+ label: 'Settings',
+ hideLabel: true,
+ items: [
{
label: 'Payment Gateway',
icon: 'DollarSign',
@@ -136,8 +152,8 @@ const tabs = computed(() => {
],
},
{
- label: 'Settings',
- hideLabel: true,
+ label: 'Customise',
+ hideLabel: false,
items: [
{
label: 'Sidebar',
@@ -179,12 +195,6 @@ const tabs = computed(() => {
},
],
},
- ],
- },
- {
- label: 'Settings',
- hideLabel: true,
- items: [
{
label: 'Email Templates',
icon: 'MailPlus',
@@ -210,12 +220,6 @@ const tabs = computed(() => {
},
],
},
- ],
- },
- {
- label: 'Settings',
- hideLabel: true,
- items: [
{
label: 'Signup',
icon: 'LogIn',
@@ -268,23 +272,36 @@ const tabs = computed(() => {
],
},
]
+})
- return _tabs.map((tab) => {
- tab.items = tab.items.filter((item) => {
- if (item.condition) {
- return item.condition()
- }
- return true
- })
- return tab
+const tabs = computed(() => {
+ return tabsStructure.value.map((tab) => {
+ return {
+ ...tab,
+ items: tab.items.filter((item) => {
+ return !item.condition || item.condition()
+ }),
+ }
})
})
-watch(show, () => {
+watch(
+ () => activeTab.value,
+ (value) => {
+ console.log('Tab watcher', value)
+ }
+)
+
+watch(show, async () => {
if (show.value) {
- activeTab.value = tabs.value[0].items[0]
+ const currentTab = await tabs.value
+ .flatMap((tab) => tab.items)
+ .find((item) => item.label === settingsStore.activeTab)
+ activeTab.value = currentTab || tabs.value[0].items[0]
} else {
+ console.log('else')
activeTab.value = null
+ settingsStore.isSettingsOpen = false
}
})
diff --git a/frontend/src/components/UserDropdown.vue b/frontend/src/components/UserDropdown.vue
index 348e7918..5071513d 100644
--- a/frontend/src/components/UserDropdown.vue
+++ b/frontend/src/components/UserDropdown.vue
@@ -67,25 +67,20 @@ import LMSLogo from '@/components/Icons/LMSLogo.vue'
import { sessionStore } from '@/stores/session'
import { Dropdown } from 'frappe-ui'
import Apps from '@/components/Apps.vue'
-import {
- ChevronDown,
- LogIn,
- LogOut,
- User,
- ArrowRightLeft,
- Settings,
-} from 'lucide-vue-next'
+import { ChevronDown, LogIn, LogOut, User, Settings } from 'lucide-vue-next'
import { useRouter } from 'vue-router'
import { convertToTitleCase } from '../utils'
import { usersStore } from '@/stores/user'
-import { ref, markRaw } from 'vue'
+import { useSettings } from '@/stores/settings'
+import { markRaw, watch, ref } from 'vue'
import SettingsModal from '@/components/Modals/Settings.vue'
const router = useRouter()
-const showSettingsModal = ref(false)
const { logout, branding } = sessionStore()
let { userResource } = usersStore()
+const settingsStore = useSettings()
let { isLoggedIn } = sessionStore()
+const showSettingsModal = ref(false)
const props = defineProps({
isCollapsed: {
@@ -94,6 +89,13 @@ const props = defineProps({
},
})
+watch(
+ () => settingsStore.isSettingsOpen,
+ (value) => {
+ showSettingsModal.value = value
+ }
+)
+
const userDropdownOptions = [
{
icon: User,
@@ -118,7 +120,7 @@ const userDropdownOptions = [
icon: Settings,
label: 'Settings',
onClick: () => {
- showSettingsModal.value = true
+ settingsStore.isSettingsOpen = true
},
condition: () => {
return userResource.data?.is_moderator
diff --git a/frontend/src/pages/CourseForm.vue b/frontend/src/pages/CourseForm.vue
index c6a82f36..a23fe42c 100644
--- a/frontend/src/pages/CourseForm.vue
+++ b/frontend/src/pages/CourseForm.vue
@@ -109,6 +109,14 @@
/>
{
course.course_image = null
}
+const openSettings = (close) => {
+ close()
+ settingsStore.activeTab = 'Categories'
+ settingsStore.isSettingsOpen = true
+}
+
const check_permission = () => {
let user_is_instructor = false
if (user.data?.is_moderator) return
diff --git a/frontend/src/pages/Courses.vue b/frontend/src/pages/Courses.vue
index 2291d067..ca7c94b4 100644
--- a/frontend/src/pages/Courses.vue
+++ b/frontend/src/pages/Courses.vue
@@ -8,6 +8,15 @@
:items="[{ label: __('Courses'), route: { name: 'Courses' } }]"
/>
+
+
+
{
+ let queries = new URLSearchParams(location.search)
+ if (queries.has('category')) {
+ currentCategory.value = queries.get('category')
+ }
+})
const courses = createResource({
url: 'lms.lms.utils.get_courses',
@@ -168,18 +185,57 @@ const addToTabs = (label) => {
}
const getCourses = (type) => {
+ let courseList = courses.data[type]
if (searchQuery.value) {
let query = searchQuery.value.toLowerCase()
- return courses.data[type].filter(
+ courseList = courseList.filter(
(course) =>
course.title.toLowerCase().includes(query) ||
course.short_introduction.toLowerCase().includes(query) ||
course.tags.filter((tag) => tag.toLowerCase().includes(query)).length
)
}
- return courses.data[type]
+ if (currentCategory.value && currentCategory.value != '') {
+ courseList = courseList.filter(
+ (course) => course.category == currentCategory.value
+ )
+ }
+ return courseList
}
+const categories = createResource({
+ url: 'lms.lms.api.get_categories',
+ makeParams() {
+ return {
+ doctype: 'LMS Course',
+ filters: {
+ published: 1,
+ },
+ }
+ },
+ cache: ['courseCategories'],
+ auto: true,
+ transform(data) {
+ data.unshift({
+ label: '',
+ value: null,
+ })
+ },
+})
+
+watch(
+ () => currentCategory.value,
+ () => {
+ let queries = new URLSearchParams(location.search)
+ if (currentCategory.value) {
+ queries.set('category', currentCategory.value)
+ } else {
+ queries.delete('category')
+ }
+ history.pushState(null, '', `${location.pathname}?${queries.toString()}`)
+ }
+)
+
const pageMeta = computed(() => {
return {
title: 'Courses',
diff --git a/frontend/src/stores/settings.js b/frontend/src/stores/settings.js
new file mode 100644
index 00000000..61d6bedc
--- /dev/null
+++ b/frontend/src/stores/settings.js
@@ -0,0 +1,12 @@
+import { defineStore } from 'pinia'
+import { ref } from 'vue'
+
+export const useSettings = defineStore('settings', () => {
+ const isSettingsOpen = ref(false)
+ const activeTab = ref(null)
+
+ return {
+ isSettingsOpen,
+ activeTab,
+ }
+})
diff --git a/lms/lms/doctype/lms_category/lms_category.json b/lms/lms/doctype/lms_category/lms_category.json
index bd5ede67..0d11937c 100644
--- a/lms/lms/doctype/lms_category/lms_category.json
+++ b/lms/lms/doctype/lms_category/lms_category.json
@@ -15,12 +15,13 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Category",
+ "reqd": 1,
"unique": 1
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2023-06-15 15:14:11.341961",
+ "modified": "2024-09-23 15:25:21.319427",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Category",
@@ -55,5 +56,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
- "title_field": "category"
+ "title_field": "category",
+ "track_changes": 1
}
\ No newline at end of file
diff --git a/lms/lms/doctype/lms_course/lms_course.json b/lms/lms/doctype/lms_course/lms_course.json
index f22970b4..851c6486 100644
--- a/lms/lms/doctype/lms_course/lms_course.json
+++ b/lms/lms/doctype/lms_course/lms_course.json
@@ -16,10 +16,12 @@
"field_order": [
"title",
"video_link",
- "image",
"column_break_3",
"instructors",
"tags",
+ "column_break_htgn",
+ "image",
+ "category",
"status",
"section_break_7",
"published",
@@ -237,6 +239,16 @@
"fieldname": "certification_tab",
"fieldtype": "Tab Break",
"label": "Certification"
+ },
+ {
+ "fieldname": "column_break_htgn",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "category",
+ "fieldtype": "Link",
+ "label": "Category",
+ "options": "LMS Category"
}
],
"is_published_field": "published",
@@ -263,7 +275,7 @@
}
],
"make_attachments_public": 1,
- "modified": "2024-07-12 13:54:40.474097",
+ "modified": "2024-09-21 10:23:58.633912",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Course",
diff --git a/lms/lms/utils.py b/lms/lms/utils.py
index a49208ad..1c4480b8 100644
--- a/lms/lms/utils.py
+++ b/lms/lms/utils.py
@@ -1220,6 +1220,7 @@ def get_course_details(course):
"featured",
"disable_self_learning",
"published_on",
+ "category",
"status",
"paid_course",
"course_price",