From d7d222842bc7ef71b7ce6624211eeef510279a51 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 6 Feb 2024 22:39:08 +0530 Subject: [PATCH] feat: statistics graphs --- frontend/package.json | 3 +- frontend/src/components/AppSidebar.vue | 1 + frontend/src/components/SidebarLink.vue | 6 +- frontend/src/pages/Statistics.vue | 252 ++++++++++++++++++------ frontend/src/utils/index.js | 13 +- lms/lms/api.py | 19 ++ lms/lms/utils.py | 16 +- yarn.lock | 14 +- 8 files changed, 254 insertions(+), 70 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 6ced7d3d..beb48936 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,6 +8,7 @@ "preview": "vite preview" }, "dependencies": { + "chart.js": "^4.4.1", "dayjs": "^1.11.6", "feather-icons": "^4.28.0", "frappe-ui": "^0.1.22", @@ -17,7 +18,7 @@ "socket.io-client": "^4.7.2", "tailwindcss": "^3.3.3", "vue": "^3.2.25", - "vue-chartjs": "^5.0.0", + "vue-chartjs": "^5.3.0", "vue-router": "^4.0.12" }, "devDependencies": { diff --git a/frontend/src/components/AppSidebar.vue b/frontend/src/components/AppSidebar.vue index 5a9f9808..8543620c 100644 --- a/frontend/src/components/AppSidebar.vue +++ b/frontend/src/components/AppSidebar.vue @@ -14,6 +14,7 @@ :icon="link.icon" :label="link.label" :to="link.to" + :activeFor="link.activeFor" :isCollapsed="isSidebarCollapsed" class="mx-2 my-0.5" /> diff --git a/frontend/src/components/SidebarLink.vue b/frontend/src/components/SidebarLink.vue index 2608c736..e54146c5 100644 --- a/frontend/src/components/SidebarLink.vue +++ b/frontend/src/components/SidebarLink.vue @@ -48,6 +48,10 @@ const props = defineProps({ type: String, default: '', }, + activeFor: { + type: Array, + default: [], + }, isCollapsed: { type: Boolean, default: false, @@ -59,6 +63,6 @@ function handleClick() { } let isActive = computed(() => { - return router.currentRoute.value.name === props.to + return props.activeFor.includes(router.currentRoute.value.name) }) diff --git a/frontend/src/pages/Statistics.vue b/frontend/src/pages/Statistics.vue index 3575d959..f12e438f 100644 --- a/frontend/src/pages/Statistics.vue +++ b/frontend/src/pages/Statistics.vue @@ -5,67 +5,67 @@ > -
-
-
+
+
+
- {{ courseCount.data?.toLocaleString() }} + {{ chartDetails.data.courses }}
{{ __('Published Courses') }}
-
+
- {{ userCount.data?.toLocaleString() }} + {{ chartDetails.data.users }}
{{ __('Total Signups') }}
-
+
- {{ enrollmentCount.data?.toLocaleString() }} + {{ chartDetails.data.enrollments }}
{{ __('Enrolled Users') }}
-
+
- {{ coursesCompleted.data?.toLocaleString() }} + {{ chartDetails.data.completions }}
{{ __('Courses Completed') }}
-
+
- {{ lessonsCompleted.data?.toLocaleString() }} + {{ chartDetails.data.lesson_completions }}
{{ __('Lessons Completed') }} @@ -73,12 +73,67 @@
+
+
+ +
+
+ +
+
+ +
+
+ +
+
diff --git a/frontend/src/utils/index.js b/frontend/src/utils/index.js index 4e5a812a..6632e712 100644 --- a/frontend/src/utils/index.js +++ b/frontend/src/utils/index.js @@ -187,21 +187,24 @@ export function getSidebarLinks() { label: 'Courses', icon: BookOpen, to: 'Courses', + activeFor: ['Courses', 'CourseDetail', 'Lesson'], }, { label: 'Batches', icon: Users, to: 'Batches', + activeFor: ['Batches', 'BatchDetail', 'Batch'], + }, + { + label: 'Jobs', + icon: Briefcase, + to: 'Jobs', + activeFor: ['Jobs', 'JobDetail'], }, { label: 'Statistics', icon: TrendingUp, to: 'Statistics', }, - { - label: 'Jobs', - icon: Briefcase, - to: 'Jobs', - }, ] } diff --git a/lms/lms/api.py b/lms/lms/api.py index 12c3d4ad..431ea4c6 100644 --- a/lms/lms/api.py +++ b/lms/lms/api.py @@ -239,3 +239,22 @@ def get_job_opportunities(): order_by="creation desc", ) return jobs + + +@frappe.whitelist(allow_guest=True) +def get_chart_details(): + details = frappe._dict() + details.enrollments = frappe.db.count("LMS Enrollment") + details.courses = frappe.db.count( + "LMS Course", + { + "published": 1, + "upcoming": 0, + }, + ) + details.users = frappe.db.count("User", {"enabled": 1}) + details.completions = frappe.db.count( + "LMS Enrollment", {"progress": ["like", "%100%"]} + ) + details.lesson_completions = frappe.db.count("LMS Course Progress") + return details diff --git a/lms/lms/utils.py b/lms/lms/utils.py index f8b3cf0f..b8b1b619 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -764,7 +764,17 @@ def has_lessons(course): @frappe.whitelist(allow_guest=True) -def get_chart_data(chart_name, timespan, timegrain, from_date, to_date): +def get_chart_data( + chart_name, + timespan="Select Date Range", + timegrain="Daily", + from_date=None, + to_date=None, +): + if not from_date: + from_date = add_months(getdate(), -1) + if not to_date: + to_date = getdate() chart = frappe.get_doc("Dashboard Chart", chart_name) filters = [([chart.document_type, "docstatus", "<", 2, False])] doctype = chart.document_type @@ -794,7 +804,7 @@ def get_chart_data(chart_name, timespan, timegrain, from_date, to_date): else get_period(r[0], timegrain) for r in result ], - "datasets": [{"name": chart.name, "values": [r[1] for r in result]}], + "datasets": [{"name": chart.name, "data": [r[1] for r in result]}], } @@ -808,7 +818,7 @@ def get_course_completion_data(): "datasets": [ { "name": "Course Completion", - "values": [completed, all_membership - completed], + "data": [completed, all_membership - completed], } ], } diff --git a/yarn.lock b/yarn.lock index aa3283a6..87fa82fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -567,6 +567,11 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@kurkle/color@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@kurkle/color/-/color-0.3.2.tgz#5acd38242e8bde4f9986e7913c8fdf49d3aa199f" + integrity sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw== + "@lezer/common@^1.0.0", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0": version "1.2.1" resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.1.tgz#198b278b7869668e1bebbe687586e12a42731049" @@ -1477,6 +1482,13 @@ charenc@0.0.2: resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== +chart.js@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.4.1.tgz#ac5dc0e69a7758909158a96fe80ce43b3bb96a9f" + integrity sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg== + dependencies: + "@kurkle/color" "^0.3.0" + chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -3712,7 +3724,7 @@ vitepress@^1.0.0-alpha.29: vite "^5.0.12" vue "^3.4.15" -vue-chartjs@^5.0.0: +vue-chartjs@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/vue-chartjs/-/vue-chartjs-5.3.0.tgz#59920a07d72f37a2375d495256e486b92813bf6e" integrity sha512-8XqX0JU8vFZ+WA2/knz4z3ThClduni2Nm0BMe2u0mXgTfd9pXrmJ07QBI+WAij5P/aPmPMX54HCE1seWL37ZdQ==