diff --git a/frontend/src/components/AppSidebar.vue b/frontend/src/components/AppSidebar.vue index 674268cc..b39a24ff 100644 --- a/frontend/src/components/AppSidebar.vue +++ b/frontend/src/components/AppSidebar.vue @@ -383,6 +383,15 @@ const checkIfCanAddProgram = async () => { return programs.enrolled.length > 0 || programs.published.length > 0 } +const addHome = () => { + sidebarLinks.value.unshift({ + label: 'Home', + icon: 'Home', + to: 'Home', + activeFor: ['Home'], + }) +} + const openPageModal = (link) => { showPageModal.value = true pageToEdit.value = link @@ -634,6 +643,7 @@ watch(userResource, () => { if (userResource.data) { isModerator.value = userResource.data.is_moderator isInstructor.value = userResource.data.is_instructor + addHome() addPrograms() addProgrammingExercises() addQuizzes() diff --git a/frontend/src/pages/Home/AdminHome.vue b/frontend/src/pages/Home/AdminHome.vue index 1c4c9f97..c027b996 100644 --- a/frontend/src/pages/Home/AdminHome.vue +++ b/frontend/src/pages/Home/AdminHome.vue @@ -3,7 +3,7 @@
- {{ __('Courses by me') }} + {{ __('Courses Created') }}
- {{ __('Batches by me') }} + {{ __('Upcoming Batches') }}
+ +
+
+
+ {{ __('Upcoming Evaluations') }} +
+
+
+
+ {{ evaluation.course_title }} +
+
+
+ + + {{ dayjs(evaluation.date).format('DD MMMM YYYY') }} + +
+
+ + + {{ formatTime(evaluation.start_time) }} + +
+
+ + + {{ evaluation.member_name }} + +
+
+
+
+
+
+
+ {{ __('Upcoming Live Classes') }} +
+
+
+
+ {{ cls.title }} +
+
+ {{ cls.description }} +
+
+
+ + + {{ dayjs(cls.date).format('DD MMMM YYYY') }} + +
+
+ + + {{ formatTime(cls.time) }} - + {{ dayjs(getClassEnd(cls)).format('HH:mm A') }} + +
+ + +
+ + + {{ __('Ended') }} + +
+
+
+
+
+
+
diff --git a/frontend/src/pages/Home/Home.vue b/frontend/src/pages/Home/Home.vue index 3817b9b8..1ca0fc64 100644 --- a/frontend/src/pages/Home/Home.vue +++ b/frontend/src/pages/Home/Home.vue @@ -11,45 +11,25 @@ {{ __('Hey') }}, {{ user.data?.full_name }} 👋
- - {{ __('Manage your courses and batches at a glance') }} - - - - {{ - __('You have {0} upcoming live classes').format( - myLiveClasses.data.length - ) - }} - - - {{ __(' and {0} evaluation').format(evalCount) }} - - - {{ __(' scheduled.') }} - - - - {{ - __('You have {0} upcoming live classes.').format( - myLiveClasses.data.length - ) - }} - - - {{ __('You have {0} evaluations scheduled.').format(evalCount) }} - - - {{ __('Resume where you left off') }} - + {{ subtitle }}
+
+ 🔥 + + {{ streakInfo.data?.current_streak }} + +
- + @@ -77,16 +57,6 @@ onMounted(() => { }) }) -const myLiveClasses = createResource({ - url: 'lms.lms.utils.get_my_live_classes', - auto: true, -}) - -const tabs = [ - { label: __('Student'), value: 'student' }, - { label: __('Instructor'), value: 'instructor' }, -] - const isAdmin = computed(() => { return ( user.data?.is_moderator || @@ -95,6 +65,63 @@ const isAdmin = computed(() => { ) }) +const myLiveClasses = createResource({ + url: 'lms.lms.utils.get_my_live_classes', + auto: !isAdmin.value ? true : false, +}) + +const adminLiveClasses = createResource({ + url: 'lms.lms.utils.get_admin_live_classes', + auto: isAdmin.value ? true : false, +}) + +const adminEvals = createResource({ + url: 'lms.lms.utils.get_admin_evals', + auto: isAdmin.value ? true : false, +}) + +const streakInfo = createResource({ + url: 'lms.lms.utils.get_streak_info', + auto: true, +}) + +const subtitle = computed(() => { + if (isAdmin.value) { + if (adminLiveClasses.data?.length > 0 && adminEvals.data?.length > 0) { + return __( + 'You have {0} upcoming live classes and {1} evaluations scheduled.' + ).format(adminLiveClasses.data.length, adminEvals.data.length) + } else if (adminLiveClasses.data?.length > 0) { + return __('You have {0} upcoming live classes.').format( + adminLiveClasses.data.length + ) + } else if (adminEvals.data?.length > 0) { + return __('You have {0} evaluations scheduled.').format( + adminEvals.data.length + ) + } + return __('Manage your courses and batches at a glance') + } else { + if (myLiveClasses.data?.length > 0 && evalCount.value > 0) { + return __( + 'You have {0} upcoming live classes and {1} evaluations scheduled.' + ).format(myLiveClasses.data.length, evalCount.value) + } else if (myLiveClasses.data?.length > 0) { + return __('You have {0} upcoming live classes.').format( + myLiveClasses.data.length + ) + } else if (evalCount.value > 0) { + return __('You have {0} evaluations scheduled.').format(evalCount.value) + } + return __('Resume where you left off') + } +}) + +const tabs = [ + { label: __('Student'), value: 'student' }, + { label: __('Instructor'), value: 'instructor' }, +] + usePageMeta(() => { return { title: __('Home'), diff --git a/frontend/src/pages/Home/StudentHome.vue b/frontend/src/pages/Home/StudentHome.vue index 03c695bd..744af3c1 100644 --- a/frontend/src/pages/Home/StudentHome.vue +++ b/frontend/src/pages/Home/StudentHome.vue @@ -159,11 +159,6 @@ const myBatches = createResource({ auto: true, }) -const streakInfo = createResource({ - url: 'lms.lms.utils.get_streak_info', - auto: true, -}) - const getClassEnd = (cls: { date: string; time: string; duration: number }) => { const classStart = new Date(`${cls.date}T${cls.time}`) return new Date(classStart.getTime() + cls.duration * 60000) diff --git a/frontend/src/router.js b/frontend/src/router.js index eb187b41..473f1776 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -258,6 +258,8 @@ router.beforeEach(async (to, from, next) => { } if (!isLoggedIn) { + if (to.name == 'Home') router.push({ name: 'Courses' }) + await allowGuestAccess.promise if (!allowGuestAccess.data) { window.location.href = '/login' diff --git a/frontend/src/stores/session.js b/frontend/src/stores/session.js index 17697079..04faec5d 100644 --- a/frontend/src/stores/session.js +++ b/frontend/src/stores/session.js @@ -61,7 +61,7 @@ export const sessionStore = defineStore('lms-session', () => { field: 'livecode_url', }, cache: 'livecodeURL', - auto: true, + auto: user.value ? true : false, }) return { diff --git a/frontend/src/stores/settings.js b/frontend/src/stores/settings.js index 68c3cd06..a29d9d52 100644 --- a/frontend/src/stores/settings.js +++ b/frontend/src/stores/settings.js @@ -4,7 +4,6 @@ import { createResource } from 'frappe-ui' import { sessionStore } from './session' export const useSettings = defineStore('settings', () => { - const { isLoggedIn } = sessionStore() const isSettingsOpen = ref(false) const activeTab = ref(null) diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index b4b0fd0e..eba86850 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -403,12 +403,6 @@ export function getUserTimezone() { export function getSidebarLinks() { return [ - { - label: 'Home', - icon: 'Home', - to: 'Home', - activeFor: ['Home'], - }, { label: 'Courses', icon: 'BookOpen', diff --git a/lms/lms/utils.py b/lms/lms/utils.py index f9fedcc2..a14d0326 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -2242,17 +2242,22 @@ def get_created_courses(): if frappe.session.user == "Guest": return created_courses - courses = frappe.get_all( - "Course Instructor", - { - "instructor": frappe.session.user, - "parenttype": "LMS Course", - }, - pluck="parent", - limit=3, - order_by="creation desc", + CourseInstructor = frappe.qb.DocType("Course Instructor") + Course = frappe.qb.DocType("LMS Course") + + query = ( + frappe.qb.from_(CourseInstructor) + .join(Course) + .on(CourseInstructor.parent == Course.name) + .select(Course.name) + .where(CourseInstructor.instructor == frappe.session.user) + .orderby(Course.published_on, order=frappe.qb.desc) + .limit(3) ) + results = query.run(as_dict=True) + courses = [row["name"] for row in results] + for course in courses: course_details = get_course_details(course) created_courses.append(course_details) @@ -2266,14 +2271,23 @@ def get_created_batches(): if frappe.session.user == "Guest": return created_batches - batches = frappe.get_all( - "Course Instructor", - {"instructor": frappe.session.user, "parenttype": "LMS Batch"}, - pluck="parent", - limit=4, - order_by="creation asc", + CourseInstructor = frappe.qb.DocType("Course Instructor") + Batch = frappe.qb.DocType("LMS Batch") + + query = ( + frappe.qb.from_(CourseInstructor) + .join(Batch) + .on(CourseInstructor.parent == Batch.name) + .select(Batch.name) + .where(CourseInstructor.instructor == frappe.session.user) + .where(Batch.start_date >= getdate()) + .orderby(Batch.start_date, order=frappe.qb.asc) + .limit(4) ) + results = query.run(as_dict=True) + batches = [row["name"] for row in results] + for batch in batches: batch_details = get_batch_details(batch) created_batches.append(batch_details) @@ -2281,6 +2295,70 @@ def get_created_batches(): return created_batches +@frappe.whitelist() +def get_admin_live_classes(): + if frappe.session.user == "Guest": + return [] + + CourseInstructor = frappe.qb.DocType("Course Instructor") + LMSLiveClass = frappe.qb.DocType("LMS Live Class") + + query = ( + frappe.qb.from_(CourseInstructor) + .join(LMSLiveClass) + .on(CourseInstructor.parent == LMSLiveClass.batch_name) + .select( + LMSLiveClass.name, + LMSLiveClass.title, + LMSLiveClass.description, + LMSLiveClass.time, + LMSLiveClass.date, + LMSLiveClass.duration, + LMSLiveClass.attendees, + LMSLiveClass.start_url, + LMSLiveClass.join_url, + LMSLiveClass.owner, + ) + .where(CourseInstructor.instructor == frappe.session.user) + .where(LMSLiveClass.date >= getdate()) + .orderby(LMSLiveClass.date, order=frappe.qb.asc) + .limit(4) + ) + results = query.run(as_dict=True) + return results + + +@frappe.whitelist() +def get_admin_evals(): + if frappe.session.user == "Guest": + return [] + + evals = frappe.get_all( + "LMS Certificate Request", + { + "evaluator": frappe.session.user, + "date": [">=", getdate()], + }, + [ + "name", + "date", + "start_time", + "course", + "evaluator", + "google_meet_link", + "member", + "member_name", + ], + limit=4, + order_by="date asc", + ) + + for evaluation in evals: + evaluation.course_title = frappe.db.get_value("LMS Course", evaluation.course, "title") + + return evals + + @frappe.whitelist() def get_streak_info(): if frappe.session.user == "Guest": @@ -2347,11 +2425,8 @@ def get_streak_info(): max_streak = max(max_streak, streak) prev_day = d - return 1 - """ return { + + return { "current_streak": streak, "max_streak": max_streak, - "last_activity_date": prev_day.strftime("%Y-%m-%d") if prev_day else None, - "total_days_active": len(all_dates), - "total_days_in_month": (getdate() - getdate(getdate().year, getdate().month, 1)).days + 1, - } """ + }