Merge pull request #300 from pateljannat/course-home-redesign

This commit is contained in:
Jannat Patel
2022-02-17 10:12:56 +05:30
committed by GitHub
27 changed files with 799 additions and 514 deletions

View File

@@ -26,6 +26,7 @@
{% endfor %}
</div>
{% if testimonials_table | length > 3 %}
<div class="slider-controls">
<a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
@@ -44,4 +45,6 @@
<span class="sr-only">Next</span>
</a>
</div>
{% endif %}
</div>

View File

@@ -12,10 +12,10 @@
<div class="common-card-style member-card">
{{ widgets.Avatar(member=member, avatar_class="avatar-large")}}
<div class="small-title member-card-title">
<div class=" member-card-title">
{{ member.full_name }}
</div>
<div class="small-title">
<div class="">
{{exhibitor_doc.company}}
</div>
<a class="stretched-link" href=""></a>

View File

@@ -12,10 +12,10 @@
<div class="common-card-style member-card">
{{ widgets.Avatar(member=member, avatar_class="avatar-large") }}
<div class="small-title member-card-title">
<div class=" member-card-title">
{{ member.full_name }}
</div>
<div class="small-title">
<div class="">
{{speaker_doc.company}}
</div>
<a class="stretched-link" href=""></a>

View File

@@ -60,7 +60,7 @@
<div class="course-card-meta-2">
{{ widgets.Avatar(member=member, avatar_class="avatar-small")}}
<span class="course-instructor"> {{ member.full_name }} </span>
<span class="small-title company-name"></span>
<span class=" company-name"></span>
</div>
<div class="view-talk-link">
Vew Talk

View File

@@ -182,6 +182,8 @@ jinja = {
"school.lms.utils.get_mentors",
"school.lms.utils.get_reviews",
"school.lms.utils.is_eligible_to_review",
"school.lms.utils.get_initial_members",
"school.lms.utils.get_sorted_reviews"
],
"filters": []
}

View File

@@ -6,6 +6,7 @@ from frappe.model.document import Document
from frappe.utils import nowdate, add_years
from frappe import _
from frappe.utils.pdf import get_pdf
from school.lms.utils import is_certified
class LMSCertification(Document):
@@ -22,8 +23,7 @@ class LMSCertification(Document):
@frappe.whitelist()
def create_certificate(course):
course_details = frappe.get_doc("LMS Course", course)
certificate = course_details.is_certified()
certificate = is_certified()
if certificate:
return certificate

View File

@@ -20,6 +20,14 @@ frappe.ui.form.on('LMS Course', {
}
};
});
frm.set_query("course", "related_courses", function () {
return {
filters: {
"is_published": true,
}
};
});
}
});

View File

@@ -10,7 +10,7 @@
"allow_guest_to_view": 1,
"allow_import": 1,
"allow_rename": 1,
"creation": "2021-03-01 16:49:33.622422",
"creation": "2022-02-08 16:34:42.721203",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
@@ -31,6 +31,7 @@
"short_introduction",
"description",
"chapters",
"related_courses",
"certification_section",
"enable_certification",
"expiry"
@@ -141,6 +142,12 @@
"fieldtype": "Select",
"label": "Certification Expires After Years",
"options": "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10"
},
{
"fieldname": "related_courses",
"fieldtype": "Table",
"label": "Related Courses",
"options": "Related Courses"
}
],
"index_web_pages_for_search": 1,
@@ -167,7 +174,7 @@
"link_fieldname": "course"
}
],
"modified": "2022-02-07 11:41:39.735325",
"modified": "2022-02-16 11:50:20.661085",
"modified_by": "Administrator",
"module": "LMS",
"name": "LMS Course",
@@ -192,4 +199,4 @@
"states": [],
"title_field": "title",
"track_changes": 1
}
}

View File

@@ -0,0 +1,8 @@
// Copyright (c) 2022, Frappe and contributors
// For license information, please see license.txt
frappe.ui.form.on('Related Courses', {
// refresh: function(frm) {
// }
});

View File

@@ -0,0 +1,32 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2022-02-16 11:45:07.200407",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"course"
],
"fields": [
{
"fieldname": "course",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Course",
"options": "LMS Course"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2022-02-16 11:48:30.964916",
"modified_by": "Administrator",
"module": "LMS",
"name": "Related Courses",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2022, Frappe and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class RelatedCourses(Document):
pass

View File

@@ -0,0 +1,8 @@
# Copyright (c) 2022, Frappe and Contributors
# See license.txt
# import frappe
import unittest
class TestRelatedCourses(unittest.TestCase):
pass

View File

@@ -1,6 +1,6 @@
import re
import frappe
from frappe.utils import flt, cint
from frappe.utils import flt, cint, cstr
from school.lms.md import markdown_to_html
RE_SLUG_NOTALLOWED = re.compile("[^a-z0-9]+")
@@ -128,7 +128,7 @@ def get_reviews(course):
{
"course": course
},
["review", "rating", "owner"],
["review", "rating", "owner", "creation"],
order_by= "creation desc")
out_of_ratings = frappe.db.get_all("DocField",
{
@@ -144,6 +144,22 @@ def get_reviews(course):
return reviews
def get_sorted_reviews(course):
rating_count = rating_percent = frappe._dict()
keys = ["5.0", "4.0", "3.0", "2.0", "1.0"]
for key in keys:
rating_count[key] = 0
reviews = get_reviews(course)
for review in reviews:
rating_count[cstr(review.rating)] += 1
for key in keys:
rating_percent[key] = (rating_count[key]/len(reviews) * 100)
return rating_percent
def is_certified(course):
certificate = frappe.get_all("LMS Certification",
{
@@ -258,3 +274,18 @@ def get_course_progress(course, member=None):
})
precision = cint(frappe.db.get_default("float_precision")) or 3
return flt(((completed_lessons/lesson_count) * 100), precision)
def get_initial_members(course):
members = frappe.get_all("LMS Batch Membership",
{
"course": course
},
["member"],
limit=3)
member_details = []
for member in members:
member_details.append(frappe.db.get_value("User",
member.member, ["name", "username", "full_name", "user_image"], as_dict=True))
return member_details

View File

@@ -7,10 +7,8 @@
{{ widgets.CourseCard(course=course, read_only=False) }}
{% endfor %}
</div>
<a class="button-links d-flex justify-content-center mt-12 intercative-link" style="color: var(--gray-800);" href="/courses">
<div>
Explore More
</div>
<img src="/assets/school/icons/arrow.svg" class="ml-2"/>
<a class="d-flex justify-content-center align-items-center mt-12" href="/courses">
<span>{{ _("Explore More") }}</span>
<img src="/assets/school/icons/blue-arrow.svg" class="ml-2"/>
</a>
</div>

View File

@@ -1,123 +0,0 @@
<div>
<div class="chapter-title small-title" data-target="#{{ get_slugified_chapter_title(chapter.title) }}"
data-toggle="collapse" aria-expanded="false">
<img class="chapter-icon" src="/assets/school/icons/chevron-right.svg">
{{ index }}. {{ chapter.title }}
</div>
<div class="chapter-content collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.title) }}">
{% if chapter.description %}
<div class="chapter-description muted-text">
{{ chapter.description }}
</div>
{% endif %}
{% set is_instructor = frappe.session.user == course.instructor %}
<div class="lessons">
{% for lesson in get_lessons(course.name, chapter) %}
<div class="lesson-info {% if membership.current_lesson == lesson.name %} active-lesson {% endif %}">
{% if membership or lesson.include_in_preview %}
<a class="lesson-links" href="{{ get_lesson_url(course.name, lesson.number) }}{{course.query_parameter}}"
data-course="{{ course.name }}">
{{ lesson.title }}
{% if membership %}
<img class="ml-1 lesson-progress-tick {{ get_progress(course.name, lesson.name) != 'Complete' and 'hide' }}"
src="/assets/school/icons/check.svg">
{% endif %}
</a>
{% elif is_instructor and not lesson.include_in_preview %}
<a class="lesson-links"
title="This lesson is not available for preview. As you are the Instructor of the course only you can see it."
href="{{ course.get_lesson_url(lesson.number) }}{{course.query_parameter}}"
data-course="{{ course.name }}">
{{ lesson.title }}
<img class="ml-2" src="/assets/school/icons/lock.svg">
</a>
{% else %}
<div class="no-preview" title="This lesson is not available for preview">
<div class="lesson-links">
{{ lesson.title }}
<img class="ml-2" src="/assets/school/icons/lock.svg">
</div>
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
</div>
{% if index != get_chapters(course.name) | length %}
<div class="card-divider"></div>
{% endif %}
<script>
frappe.ready(() => {
expand_the_active_chapter();
$(".chapter-title").unbind().click((e) => {
rotate_chapter_icon(e);
});
});
var expand_the_first_chapter = () => {
var elements = $(".course-outline .collapse");
elements.each((i, element) => {
if (i < 1) {
show_section(element);
return false;
}
});
}
var expand_the_active_chapter = () => {
/* Find anchor matching the URL for course details page */
var selector = $(`a[href="${decodeURIComponent(window.location.pathname)}"]`).parent();
if (!selector.length) {
selector = $(`a[href^="${decodeURIComponent(window.location.pathname)}"]`).parent();
}
if (selector.length && $(".course-details-page").length) {
$(".lesson-info").removeClass("active-lesson")
selector.addClass("active-lesson");
show_section(selector.parent().parent());
}
/* For course home page */
else if ($(".active-lesson").length) {
selector = $(".active-lesson")
show_section(selector.parent().parent());
}
/* If no active chapter then exapand the first chapter */
else {
expand_the_first_chapter();
}
}
var show_section = (element) => {
$(element).addClass("show");
$(element).siblings(".chapter-title").children(".chapter-icon").css("transform", "rotate(90deg)");
}
var rotate_chapter_icon = (e) => {
var icon = $(e.currentTarget).children(".chapter-icon");
if (icon.css("transform") == "none") {
icon.css("transform", "rotate(90deg)");
} else {
icon.css("transform", "none");
}
}
</script>

View File

@@ -58,11 +58,11 @@
{% endif %}
</span>
</a>
</span>
</span>
{% set student_count = get_students(course.name) | length %}
<span class="course-student-count">
{% if student_count %}
<span class="vertically-center mr-4">
<span class="vertically-center mr-3">
<img class="icon-background" src="/assets/school/icons/user.svg" />
{{ student_count }}
</span>
@@ -85,15 +85,8 @@
membership.current_lesson else '1.1' %}
{% set query_parameter = "?batch=" + membership.batch if membership and
membership.batch else "" %}
{% set certificate = is_certified(course.name) %}
{% if certificate %}
<a class="stretched-link" href="/courses/{{ course.name }}/{{ certificate }}"></a>
{% elif course.enable_certification and progress == 100 %}
<a class="stretched-link" id="certification" data-course="{{ course.name }}"></a>
{% elif progress == 100 %}
{% if progress == 100 %}
<a class="stretched-link" href="/courses/{{ course.name }}"></a>
{% elif course.upcoming %}
@@ -109,27 +102,3 @@
{% endif %}
</div>
</div>
<script>
frappe.ready(() => {
$("#certification").unbind().click((e) => {
create_certificate(e);
});
})
var create_certificate = (e) => {
e.preventDefault();
course = $(e.currentTarget).attr("data-course");
frappe.call({
method: "school.lms.doctype.lms_certification.lms_certification.create_certificate",
args: {
"course": course
},
callback: (data) => {
window.location.href = `/courses/${course}/${data.message}`;
}
})
}
</script>

View File

@@ -1,12 +1,131 @@
{% if get_chapters(course.name) | length %}
<div class="">
<div class="course-home-outline">
<div class="course-home-headings">
Course Outline
{{ _("Course Content") }}
</div>
<div class="common-card-style course-outline">
{% for chapter in get_chapters(course.name) %}
{{ widgets.ChapterTeaser(index=loop.index, chapter=chapter, course=course, batch=batch, membership=membership) }}
{% endfor %}
{% for chapter in get_chapters(course.name) %}
<div class="mb-2">
<div class="chapter-title" data-target="#{{ get_slugified_chapter_title(chapter.title) }}"
data-toggle="collapse" aria-expanded="false">
<img class="chapter-icon" src="/assets/school/icons/chevron-right.svg">
<div>{{ chapter.title }}</div>
</div>
<div class="chapter-content collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.title) }}">
{% if chapter.description %}
<div class="chapter-description muted-text">
{{ chapter.description }}
</div>
{% endif %}
{% set is_instructor = frappe.session.user == course.instructor %}
<div class="lessons">
{% for lesson in get_lessons(course.name, chapter) %}
<div class="lesson-info {% if membership.current_lesson == lesson.name %} active-lesson {% endif %}">
{% if membership or lesson.include_in_preview %}
<a class="lesson-links" href="{{ get_lesson_url(course.name, lesson.number) }}{{course.query_parameter}}"
data-course="{{ course.name }}">
{{ lesson.title }}
{% if membership %}
<img class="ml-1 lesson-progress-tick {{ get_progress(course.name, lesson.name) != 'Complete' and 'hide' }}"
src="/assets/school/icons/check.svg">
{% endif %}
</a>
{% elif is_instructor and not lesson.include_in_preview %}
<a class="lesson-links"
title="This lesson is not available for preview. As you are the Instructor of the course only you can see it."
href="{{ course.get_lesson_url(lesson.number) }}{{course.query_parameter}}"
data-course="{{ course.name }}">
<img class="mr-3" src="/assets/school/icons/lock.svg">
<div>{{ lesson.title }}</div>
</a>
{% else %}
<div class="no-preview" title="This lesson is not available for preview">
<div class="lesson-links">
<img class="mr-3" src="/assets/school/icons/lock.svg">
<div>{{ lesson.title }}</div>
</div>
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
<script>
frappe.ready(() => {
expand_the_active_chapter();
$(".chapter-title").unbind().click((e) => {
rotate_chapter_icon(e);
});
})
var expand_the_first_chapter = () => {
var elements = $(".course-outline .collapse");
elements.each((i, element) => {
if (i < 1) {
show_section(element);
return false;
}
});
}
var expand_the_active_chapter = () => {
/* Find anchor matching the URL for course details page */
var selector = $(`a[href="${decodeURIComponent(window.location.pathname)}"]`).parent();
if (!selector.length) {
selector = $(`a[href^="${decodeURIComponent(window.location.pathname)}"]`).parent();
}
if (selector.length && $(".course-details-page").length) {
$(".lesson-info").removeClass("active-lesson")
selector.addClass("active-lesson");
show_section(selector.parent().parent());
}
/* For course home page */
else if ($(".active-lesson").length) {
selector = $(".active-lesson")
show_section(selector.parent().parent());
}
/* If no active chapter then exapand the first chapter */
else {
expand_the_first_chapter();
}
}
var show_section = (element) => {
$(element).addClass("show");
$(element).siblings(".chapter-title").children(".chapter-icon").css("transform", "rotate(90deg)");
$(element).siblings(".chapter-title").attr("aria-expanded", true);
}
var rotate_chapter_icon = (e) => {
var icon = $(e.currentTarget).children(".chapter-icon");
if (icon.css("transform") == "none") {
icon.css("transform", "rotate(90deg)");
} else {
icon.css("transform", "none");
}
}
</script>

View File

@@ -1,12 +1,12 @@
<div class="common-card-style member-card">
{{ widgets.Avatar(member=member, avatar_class=avatar_class) }}
<div class="small-title member-card-title {% if show_course_count %} font-weight-bold {% endif %}">
<div class=" member-card-title {% if show_course_count %} font-weight-bold {% endif %}">
{{ member.full_name }}
</div>
{% set course_count = get_authored_courses(member.name) | length %}
{% if show_course_count and course_count > 0 %}
{% set suffix = "Courses" if course_count > 1 else "Course" %}
<div class="small-title">
<div class="">
Created {{ course_count }} {{ suffix }}
</div>
{% endif %}

View File

@@ -10,29 +10,76 @@
{% endif %}
</div>
{% if reviews | length %}
<div class="reviews-section">
{% for review in reviews %}
<div class="review-card">
<div class="common-card-style review-content small-title"> {{ review.review }} </div>
<div class="review-card-footer">
<div>
{{ widgets.Avatar(member=review.owner_details, avatar_class="avatar-medium") }}
<a class="button-links" href="{{get_profile_url(review.owner_details.username) }}">
<span class="course-instructor">
{{ review.owner_details.full_name }}
</span>
</a>
</div>
{% set avg_rating = get_average_rating(course.name) %}
<div class="reviews-header">
<div class="text-center">
<div class="avg-rating"> {{ avg_rating }} </div>
<div class="course-meta"> {{ reviews | length }} {{ _("ratings") }} </div>
<div class="avg-rating-stars">
<div class="rating">
{% for i in [1, 2, 3, 4, 5] %}
<svg class="icon icon-md {% if i <= review.rating %} star-click {% endif %}" data-rating="{{ i }}">
<svg class="icon icon-md {% if i <= avg_rating %} star-click {% endif %}" data-rating="{{ i }}">
<use href="#icon-star"></use>
</svg>
{% endfor %}
</div>
</div>
<div class="course-meta"> {{ avg_rating }} {{ _("out of 5 ") }} </div>
</div>
<div class="vertical-divider"></div>
{% set sorted_reviews = get_sorted_reviews(course.name) %}
<div>
{% for review in sorted_reviews %}
<div class="d-flex align-items-center mb-3">
<div class="course-meta mr-2"> {{ frappe.utils.cint(review) }} {{ _("stars") }} </div>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="{{ sorted_reviews[review] }}"
aria-valuemin="0" aria-valuemax="100" style="width:{{ sorted_reviews[review] }}%">
<span class="sr-only"> {{ sorted_reviews[review] }} Complete</span>
</div>
</div>
<div class="course-meta ml-3"> {{ frappe.utils.cint(sorted_reviews[review]) }}% </div>
</div>
{% endfor %}
</div>
</div>
{% if reviews | length %}
<div class="mt-12">
{% for review in reviews %}
<div class="">
<div class="review-card-footer">
<div class="d-flex align-items-center">
<div class="mr-5">
{{ widgets.Avatar(member=review.owner_details, avatar_class="avatar-medium") }}
</div>
<div>
<a class="button-links" href="{{get_profile_url(review.owner_details.username) }}">
<span class="review-author">
{{ review.owner_details.full_name }}
</span>
</a>
<div class="rating">
{% for i in [1, 2, 3, 4, 5] %}
<svg class="icon icon-md {% if i <= review.rating %} star-click {% endif %}" data-rating="{{ i }}">
<use href="#icon-star"></use>
</svg>
{% endfor %}
</div>
</div>
</div>
<div class="ml-16 mt-4">
<div> {{ review.review }} </div>
<div class="frappe-timestamp mt-2 mb-6 course-meta" data-timestamp="{{ review.creation }}"> frappe.utils.pretty_date(review.creation) </div>
</div>
</div>
</div>
{% if loop.index != reviews | length %}
<div class="card-divider"></div>
{% endif %}
{% endfor %}
</div>

View File

@@ -8,10 +8,15 @@
--text-2xl: 20px;
--text-3xl: 22px;
--text-3-5xl: 24px;
--text-3-8xl: 34px;
--text-4xl: 44px;
--navbar-shadow: 0px 1px 8px rgba(0, 0, 0, 0.08);
}
body {
background-color: #FFFFFF;
}
input[type=checkbox] {
appearance: auto;
}
@@ -19,8 +24,6 @@ input[type=checkbox] {
.course-image {
height: 168px;
width: 100%;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
@@ -66,6 +69,7 @@ input[type=checkbox] {
font-weight: 600;
box-shadow: var(--popover-box-shadow);
color: var(--gray-900);
width: fit-content;
}
.dark-pills {
@@ -96,6 +100,7 @@ input[type=checkbox] {
flex-direction: column;
height: 100%;
min-height: 350px;
overflow: auto;
}
.muted-text {
@@ -120,6 +125,12 @@ input[type=checkbox] {
flex: 1 1 auto;
}
@media (max-width: 400px) {
.course-card-content {
padding: 0 0.5rem 1.25rem;
}
}
@media (max-width: 350px) {
.course-card-content {
padding: 0px 10px 10px;
@@ -155,6 +166,12 @@ input[type=checkbox] {
color: var(--gray-700);
}
@media (max-width: 400px) {
.course-instructor {
margin-left: 0;
}
}
.course-student-count {
display: flex;
font-size: 12px;
@@ -279,7 +296,6 @@ input[type=checkbox] {
}
.review-card-footer {
display: flex;
margin-top: 20px;
justify-content: space-between;
}
@@ -293,10 +309,6 @@ input[type=checkbox] {
width: 100px;
}
.rating .star-click {
--star-fill: #74808B;
}
.custom-checkbox {
display: flex;
align-items: center;
@@ -329,26 +341,13 @@ input[type=checkbox] {
}
.course-card-wide {
display: flex;
flex-direction: row;
padding: 24px;
background: #E2E6E9;
border-radius: var(--border-radius-md);
margin-top: 16px;
box-shadow: 0px 2px 1px rgba(0, 0, 0, 0.02), 0px 0px 8px rgba(0, 0, 0, 0.04);
margin-top: 1rem;
width: 60%;
}
@media (max-width: 768px) {
.course-card-wide {
flex-direction: column;
}
}
@media (max-width: 600px) {
.course-card-wide {
padding: 40px 24px 40px;
border-radius: 0px;
align-items: center;
width: 100%;
}
}
@@ -380,13 +379,6 @@ input[type=checkbox] {
}
}
@media (max-width: 500px) {
.course-home-page {
padding-right: 0;
padding-left: 0;
}
}
.course-card-wide-content {
display: flex;
flex-direction: column;
@@ -394,49 +386,12 @@ input[type=checkbox] {
justify-content: space-between;
}
@media (max-width: 768px) {
.course-card-wide-content {
width: 100%;
}
}
@media (max-width: 600px) {
.course-card-wide-content {
width: 90%;
align-items: center;
}
}
.course-card-wide-title {
font-style: normal;
font-weight: 600;
font-size: 40px;
line-height: 120%;
color: var(--gray-800);
margin-bottom: 8px;
}
@media (max-width: 768px) {
.course-card-wide-title {
margin-top: 24px;
font-size: 36px;
}
}
@media (max-width: 600px) {
.course-card-wide-title {
margin-top: 16px;
font-size: 28px;
}
}
.course-card-wide-intro {
font-size: 16px;
line-height: 172%;
letter-spacing: -0.011em;
margin-bottom: 16px;
display: flex;
flex-wrap: wrap;
font-weight: bold;
font-size: 36px;
line-height: 44px;
color: var(--gray-900);
margin-bottom: 0.75rem;
}
.button {
@@ -449,6 +404,7 @@ input[type=checkbox] {
padding: 0.25rem 1.25rem;
font-size: var(--text-md);
line-height: 20px;
box-shadow: var(--btn-shadow);
}
.button:disabled {
@@ -456,16 +412,13 @@ input[type=checkbox] {
}
.wide-button {
padding: 12px 24px 12px;
height: 48px;
margin-right: 16px;
font-size: 16px;
line-height: 150%;
padding: 0.5rem 6rem;
font-weight: 500;
}
@media (max-width: 600px) {
@media (max-width: 768px) {
.wide-button {
width: 264px;
padding: 0.5rem 4rem;
}
}
@@ -499,28 +452,26 @@ input[type=checkbox] {
color: #FFFFFF;
}
.course-home-outline {
margin-top: 3rem;
}
.small-title {
letter-spacing: -0.011em;
.course-home-page .course-home-outline {
margin: 5rem 0 4rem;
}
.chapter-title {
font-weight: bold;
margin: 0 .25rem 0;
font-weight: 500;
cursor: pointer;
border-radius: var(--border-radius-lg);
padding: 0.75rem 0;
color: var(--gray-900);
display: flex;
align-items: center;
padding-bottom: 1rem;
}
.chapter-title[aria-expanded="true"] {
background: var(--gray-100);
}
.chapter-description {
height: fit-content;
padding-left: 1rem;
padding-right: 1rem;
margin-bottom: 0.75rem;
margin: 0.75rem 3rem 1rem;
}
.course-content-parent .chapter-description {
@@ -528,7 +479,7 @@ input[type=checkbox] {
}
.chapter-icon {
margin-right: .25rem;
margin: 0 1.25rem;
}
.course-outline-instructor-parent {
@@ -579,17 +530,11 @@ input[type=checkbox] {
}
.reviews-parent {
margin-top: 3rem;
}
@media (max-width: 600px) {
.reviews-parent {
padding: 0px 24px 0px;
}
margin: 5rem 0;
}
.course-description-section {
margin-top: 3rem;
margin-top: 3.75rem;
}
.course-overview-section {
@@ -600,21 +545,20 @@ input[type=checkbox] {
font-size: 16px;
line-height: 250%;
letter-spacing: -0.011em;
margin-top: 0.5rem;
}
.lesson-links {
display: flex;
padding: 0 1rem;
margin-bottom: .25rem;
color: inherit;
}
.lesson-links:hover {
cursor: pointer;
text-decoration: none;
background: #F4F5F6;
color: inherit;
border-radius: var(--border-radius-sm);
border-radius: var(--border-radius-md);
}
.course-content-parent .lesson-links {
@@ -635,7 +579,7 @@ input[type=checkbox] {
}
.lessons {
margin-bottom: 1rem;
margin-left: 2rem;
}
.course-buttons {
@@ -906,9 +850,9 @@ input[type=checkbox] {
.breadcrumb {
display: flex;
align-items: center;
font-size: 12px;
line-height: 135%;
color: var(--gray-800);
font-size: var(--text-md);
line-height: 20px;
color: var(--gray-900);
}
.course-details-outline {
@@ -962,8 +906,8 @@ input[type=checkbox] {
}
.active-lesson {
background-color: #EBF5FF;
border-radius: var(--border-radius-sm);
background-color: var(--gray-100);
border-radius: var(--border-radius-md);
}
.lesson-progress {
@@ -1194,6 +1138,10 @@ input[type=checkbox] {
height: 4px;
}
.course-card-wide .progress {
background-color: var(--gray-500);
}
.progress-bar {
background-color: var(--primary-color);
}
@@ -1324,19 +1272,6 @@ pre {
.navbar {
box-shadow: var(--navbar-shadow);
}
.interactive-arrow {
background-image: url("/assets/school/icons/arrow.svg");
width: 1.5rem;
height: 1.5rem;
margin-left: 0.5rem;
}
.intercative-link:hover .interactive-arrow{
background-image: url("/assets/school/icons/blue-arrow.svg");
margin-left: 1.5rem;
}
.search {
background-image: url(/assets/frappe/icons/timeless/search.svg);
border: 1px solid #C8CFD5;
@@ -1403,8 +1338,22 @@ pre {
}
.carousel-control-prev, .carousel-control-next {
position: inherit;
width: auto;
top: 30%;
height: fit-content;
background: white;
border-radius: 50%;
box-shadow: var(--shadow-sm);
opacity: 1;
}
.related-courses .carousel-control-prev, .related-courses .carousel-control-next {
top: 40%;
}
.related-courses {
background: var(--gray-50);
padding: 5rem 0;
}
.carousel-indicators {
@@ -1412,6 +1361,16 @@ pre {
margin: 0;
}
.carousel {
padding: 0 1rem;
}
@media (max-width: 500px) {
.carousel {
padding: 0 0.5rem;
}
}
.slider-controls {
display: flex;
align-items: center;
@@ -1563,3 +1522,170 @@ pre {
content: "\00B7";
margin: 0 8px;
}
.course-head-container {
color: var(--gray-900);
}
.course-intructor-rating-section {
display: flex;
align-items: center;
margin-top: 3.5rem;
}
.course-intructor-rating-section .seperator::before {
content: "\00B7";
margin: 0 1rem;
}
.course-head-container .progress {
margin-top: 2.75rem;
}
.course-overlay-card {
background-color: white;
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-sm);
overflow: auto;
width: fit-content;
position: absolute;
top: 40%;
right: 7%;
max-width: 400px;
}
@media (max-width: 768px) {
.course-overlay-card {
position: inherit;
margin-top: 1rem;
}
.course-intructor-rating-section .seperator::before {
content: "\00B7";
margin: 0 0.25rem;
}
}
.video-in-overlay {
top: 30%;
}
.course-overlay-content {
padding: 1.25rem;
font-size: var(--text-base);
color: var(--gray-700);
}
.breadcrumb-destination {
color: var(--gray-600);
}
.preview-video {
width: 100%;
height: 190px;
border: none;
}
.course-body-container {
width: 60%;
}
@media (max-width: 768px) {
.course-body-container {
width: 100%;
}
}
.overlay-heading {
margin-top: 2rem;
font-weight: 600;
color: var(--gray-800);
}
.overlay-student-count {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 1.5rem;
}
.course-creators-card {
display: grid;
grid-gap: 1rem;
padding: 1rem;
background-color: var(--gray-100);
box-shadow: none;
}
.course-creator-name {
font-size: var(--text-xl);
font-weight: 500;
color: var(--gray-900);
}
.course-meta {
font-size: var(--text-base);
color: var(--gray-600);
}
.avg-rating {
font-size: var(--text-3-8xl);
color: var(--gray-900);
font-weight: bold;
}
.reviews-header {
display: flex;
justify-content: space-between;
width: 75%;
}
@media (max-width: 768px) {
.reviews-header {
width: 100%;
}
}
@media (max-width: 500px) {
.reviews-header {
flex-direction: column;
align-items: center;
}
.vertical-divider {
margin: 1rem 0;
}
}
.review-author {
font-size: var(--text-lg);
color: var(--gray-900);
font-weight: 600;
}
.star-click {
--star-fill: var(--yellow-500);
}
.rating {
--star-fill: var(--gray-400);
}
.vertical-divider {
border: 1px solid var(--gray-300);
}
.avg-rating-stars {
background: var(--gray-200);
border-radius: 100px;
padding: 0.5rem 0.75rem;
margin: 1.25rem 0 0.5rem;
}
.reviews-parent .progress {
width: 200px;
}
.reviews-parent .progress-bar {
background-color: var(--gray-600);
}

View File

@@ -0,0 +1,7 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.25 7.5375L14.625 6.1875" stroke="#687178" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.375 6.1875L6.75 7.5375" stroke="#687178" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.25 12.0375L14.625 10.6875" stroke="#687178" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3.375 10.6875L6.75 12.0375" stroke="#687178" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M0.5625 0.5625L9 3.9375L17.4375 0.5625V14.0625L9 17.4375L0.5625 14.0625V0.5625Z" stroke="#687178" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 790 B

View File

@@ -1,4 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.3333 14V12.6667C13.3333 11.9594 13.0524 11.2811 12.5523 10.781C12.0522 10.281 11.3739 10 10.6667 10H5.33332C4.62608 10 3.9478 10.281 3.4477 10.781C2.94761 11.2811 2.66666 11.9594 2.66666 12.6667V14" stroke="#687178" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8.00001 7.33333C9.47277 7.33333 10.6667 6.13943 10.6667 4.66667C10.6667 3.19391 9.47277 2 8.00001 2C6.52725 2 5.33334 3.19391 5.33334 4.66667C5.33334 6.13943 6.52725 7.33333 8.00001 7.33333Z" stroke="#687178" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.3334 14V12.6667C13.3334 11.9594 13.0525 11.2811 12.5524 10.781C12.0523 10.281 11.374 10 10.6667 10H5.33341C4.62617 10 3.94789 10.281 3.4478 10.781C2.9477 11.2811 2.66675 11.9594 2.66675 12.6667V14" stroke="#687178" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.99992 7.33333C9.47268 7.33333 10.6666 6.13943 10.6666 4.66667C10.6666 3.19391 9.47268 2 7.99992 2C6.52716 2 5.33325 3.19391 5.33325 4.66667C5.33325 6.13943 6.52716 7.33333 7.99992 7.33333Z" stroke="#687178" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 648 B

View File

@@ -104,7 +104,7 @@ const mark_progress = (e) => {
callback: (data) => {
change_progress_indicators(status, e);
show_certificate_if_course_completed(data);
move_to_next_lesson(e);
move_to_next_lesson(status, e);
}
});
}
@@ -134,10 +134,20 @@ const show_certificate_if_course_completed = (data) => {
}
};
const move_to_next_lesson = (e) => {
const move_to_next_lesson = (status, e) => {
if ($(e.currentTarget).hasClass("next") && $(e.currentTarget).attr("data-href")) {
window.location.href = $(e.currentTarget).attr("data-href");
}
else if (status == "Complete") {
$("input.mark-progress").closest(".custom-checkbox").addClass("hide");
$("div.mark-progress").removeClass("hide");
$(".next").addClass("hide");
}
else {
$("input.mark-progress").closest(".custom-checkbox").removeClass("hide");
$("div.mark-progress").addClass("hide");
$(".next").removeClass("hide");
}
};
const quiz_summary = (e) => {

View File

@@ -1,234 +1,249 @@
{% extends "templates/base.html" %}
{% from "www/macros/common_macro.html" import MentorsSection %}
{% block title %}{{ course.title }}
{% endblock %}
{% block head_include %}
<link rel="stylesheet" href="/assets/frappe/css/font-awesome.css">
{% endblock %}
{% block content %}
<div class="common-page-style">
<div class="common-page-style pt-0">
{{ CourseHomeHeader(course) }}
<div class="container course-home-page">
{{ widgets.BreadCrumb(course=course) }}
{{ CourseCardWide(course) }}
{{ CourseSections(course) }}
{{ Mentors(course) }}
{{ widgets.Reviews(course=course, membership=membership) }}
<div class="course-body-container">
{{ Description(course) }}
{{ widgets.CourseOutline(course=course, membership=membership) }}
{{ CourseCreator(course) }}
{{ widgets.Reviews(course=course, membership=membership) }}
</div>
</div>
{{ RelatedCourses(course) }}
</div>
{% endblock %}
{% macro CourseHomeHeader(course) %}
<div class="course-head-container"
style=" {% if course.image %} background-position: center; background-size: cover; background-image: url({{ course.image }});
{% else %} background-color: var(--gray-200) {% endif %}">
<div class="container pt-10 pb-10">
{{ BreadCrumb(course) }}
{{ CourseCardWide(course) }}
{{ CourseHeaderOverlay(course) }}
</div>
</div>
{% endmacro %}
<!-- BreadCrumb -->
{% macro BreadCrumb(course) %}
<div class="breadcrumb">
<a class="dark-links" href="/courses">{{ _("All Courses") }}</a>
<img class="ml-2 mr-2" src="/assets/school/icons/chevron-right.svg">
<span class="breadcrumb-destination">{{ course.title }}</span>
</div>
{% endmacro %}
<!-- Course Card -->
{% macro CourseCardWide(course) %}
<div class="common-card-style course-card-wide">
<div class="course-image-wide {% if not course.image %} default-image {% endif %}" {% if course.image
%}style="background-image: url({{ course.image }});" {% endif %}>
<div class="course-tags">
{% for tag in course.get_tags() %}
<div class="course-card-pills">{{ tag }}</div>
<div class="course-card-wide">
<div class="d-flex align-items-center">
{% for tag in get_tags(course.name) %}
<div class="course-card-pills">{{ tag }}</div>
{% endfor %}
</div>
<div class="course-card-wide-title">
{{ course.title }}
</div>
<div class="">
{{ course.short_introduction }}
</div>
<div class="course-intructor-rating-section">
<div class="d-flex align-items-center">
{% set instructors = get_instructors(course.name) %}
{% set ins_len = instructors | length %}
{% for instructor in instructors %}
{% if ins_len > 1 and loop.index == 1 %}
<div class="avatar-group overlap">
{% endif %}
{{ widgets.Avatar(member=instructor, avatar_class="avatar-small") }}
{% if ins_len > 1 and loop.index == ins_len %}
</div>
{% endif %}
{% endfor %}
<a class="button-links" href="{{ get_profile_url(instructors[0].username) }}">
<span class="course-instructor">
{% if ins_len == 1 %}
{{ instructors[0].full_name }}
{% else %}
{% set suffix = "other" if ins_len - 1 == 1 else "others" %}
{{ instructors[0].full_name.split(" ")[0] }} and {{ ins_len - 1 }} {{ suffix }}
{% endif %}
</span>
</a>
</div>
<span class="seperator"></span>
{% set avg_rating = get_average_rating(course.name) %}
{% if avg_rating %}
<div class="rating mr-2">
{% for i in [1, 2, 3, 4, 5] %}
<svg class="icon icon-md {% if i <= avg_rating %} star-click {% endif %}" data-rating="{{ i }}">
<use href="#icon-star"></use>
</svg>
{% endfor %}
</div>
{% if not course.image %}
<div class="default-image-text">{{ course.title[0] }}</div>
<span> {{ avg_rating }} {{ _(" Rating ") }} </span>
{% endif %}
</div>
<div class="course-card-wide-content">
<div class="course-info">
<div class="course-card-wide-title">
{{ course.title }}
</div>
<div class="course-card-wide-intro">
{{ course.short_introduction }}
</div>
</div>
<div class="course-buttons">
{% if not course.disable_self_learning and not membership and not course.upcoming and not restriction.restrict %}
<div class="button wide-button start-learning is-primary join-batch" data-course="{{ course.name | urlencode }}">
{{ _("Start Learning") }}
<img class="ml-2" src="/assets/school/icons/white-arrow.svg" />
</div>
{% endif %}
{% if membership %}
{% set lesson_index = get_lesson_index(membership.current_lesson) if membership and
membership.current_lesson
else '1.1' %}
<a class="button wide-button is-primary" id="continue-learning"
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
Continue Learning <img class="ml-2" src="/assets/school/icons/white-arrow.svg" />
</a>
{% endif %}
{% if course.upcoming and not is_user_interested %}
<button class="button wide-button is-default"
id="notify-me" data-course="{{course.name | urlencode}}">
Notify me when available
</button>
{% endif %}
{% if course.video_link %}
<div class="button wide-button is-secondary video-preview">
Watch Video Preview
<img class="ml-2" src="/assets/school/images/play.png" />
</div>
{% endif %}
{% if is_cohort_staff(course.name, frappe.session.user) %}
<a class="button wide-button is-secondary"
href="/courses/{{course.name}}/manage"
style="color: inherit;">
Manage the course
</a>
{% endif %}
{% if membership %}
{% set progress = frappe.utils.cint(membership.progress) %}
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="{{ progress }}"
aria-valuemin="0" aria-valuemax="100" style="width:{{ progress }}%">
<span class="sr-only"> {{ progress }} Complete</span>
</div>
</div>
<div class="progress-percent">{{ progress }}% Completed</div>
{% endif %}
</div>
<div id="interest-alert" class="alert alert-dismissible empty-state p-4 mt-10 {% if not is_user_interested %} hide {% endif %}">
You have opted to be notified for this course. You will receive an email when the course becomes available.
<a href="#" class="close p-4" data-dismiss="alert" aria-label="close">&times;</a>
</div>
{% if course.video_link %}
<div class="modal fade preview-modal" id="video-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<div class="course-home-headings modal-headings">{{ course.title }}</div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<iframe class="video-iframe" frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen src="{{ course.video_link }}"></iframe>
</div>
</div>
</div>
</div>
{% endif %}
{% endmacro%}
<!-- Course Outline and Creator -->
{% macro CourseHeaderOverlay(course) %}
<div class="course-overlay-card {% if course.video_link %} video-in-overlay {% endif %}">
{% macro CourseSections(course) %}
<div class="course-outline-instructor-parent">
<div class="course-home-outline">
{{ widgets.CourseOutline(course=course, membership=membership) }}
{{ Description(course) }}
</div>
<div class="course-creator-progress-parent">
{{ CreatorSection(course) }}
{{ Progress(course) }}
{{ Overview(course) }}
</div>
</div>
{% endmacro %}
{% if course.video_link %}
<iframe class="preview-video" src="{{ course.video_link }}"></iframe>
{% endif %}
{% macro CreatorSection(course) %}
<div class="course-creator-section">
<div class="course-home-headings">
Creator
</div>
{% for instructor in get_instructors(course.name) %}
{{ widgets.MemberCard(member=instructor, show_course_count=True, avatar_class="avatar-large") }}
{% endfor %}
</div>
{% endmacro %}
<div class="course-overlay-content">
{% macro Progress(course) %}
{% set certificate = is_certified(course.name) %}
{% set progress = frappe.utils.cint(membership.progress) %}
{% if progress %}
<div class="course-progress-section">
<div class="course-home-headings">
Your Progress
</div>
<div class="common-card-style progress-card">
<p class="small-title">
{% if progress != 100 %}
Great work so far!
{% else %}
Excellent work on completing this course 👏
{% endif %}
</p>
<p class="progress-text">
{% if progress != 100 %}
Challenge yourself to complete the lessons and grow professionally.
{% else %}
You have reached a new level in your journey to success!
{% endif %}
</p>
<div class="progress-percentage">
{{ frappe.utils.rounded(progress) }}%
<div id="interest-alert" class="{% if not is_user_interested %} hide {% endif %}">
You have opted to be notified for this course. You will receive an email when the course becomes available.
</div>
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: {{ progress }}%" aria-valuenow="{{ progress }}"
aria-valuemin="0" aria-valuemax="100"></div>
{% if get_students(course.name) | length %}
{% set initial_members = get_initial_members(course.name) %}
<div class="overlay-student-count">
{% for member in initial_members %}
{% if initial_members | length > 1 and loop.index == 1 %}
<div class="avatar-group overlap">
{% endif %}
{{ widgets.Avatar(member=member, avatar_class="avatar-small") }}
{% if initial_members | length > 1 and loop.index == initial_members | length %}
</div>
{% endif %}
{% endfor %}
<div class="course-meta ml-2">{{ get_students(course.name) | length }} {{ _("Enrolled") }} </div>
</div>
{% endif %}
{% if not course.disable_self_learning and not membership and not course.upcoming and not restriction.restrict %}
<div class="button wide-button start-learning is-primary join-batch" data-course="{{ course.name | urlencode }}">
{{ _("Start Learning") }}
<img class="ml-2" src="/assets/school/icons/white-arrow.svg" />
</div>
{% endif %}
{% if membership %}
{% set lesson_index = get_lesson_index(membership.current_lesson) if membership and
membership.current_lesson
else '1.1' %}
<a class="button wide-button is-primary" id="continue-learning"
href="{{ get_lesson_url(course.name, lesson_index) }}{{ course.query_parameter }}">
Continue Learning <img class="ml-2" src="/assets/school/icons/white-arrow.svg" />
</a>
{% endif %}
{% if course.upcoming and not is_user_interested %}
<div class="button wide-button is-default"
id="notify-me" data-course="{{course.name | urlencode}}">
Notify me when available
</div>
{% endif %}
{% if is_cohort_staff(course.name, frappe.session.user) %}
<a class="button wide-button is-secondary"
href="/courses/{{course.name}}/manage"
style="color: inherit;">
Manage the course
</a>
{% endif %}
<div class="overlay-heading"> {{ _("Course Include:") }} </div>
{% if get_lessons(course.name) | length %}
<div class="mt-3">
<img class="mr-3" src="/assets/school/icons/book.svg">
{{ get_lessons(course.name) | length }} {{ _("Lessons") }}
</div>
{% if certificate %}
<a class="muted-text dark-links mt-5 text-center" href="/courses/{{ course.name }}/{{ certificate }}">Get
Certificate</a>
{% endif %}
</div>
</div>
{% endif %}
{% endmacro %}
{% macro Description(course) %}
<div class="course-description-section">
<div class="course-home-headings">
Course Description
</div>
<div class="common-card-style description-card">
{{ frappe.utils.md_to_html(course.description) }}
</div>
{{ frappe.utils.md_to_html(course.description) }}
</div>
{% endmacro %}
{% macro Overview(course) %}
{% set avg_rating = get_average_rating(course.name) %}
{% if get_students(course.name) | length or avg_rating %}
<div class="course-overview-section">
<div class="course-home-headings">
Overview
</div>
<div class="common-card-style overview-card small-title">
{% if get_students(course.name) | length %}
<div class="overview-item">
<img class="icon-background mr-1" src="/assets/school/icons/user.svg" />
{{ get_students(course.name) | length }} Enrolled
{% macro CourseCreator(course) %}
<div class="course-home-headings"> {{ _("Course Creators") }} </div>
<div class="common-card-style course-creators-card">
{% set instructors = get_instructors(course.name) %}
{% for instructor in instructors %}
<div class="d-flex align-items-center">
{{ widgets.Avatar(member=instructor, avatar_class="avatar-medium") }}
<div class="ml-4">
<div class="course-creator-name"> {{ instructor.full_name }} </div>
<div class="course-meta"> {{ get_authored_courses(instructor.name) | length }} {{ _("Courses Created") }} </div>
</div>
{% endif %}
{% if avg_rating %}
<div class="overview-item">
<img class="icon-background mr-1" src="/assets/school/icons/rating.svg" />
{{ frappe.utils.flt(avg_rating, frappe.get_system_settings("float_precision") or 3) }} Rating
</div>
{% endfor %}
</div>
{% endmacro %}
{% macro RelatedCourses(course) %}
{% if course.related_courses | length %}
<div class="related-courses">
<div class="container">
<div class="course-home-headings"> {{ _("Other Courses") }} </div>
<div class="carousel slide" id="carouselExampleControls" data-ride="carousel" data-interval="false">
<div class="carousel-inner">
{% for crs in course.related_courses %}
{% if loop.index % 3 == 1 %}
<div class="carousel-item {% if loop.index == 1 %} active {% endif %}"><div class="cards-parent">
{% endif %}
{{ widgets.CourseCard(course=crs, read_only=False) }}
{% if loop.index % 3 == 0 or loop.index == course.related_courses | length %} </div> </div> {% endif %}
{% endfor %}
</div>
{% if course.related_courses | length > 3 %}
<div class="slider-controls">
<a class="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
{% endif %}
{% endmacro %}
<!-- Mentors -->
{% macro Mentors(course) %}
{% if get_mentors(course.name) | length %}
<div class="course-home-mentors">
<div class="course-home-headings">
Mentors
</div>
<div class="member-parent">
{% for mentor in get_mentors(course.name) %}
{{ widgets.MemberCard(member=mentor, show_course_count=False) }}
{% endfor %}
</div>
<div class="view-all-mentors">
<span class="card-divider-dark flex-one"></span>
<span class="course-instructor"><span class="all-mentors-text">View all mentors</span> <img class="mentor-icon"
src="/assets/school/icons/down-arrow.svg" /></span>
<span class="card-divider-dark flex-one"></span>
</div>
</div>
{% endif %}
{% endif%}
{% endmacro %}

View File

@@ -11,7 +11,17 @@ def get_context(context):
frappe.local.flags.redirect_location = "/courses"
raise frappe.Redirect
course = frappe.get_doc("LMS Course", course_name)
course = frappe.db.get_value("LMS Course", course_name,
["name", "title", "image", "short_introduction", "description", "is_published", "upcoming",
"disable_self_learning", "video_link"],
as_dict=True)
related_courses = frappe.get_all("Related Courses", {"parent": course.name}, ["course"])
for csr in related_courses:
csr.update(frappe.db.get_value("LMS Course",
csr.course, ["name", "upcoming", "title", "image", "enable_certification"], as_dict=True))
course.related_courses = related_courses
if course is None:
frappe.local.flags.redirect_location = "/courses"
raise frappe.Redirect

View File

@@ -78,7 +78,7 @@
<div class="course-home-headings">
Overview
</div>
<div class="common-card-style overview-card small-title">
<div class="common-card-style overview-card ">
{% if enrollment %}
<div class="overview-item">
<img class="mr-1" src="/assets/school/icons/course.svg" />