Merge pull request #592 from pateljannat/course-filter
feat: course filters
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
{% for course_row in courses %}
|
{% for course_row in courses %}
|
||||||
{% set course = frappe.db.get_value("LMS Course", course_row.course,
|
{% set course = frappe.db.get_value("LMS Course", course_row.course,
|
||||||
["name", "short_introduction", "upcoming", "title", "image", "currency",
|
["name", "short_introduction", "upcoming", "title", "image", "currency",
|
||||||
"enable_certification", "paid_certificate", "price_certificate"], as_dict=True) %}
|
"enable_certification", "paid_course", "course_price"], as_dict=True) %}
|
||||||
{{ widgets.CourseCard(course=course, read_only=False) }}
|
{{ widgets.CourseCard(course=course, read_only=False) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<div class="common-card-style course-card" data-course="{{ course.name }}">
|
<div class="common-card-style course-card" data-course="{{ course.name }}" data-rating="{{ course.avg_rating }}"
|
||||||
|
data-enrollment="{{ course.enrollment_count }}" data-creation="{{ course.creation }}">
|
||||||
|
|
||||||
<div class="course-image {% if not course.image %} default-image {% endif %}"
|
<div class="course-image {% if not course.image %} default-image {% endif %}"
|
||||||
{% if course.image %} style="background-image: url( {{ course.image | urlencode }} );" {% endif %}>
|
{% if course.image %} style="background-image: url( {{ course.image | urlencode }} );" {% endif %}>
|
||||||
@@ -40,23 +41,21 @@
|
|||||||
<div class="pull-right indicator-pill {{ pill_color }} "> {{ course.status }} </div>
|
<div class="pull-right indicator-pill {{ pill_color }} "> {{ course.status }} </div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% set student_count = get_students(course.name) | length %}
|
{% if course.enrollment_count %}
|
||||||
{% set avg_rating = get_average_rating(course.name) %}
|
|
||||||
{% if student_count %}
|
|
||||||
<div class="vertically-center">
|
<div class="vertically-center">
|
||||||
<svg class="icon icon-md">
|
<svg class="icon icon-md">
|
||||||
<use class="" href="#icon-users">
|
<use class="" href="#icon-users">
|
||||||
</svg>
|
</svg>
|
||||||
{{ student_count }}
|
{{ course.enrollment_count }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if avg_rating %}
|
{% if course.avg_rating %}
|
||||||
<div class="vertically-center">
|
<div class="vertically-center">
|
||||||
<svg class="icon icon-md">
|
<svg class="icon icon-md">
|
||||||
<use href="#icon-star"></use>
|
<use href="#icon-star"></use>
|
||||||
</svg>
|
</svg>
|
||||||
{{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }}
|
{{ frappe.utils.flt(course.avg_rating, frappe.get_system_settings("float_precision") or 3) }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from frappe import _
|
|||||||
from frappe.core.doctype.user.user import User
|
from frappe.core.doctype.user.user import User
|
||||||
from frappe.utils import cint, escape_html, random_string
|
from frappe.utils import cint, escape_html, random_string
|
||||||
from frappe.website.utils import is_signup_disabled
|
from frappe.website.utils import is_signup_disabled
|
||||||
from lms.lms.utils import validate_image
|
from lms.lms.utils import validate_image, get_average_rating
|
||||||
from frappe.website.utils import cleanup_page_name
|
from frappe.website.utils import cleanup_page_name
|
||||||
from frappe.model.naming import append_number_if_name_exists
|
from frappe.model.naming import append_number_if_name_exists
|
||||||
from lms.widgets import Widgets
|
from lms.widgets import Widgets
|
||||||
@@ -107,17 +107,25 @@ def get_enrolled_courses():
|
|||||||
"course_price",
|
"course_price",
|
||||||
"currency",
|
"currency",
|
||||||
"published",
|
"published",
|
||||||
|
"creation",
|
||||||
],
|
],
|
||||||
as_dict=True,
|
as_dict=True,
|
||||||
)
|
)
|
||||||
if not course.published:
|
if not course.published:
|
||||||
continue
|
continue
|
||||||
|
course.enrollment_count = frappe.db.count(
|
||||||
|
"LMS Batch Membership", {"course": course.name, "member_type": "Student"}
|
||||||
|
)
|
||||||
|
course.avg_rating = get_average_rating(course.name) or 0
|
||||||
progress = cint(membership.progress)
|
progress = cint(membership.progress)
|
||||||
if progress < 100:
|
if progress < 100:
|
||||||
in_progress.append(course)
|
in_progress.append(course)
|
||||||
else:
|
else:
|
||||||
completed.append(course)
|
completed.append(course)
|
||||||
|
|
||||||
|
in_progress.sort(key=lambda x: x.enrollment_count, reverse=True)
|
||||||
|
completed.sort(key=lambda x: x.enrollment_count, reverse=True)
|
||||||
|
|
||||||
return {"in_progress": in_progress, "completed": completed}
|
return {"in_progress": in_progress, "completed": completed}
|
||||||
|
|
||||||
|
|
||||||
@@ -153,14 +161,20 @@ def get_authored_courses(member=None, only_published=True):
|
|||||||
"currency",
|
"currency",
|
||||||
"status",
|
"status",
|
||||||
"published",
|
"published",
|
||||||
|
"creation",
|
||||||
],
|
],
|
||||||
as_dict=True,
|
as_dict=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
if only_published and detail and not detail.published:
|
if only_published and detail and not detail.published:
|
||||||
continue
|
continue
|
||||||
|
detail.enrollment_count = frappe.db.count(
|
||||||
|
"LMS Batch Membership", {"course": detail.name, "member_type": "Student"}
|
||||||
|
)
|
||||||
|
detail.avg_rating = get_average_rating(detail.name) or 0
|
||||||
course_details.append(detail)
|
course_details.append(detail)
|
||||||
|
|
||||||
|
course_details.sort(key=lambda x: x.enrollment_count, reverse=True)
|
||||||
return course_details
|
return course_details
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1963,10 +1963,6 @@ select {
|
|||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-list-cta {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-title {
|
.modal-title {
|
||||||
font-size: var(--text-lg) !important;
|
font-size: var(--text-lg) !important;
|
||||||
}
|
}
|
||||||
@@ -2034,15 +2030,24 @@ select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lms-menu {
|
.lms-menu {
|
||||||
|
background-color: var(--control-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: 0.15rem 0.5rem;
|
||||||
|
box-shadow: var(--btn-shadow);
|
||||||
background-image: url(/assets/lms/icons/down-arrow.svg);
|
background-image: url(/assets/lms/icons/down-arrow.svg);
|
||||||
background-position: right 0.5rem center;
|
background-position: right 0.5rem center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: 0.75rem;
|
background-size: 0.75rem;
|
||||||
padding-right: 2.5rem;
|
padding-right: 2rem;
|
||||||
text-align: left;
|
|
||||||
-webkit-print-color-adjust: exact;
|
-webkit-print-color-adjust: exact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lms-menu:focus-visible {
|
||||||
|
outline: var(--gray-500);
|
||||||
|
}
|
||||||
|
|
||||||
.clickable-row {
|
.clickable-row {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ frappe.ready(() => {
|
|||||||
$("#create-class").click((e) => {
|
$("#create-class").click((e) => {
|
||||||
open_class_dialog(e);
|
open_class_dialog(e);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#course-filter").change((e) => {
|
||||||
|
filter_courses(e);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const pin_header = () => {
|
const pin_header = () => {
|
||||||
@@ -354,3 +358,17 @@ const save_class = (values) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filter_courses = (e) => {
|
||||||
|
const course_lists = $(".course-cards-parent");
|
||||||
|
const filter = $(e.currentTarget).val();
|
||||||
|
course_lists.each((i, list) => {
|
||||||
|
const course_cards = $(list).children(".course-card");
|
||||||
|
course_cards.sort((a, b) => {
|
||||||
|
var value1 = $(a).data(filter);
|
||||||
|
var value2 = $(b).data(filter);
|
||||||
|
return value1 > value2 ? -1 : value1 < value2 ? 1 : 0;
|
||||||
|
});
|
||||||
|
$(list).append(course_cards);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="{{ classes }}">
|
<div class="{{ classes }}">
|
||||||
{% if courses | length %}
|
{% if courses | length %}
|
||||||
<div class="cards-parent">
|
<div class="course-cards-parent cards-parent">
|
||||||
{% for course in courses %}
|
{% for course in courses %}
|
||||||
{{ widgets.CourseCard(course=course, read_only=False) }}
|
{{ widgets.CourseCard(course=course, read_only=False) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -122,9 +122,11 @@
|
|||||||
|
|
||||||
{{ Notes(course) }}
|
{{ Notes(course) }}
|
||||||
|
|
||||||
|
{% if course.paid_course %}
|
||||||
<div class="vertically-center mb-3 bold-heading">
|
<div class="vertically-center mb-3 bold-heading">
|
||||||
{{ frappe.utils.fmt_money(course.course_price, 0, course.currency) }}
|
{{ frappe.utils.fmt_money(course.course_price, 0, course.currency) }}
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="vertically-center mb-3">
|
<div class="vertically-center mb-3">
|
||||||
<svg class="icon icon-md mr-1">
|
<svg class="icon icon-md mr-1">
|
||||||
|
|||||||
@@ -24,9 +24,25 @@
|
|||||||
|
|
||||||
{% include "lms/templates/search_course/search_course.html" %}
|
{% include "lms/templates/search_course/search_course.html" %}
|
||||||
|
|
||||||
<div class="course-list-cta">
|
<div class="flex align-center pull-right">
|
||||||
|
|
||||||
|
<select class="lms-menu" id="course-filter">
|
||||||
|
<option disabled value="">
|
||||||
|
{{ _("Sort By") }}
|
||||||
|
</option>
|
||||||
|
<option selected value="enrollment">
|
||||||
|
{{ _("Most Popular") }}
|
||||||
|
</option>
|
||||||
|
<option value="rating">
|
||||||
|
{{ _("Highest Rated") }}
|
||||||
|
</option>
|
||||||
|
<option value="creation">
|
||||||
|
{{ _("Newest") }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
{% if frappe.session.user != "Guest" %}
|
{% if frappe.session.user != "Guest" %}
|
||||||
<a class="btn btn-default btn-sm" href="/users">
|
<a class="btn btn-default btn-sm ml-2" href="/users">
|
||||||
{{ _("My Profile") }}
|
{{ _("My Profile") }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from lms.lms.utils import (
|
|||||||
get_restriction_details,
|
get_restriction_details,
|
||||||
has_course_moderator_role,
|
has_course_moderator_role,
|
||||||
get_courses_under_review,
|
get_courses_under_review,
|
||||||
|
get_average_rating,
|
||||||
)
|
)
|
||||||
from lms.overrides.user import get_enrolled_courses, get_authored_courses
|
from lms.overrides.user import get_enrolled_courses, get_authored_courses
|
||||||
|
|
||||||
@@ -48,13 +49,22 @@ def get_courses():
|
|||||||
"paid_course",
|
"paid_course",
|
||||||
"course_price",
|
"course_price",
|
||||||
"currency",
|
"currency",
|
||||||
|
"creation",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
live_courses, upcoming_courses = [], []
|
live_courses, upcoming_courses = [], []
|
||||||
for course in courses:
|
for course in courses:
|
||||||
|
course.enrollment_count = frappe.db.count(
|
||||||
|
"LMS Batch Membership", {"course": course.name, "member_type": "Student"}
|
||||||
|
)
|
||||||
|
course.avg_rating = get_average_rating(course.name) or 0
|
||||||
if course.upcoming:
|
if course.upcoming:
|
||||||
upcoming_courses.append(course)
|
upcoming_courses.append(course)
|
||||||
else:
|
else:
|
||||||
live_courses.append(course)
|
live_courses.append(course)
|
||||||
|
|
||||||
|
live_courses.sort(key=lambda x: x.enrollment_count, reverse=True)
|
||||||
|
upcoming_courses.sort(key=lambda x: x.enrollment_count, reverse=True)
|
||||||
|
|
||||||
return live_courses, upcoming_courses
|
return live_courses, upcoming_courses
|
||||||
|
|||||||
@@ -5,11 +5,6 @@
|
|||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% set read_only = member.name != frappe.session.user %}
|
|
||||||
{% set user = member.name %}
|
|
||||||
{% set courses_created = get_authored_courses(member.name, True) %}
|
|
||||||
{% set certificates = get_certificates(user) %}
|
|
||||||
|
|
||||||
<div class="common-page-style profile-page">
|
<div class="common-page-style profile-page">
|
||||||
{{ ProfileBanner(member) }}
|
{{ ProfileBanner(member) }}
|
||||||
<div class="profile-page-body">
|
<div class="profile-page-body">
|
||||||
@@ -82,14 +77,19 @@
|
|||||||
|
|
||||||
{% if not read_only %}
|
{% if not read_only %}
|
||||||
<div class="tab-pane fade" id="courses-enrolled" role="tabpanel" aria-labelledby="courses-enrolled">
|
<div class="tab-pane fade" id="courses-enrolled" role="tabpanel" aria-labelledby="courses-enrolled">
|
||||||
{% include "lms/lms/web_template/courses_enrolled/courses_enrolled.html" %}
|
{% set courses = enrolled_courses %}
|
||||||
|
{% set title = _("Enrolled Courses") %}
|
||||||
|
{% set classes = "enrolled-courses" %}
|
||||||
|
{% include "lms/templates/course_list.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if courses_created | length %}
|
{% if courses_created | length %}
|
||||||
{% set only_published = True %}
|
|
||||||
<div class="tab-pane fade" id="courses-created" role="tabpanel" aria-labelledby="courses-created">
|
<div class="tab-pane fade" id="courses-created" role="tabpanel" aria-labelledby="courses-created">
|
||||||
{% include "lms/templates/courses_created.html" %}
|
{% set courses = courses_created %}
|
||||||
|
{% set title = _("Created Courses") %}
|
||||||
|
{% set classes = "created-courses" %}
|
||||||
|
{% include "lms/templates/course_list.html" %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
@@ -249,7 +249,9 @@
|
|||||||
<!-- Career Preference -->
|
<!-- Career Preference -->
|
||||||
{% macro CareerPreference(member) %}
|
{% macro CareerPreference(member) %}
|
||||||
{% if member.preferred_functions or member.preferred_industries or member.preferred_location or member.dream_companies %}
|
{% if member.preferred_functions or member.preferred_industries or member.preferred_location or member.dream_companies %}
|
||||||
<div class="course-home-headings mt-10"> {{ _("Career Preference") }} </div>
|
<div class="course-home-headings mt-10">
|
||||||
|
{{ _("Career Preference") }}
|
||||||
|
</div>
|
||||||
<div class="profile-column-grid">
|
<div class="profile-column-grid">
|
||||||
|
|
||||||
{% if member.preferred_functions | length %}
|
{% if member.preferred_functions | length %}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import frappe
|
import frappe
|
||||||
|
|
||||||
from lms.lms.utils import get_lesson_index
|
from lms.lms.utils import get_lesson_index, get_certificates
|
||||||
from lms.page_renderers import get_profile_url_prefix
|
from lms.page_renderers import get_profile_url_prefix
|
||||||
|
from lms.overrides.user import get_authored_courses, get_enrolled_courses
|
||||||
|
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
@@ -17,6 +18,12 @@ def get_context(context):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
context.member = frappe.get_doc("User", {"username": username})
|
context.member = frappe.get_doc("User", {"username": username})
|
||||||
|
context.courses_created = get_authored_courses(context.member.name, True)
|
||||||
|
context.enrolled_courses = (
|
||||||
|
get_enrolled_courses()["in_progress"] + get_enrolled_courses()["completed"]
|
||||||
|
)
|
||||||
|
context.read_only = frappe.session.user != context.member.name
|
||||||
|
context.certificates = get_certificates(context.member.name)
|
||||||
except Exception:
|
except Exception:
|
||||||
context.template = "www/404.html"
|
context.template = "www/404.html"
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user