feat: redesign lesson page

This commit is contained in:
Jannat Patel
2023-04-25 20:54:57 +05:30
parent 3b5c47222d
commit 4eb5390ad8
14 changed files with 314 additions and 255 deletions

View File

@@ -139,6 +139,7 @@ website_route_rules = [
{"from_route": "/sketches/<sketch>", "to_route": "sketches/sketch"},
{"from_route": "/courses/<course>", "to_route": "courses/course"},
{"from_route": "/courses/<course>/edit", "to_route": "courses/create"},
{"from_route": "/courses/<course>/outline", "to_route": "courses/outline"},
{"from_route": "/courses/<course>/<certificate>", "to_route": "courses/certificate"},
{"from_route": "/courses/<course>/learn", "to_route": "batch/learn"},
{

View File

@@ -502,12 +502,17 @@ def can_create_courses(member=None):
if not member:
member = frappe.session.user
if frappe.session.user == "Guest":
return False
if has_course_instructor_role(member) or has_course_moderator_role(member):
return True
portal_course_creation = frappe.db.get_single_value(
"LMS Settings", "portal_course_creation"
)
return frappe.session.user != "Guest" and (
portal_course_creation == "Anyone" or has_course_instructor_role(member)
)
return portal_course_creation == "Anyone"
def has_course_moderator_role(member=None):
@@ -618,15 +623,17 @@ def get_filtered_membership(course, memberships):
def show_start_learing_cta(course, membership):
return (
not course.disable_self_learning
and not membership
and not course.upcoming
and not check_profile_restriction()
and not is_instructor(course.name)
and course.status == "Approved"
and has_lessons(course)
)
if course.disable_self_learning or course.upcoming:
return False
if is_instructor(course.name):
return False
if course.status != "Approved":
return False
if not has_lessons(course):
return False
if not membership:
return True
def has_lessons(course):

View File

@@ -4,6 +4,7 @@
{% if chapters | length %}
<div class="course-home-outline">
{% if not lesson_page %}
<div class="page-title mb-8" id="outline-heading" data-course="{{ course.name }}">
{{ _("Course Content") }}
</div>
@@ -16,9 +17,10 @@
. {{ get_lessons(course.name, None, False) }} lessons
</span>
</div>
{% endif %}
{% if chapters | length %}
<div class="common-card-style column-card p-4">
<div {% if not lesson_page %} class="common-card-style column-card p-4" {% endif %}>
{% for chapter in chapters %}
{% set lessons = get_lessons(course.name, chapter) %}
@@ -41,7 +43,7 @@
<div class="chapter-content collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.title) }}">
{% if chapter.description %}
<div class="chapter-description ml-2 mb-2">
<div class="chapter-description">
{{ chapter.description }}
</div>
{% endif %}
@@ -67,8 +69,8 @@
<span>{{ lesson.title }}</span>
{% if membership %}
<svg class="icon icon-sm lesson-progress-tick {{ get_progress(course.name, lesson.name) != 'Complete' and 'hide' }}">
<use class="" href="#icon-green-check">
<svg class="icon icon-md lesson-progress-tick ml-auto {{ get_progress(course.name, lesson.name) != 'Complete' and 'hide' }}">
<use class="" href="#icon-success">
</svg>
{% endif %}

View File

@@ -29,6 +29,30 @@
letter-spacing: 0.005em;
}
.sticky {
position: sticky;
top: -1px;
z-index: 1020;
}
.is-pinned {
background: #FFFFFF;
padding: 0.5rem 0;
border-bottom: 1px solid var(--gray-300);
}
.field-parent {
margin-top: 2rem;
}
.frappe-control .ql-editor:not(.read-mode) {
background-color: #FFFFFF;
}
.ql-toolbar.ql-snow, .ql-container.ql-snow {
border: 1px solid var(--gray-300);
}
.rating .icon {
background: var(--gray-200);
border-radius: var(--border-radius-md);
@@ -60,16 +84,20 @@
border: 1px solid var(--gray-300);
border-radius: var(--border-radius-md);
padding: 0.5rem;
width: 75%;
margin: 0.25rem 0 1rem;
width: 100%;
margin-top: 0.25rem;
}
.field-input:focus-visible {
outline: none;
}
.field-group {
margin-bottom: 2rem;
}
.field-description {
font-size: var(--text-sm);
font-size: var(--text-md);
}
.invisible-input {
@@ -480,7 +508,8 @@ input[type=checkbox] {
color: var(--gray-900);
display: flex;
align-items: center;
padding-bottom: 0.5rem;
padding-bottom: 0.25rem;
padding-right: 0.5rem;
font-size: var(--text-lg);
}
@@ -491,6 +520,8 @@ input[type=checkbox] {
.chapter-description {
color: var(--gray-900);
font-size: var(--text-sm);
margin-left: 0.5rem;
margin-bottom: 0.5rem;
}
.course-content-parent .chapter-description {
@@ -663,7 +694,7 @@ input[type=checkbox] {
}
.course-details-outline {
margin-top: 1rem;
margin-top: 2.5rem;
}
.lesson-content {
@@ -672,7 +703,7 @@ input[type=checkbox] {
}
.lesson-content-card {
margin-top: 2rem;
margin-top: 1.5rem;
}
.lesson-content-card .alert-dismissible .close {
@@ -682,7 +713,7 @@ input[type=checkbox] {
.course-content-parent {
display: grid;
grid-gap: 2rem;
grid-template-columns: 2fr minmax(600px, 5fr);
grid-template-columns: 1fr 3fr;
}
@media (max-width: 1024px) {
@@ -704,16 +735,6 @@ input[type=checkbox] {
margin-top: 2rem
}
.lesson-pagination-parent {
margin-top: 1rem;
}
@media (max-width: 768px) {
.lesson-pagination-parent {
margin-left: 0px;
}
}
.lesson-video {
width: 100%;
}
@@ -723,12 +744,6 @@ input[type=checkbox] {
border-radius: var(--border-radius-md);
}
.lesson-title {
display: flex;
align-items: center;
margin-bottom: 1rem;
}
.profile-page {
padding-top: 0;
}
@@ -993,12 +1008,12 @@ pre {
}
.empty-state {
background: var(--gray-200);
border-radius: var(--border-radius-lg);
padding: 4rem;
display: flex;
justify-content: center;
align-items: center;
border: 1px solid var(--gray-300);
border-radius: var(--border-radius-lg);
padding: 4rem;
display: flex;
justify-content: center;
align-items: center;
}
.empty-state-text {
@@ -1568,14 +1583,6 @@ li {
margin-bottom: 1.25rem;
}
.course-card-wide .avatar .standard-image {
border: 1px solid var(--gray-400);
}
.lesson-progress-tick {
margin: 0 0.5rem
}
.no-preview {
color: var(--gray-600);
}

View File

@@ -74,4 +74,7 @@
<circle cx="12" cy="12" r="10"></circle>
<polyline points="12 6 12 12 16 14"></polyline>
</svg>
<svg width="20" height="20" viewBox="0 0 20 20" id="icon-success" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 18.75C14.8325 18.75 18.75 14.8325 18.75 10C18.75 5.16751 14.8325 1.25 10 1.25C5.16751 1.25 1.25 5.16751 1.25 10C1.25 14.8325 5.16751 18.75 10 18.75ZM13.966 7.48104C14.1856 7.21471 14.1477 6.8208 13.8813 6.60122C13.615 6.38164 13.2211 6.41954 13.0015 6.68587L8.68984 11.9155L7.01289 9.74823C6.80165 9.47524 6.40911 9.42517 6.13611 9.6364C5.86311 9.84764 5.81304 10.2402 6.02428 10.5132L8.18004 13.2993C8.29633 13.4495 8.47467 13.5388 8.66468 13.5417C8.85468 13.5447 9.0357 13.461 9.15658 13.3144L13.966 7.48104Z" fill="#171717"/>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -3,11 +3,7 @@
{% block title %}
{% if lesson.title %}
{{ lesson.title }} - {{ course.title }}
{% else %}
{{ _("New Lesson") }}
{% endif %}
{% endblock %}
@@ -21,16 +17,35 @@
{% block page_content %}
<div class="common-page-style lesson-page">
<div class="common-page-style">
<div class="container course-details-page">
{{ BreadCrumb(course, lesson) }}
<div class="course-content-parent">
<div class="course-details-outline">
{{ widgets.CourseOutline(course=course, membership=membership) }}
<div>
<div class="bold-heading mb-4">
{{ course.title }}
</div>
{% if membership %}
<div class="">
<div class="progress-percent m-0">{{ progress }}% {{ _("Completed") }}</div>
<div class="progress" title="{{ progress }}% Completed">
<div class="progress-bar" role="progressbar" aria-valuenow="{{ progress }}"
aria-valuemin="0" aria-valuemax="100" style="width:{{ progress }}%">
</div>
</div>
</div>
{% endif %}
<div class="course-details-outline">
{{ widgets.CourseOutline(course=course, membership=membership, lesson_page=True) }}
</div>
</div>
<div class="lesson-pagination-parent">
{{ BreadCrumb(course, lesson) }}
{{ LessonContent(lesson) }}
{% if not lesson.edit_mode and course.status == "Approved" and not course.upcoming %}
{% if course.status == "Approved" and not course.upcoming %}
{{ Discussions() }}
{% endif %}
</div>
@@ -57,25 +72,24 @@
{% set instructors = get_instructors(course.name) %}
{% set is_instructor = is_instructor(course.name) %}
<div class="common-card-style lesson-content">
<div class="lesson-title">
<div>
<div>
<div class="pull-right">
{% if get_progress(course.name, lesson.name) == 'Complete' %}
<span id="status-indicator" class="indicator-pill green">{{ _("COMPLETED") }}</span>
{% endif %}
<!-- Title -->
<div class="course-home-headings title mb-0 {% if membership %} is-member {% endif %}
<!-- Edit Button -->
{% if (is_instructor or has_course_moderator_role()) %}
<button class="btn btn-secondary btn-sm ml-2 btn-edit"> {{ _("Edit") }} </button>
{% endif %}
</div>
<div class="page-title title {% if membership %} is-member {% endif %}
{% if membership or is_instructor %} eligible-for-submission {% endif %}" id="title"
{% if lesson.edit_mode %} data-placeholder="{{ _('Title') }}" contenteditable="true" {% endif %}
data-index="{{ lesson_index }}" data-course="{{ course.name }}" data-chapter="{{ chapter }}"
{% if lesson.name %} data-lesson="{{ lesson.name }}" {% endif %}
>{% if lesson.title %}{{ lesson.title }}{% endif %}</div>
{% if get_progress(course.name, lesson.name) == 'Complete' %}
<span id="status-indicator" class="indicator-pill green">{{ _("COMPLETED") }}</span>
{% endif %}
<!-- Edit Button -->
{% if (is_instructor or has_course_moderator_role()) and not lesson.edit_mode %}
<button class="btn btn-secondary btn-sm ml-2 btn-edit"> {{ _("Edit") }} </button>
{% endif %}
</div>
<!-- Instructors -->
@@ -107,21 +121,17 @@
</div>
<!-- Lesson Content -->
<div class="markdown-source lesson-content-card {% if lesson.edit_mode %} mb-0 mt-2 {% endif %} ">
<div class="markdown-source lesson-content-card">
{% if show_lesson %}
{% if is_instructor and not lesson.include_in_preview and not lesson.edit_mode %}
{% if is_instructor and not lesson.include_in_preview %}
<div class="medium alert alert-info alert-dismissible mb-4">
{{ _("This lesson is not available for preview. As you are the Instructor of the course only you can see it.") }}
<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
</div>
{% endif %}
{% if lesson.edit_mode %}
{{ EditLesson(lesson) }}
{% else %}
{{ render_html(lesson) }}
{% endif %}
{% else %}
{% set course_link = "<a class='join-batch' data-course=" + course.name | urlencode + " href=''>" + _('here') + "</a>" %}
@@ -133,9 +143,8 @@
{% endif %}
</div>
{% if not lesson.edit_mode %}
{{ pagination(prev_url, next_url) }}
{% endif %}
</div>
{% endmacro %}
@@ -164,56 +173,6 @@
{% endif %}
{% endmacro %}
<!-- Edit Lesson -->
{% macro EditLesson(lesson) %}
<div class="d-flex mt-2 medium">
<div class="flex-grow-1" contenteditable="true" data-placeholder="{{ _('YouTube Video ID') }}"
id="youtube">{% if lesson.youtube %}{{ lesson.youtube }}{% endif %}</div>
<div class="flex-grow-1 ml-2" contenteditable="true" data-placeholder="{{ _('Quiz ID') }}"
id="quiz-id">{% if lesson.quiz_id %}{{ lesson.quiz_id }}{% endif %}</div>
</div>
{% if lesson.body %}
<div class="body-data hide"> {{ lesson.body }} </div>
{% endif %}
<div id="body"></div>
<div class="d-flex medium mx-0 mb-4">
<div class="flex-grow-1" contenteditable="true" data-placeholder="{{ _('Assignment Question') }}"
id="assignment-question">{% if lesson.question %}{{ lesson.question }}{% endif %}</div>
<select class="btn btn-default ml-2" id="file-type" data-type="{{ lesson.file_type }}">
<option selected> {{ _("File Type") }} </option>
<option value="Image"> {{ _("Image") }} </option>
<option value="Document"> {{ _("Document") }} </option>
<option value="PDF"> {{ _("PDF") }} </option>
</select>
</div>
<label class="preview" for="preview">
<input {% if lesson.include_in_preview %} checked {% endif %} type="checkbox" id="preview">
{{ _("Show preview of this lesson to Guest users.") }}
</label>
<div class="mt-4">
<button class="btn btn-primary btn-sm btn-lesson pull-right ml-2"> {{ _("Save") }} </button>
{% if lesson.name %}
<button class="btn btn-secondary btn-sm pull-right btn-back ml-2"> {{ _("Back to Lesson") }} </button>
<a class="btn btn-secondary btn-sm pull-right" href="/quizzes"> {{ _("Create Quiz") }} </a>
{% endif %}
{{ UploadAttachments() }}
</div>
{{ HelpArticle() }}
{% endmacro %}
{% macro UploadAttachments() %}
<div class="attachments-parent">
<div class="attachment-controls">

View File

@@ -27,6 +27,7 @@ def get_context(context):
context.lesson = get_current_lesson_details(lesson_number, context)
instructor = is_instructor(context.course.name)
context.show_lesson = (
context.membership
or (context.lesson and context.lesson.include_in_preview)

View File

@@ -12,11 +12,9 @@
<div class="container">
<div class="course-body-container">
{{ CourseHeaderOverlay(course) }}
{{ CourseSettings(course) }}
{{ Description(course) }}
{{ Save(course) }}
{{ widgets.CourseOutline(course=course, membership=membership, is_user_interested=is_user_interested) }}
{% if not course.edit_mode and course.status == "Approved" and not frappe.utils.cint(course.upcoming) %}
{% if course.status == "Approved" and not frappe.utils.cint(course.upcoming) %}
{% include "lms/templates/reviews.html" %}
{% endif %}
</div>
@@ -69,6 +67,7 @@
{% endif %}
</div>
{% if not course.upcoming %}
<div class="avg-rating-stars">
<div class="rating">
{% for i in [1, 2, 3, 4, 5] %}
@@ -78,10 +77,9 @@
{% endfor %}
</div>
</div>
{% endif %}
<div class="mt-4">
<div class="mt-2">
<div class="bold-heading">{{ _("Instructors") }}:</div>
{% for instructor in get_instructors(course.name) %}
<div class="mt-1">
@@ -149,8 +147,6 @@
</div>
{% endif %}
</div>
</div>
{{ SlotModal(course) }}
@@ -160,54 +156,12 @@
<!-- Description -->
{% macro Description(course) %}
{% if course.edit_mode %}
{% if course.description %}
<div class="description-data hide">{{ course.description }}</div>
{% endif %}
<div id="description"></div>
{% else %}
<div class="course-description-section">
{{ frappe.utils.md_to_html(course.description) }}
</div>
{% endif %}
<div class="course-description-section">
{{ course.description }}
</div>
{% endmacro %}
<!-- Course Settings -->
{% macro CourseSettings(course) %}
{% if course.edit_mode and has_course_moderator_role() %}
<div class="mb-4">
<label for="published" class="mb-0">
<input type="checkbox" id="published" {% if course.published %} checked {% endif %}>
{{ _("Published") }}
</label>
<label for="upcoming" class="mb-0 ml-20">
<input type="checkbox" id="upcoming" {% if course.upcoming %} checked {% endif %}>
{{ _("Upcoming") }}
</label>
</div>
{% endif %}
{% endmacro %}
<!-- Save -->
{% macro Save(course) %}
{% if course.edit_mode %}
<div class="mb-16">
<button class="btn btn-primary btn-sm btn-save-course">
{{ _("Save Course Details") }}
</button>
{% if course.name %}
<a class="btn btn-secondary btn-sm btn-exit-edit ml-2" href="/courses/{{ course.name }}">
{{ _("Back to Course") }}
</a>
{% endif %}
</div>
{% endif %}
{% endmacro %}
<!-- Related Courses Section -->
{% macro RelatedCourses(course) %}
@@ -251,7 +205,6 @@
{% set lesson_index = get_lesson_index(membership.current_lesson) if membership and
membership.current_lesson else "1.1" if first_lesson_exists(course.name) else None %}
<div class="all-cta">
{% if is_instructor(course.name) and not course.published and course.status != "Under Review" %}
<div class="btn btn-primary wide-button" id="submit-for-review" data-course="{{ course.name | urlencode }}">
@@ -310,7 +263,7 @@
<div>
{% if is_instructor(course.name) or has_course_moderator_role() %}
<a class="btn btn-default btn-sm pull-right ml-2" title="Edit Course" href="/courses/{{ course.name }}?edit=1">
<a class="btn btn-default btn-sm pull-right ml-2" title="Edit Course" href="/courses/{{ course.name }}/edit">
<svg class="icon icon-md">
<use href="#icon-edit"></use>
</svg>

View File

@@ -5,10 +5,21 @@
{% block content %}
<main class="common-page-style">
<div class="container">
<div class="page-title"> {{ _("Course Details") }} </div>
<div class="mt-10">
<div>
<header class="sticky">
<div class="container w-75">
<button class="btn btn-primary btn-sm btn-save-course pull-right mt-1">
{{ _("Save") }}
</button>
<div class="page-title"> {{ _("Course Details") }} </div>
</div>
</header>
<div class="container w-75">
<div class="field-parent">
<div class="field-group">
<div>
<div class="field-label">
{{ _("Title") }}
@@ -18,11 +29,11 @@
</div>
</div>
<div class="">
<input type="text" class="field-input" value="{{ course.title }}">
<input id="title" type="text" class="field-input" data-course="{{ course.name }}" {% if course.title %} value="{{ course.title }}" {% endif %}>
</div>
</div>
<div>
<div class="field-group">
<div>
<div class="field-label">
{{ _("Preview Video") }}
@@ -32,11 +43,11 @@
</div>
</div>
<div class="">
<input type="text" class="field-input" value="{{ course.video_link }}">
<input id="video-link" type="text" class="field-input" {% if course.video_link %} value="{{ course.video_link }}" {% endif %}>
</div>
</div>
<div>
<div class="field-group">
<div>
<div class="field-label">
{{ _("Short Introduction") }}
@@ -46,11 +57,11 @@
</div>
</div>
<div class="">
<input type="text" class="field-input" value="{{ course.short_introduction }}">
<input id="intro" type="text" class="field-input" {% if course.short_introduction %} value="{{ course.short_introduction }}" {% endif %}>
</div>
</div>
<div>
<div class="field-group">
<div>
<div class="field-label">
{{ _("Tags") }}
@@ -74,34 +85,7 @@
</div>
</div>
<div>
<div>
<div class="field-label">
{{ _("Course Image") }}
</div>
<div class="field-description">
{{ _("Add an appropriate image") }}
</div>
</div>
<div class="">
<input type="file" class="field-input" id="image">
</div>
<img {% if course.image %} class="image-preview" src="{{ course.image }}" {% endif %}>
</div>
<div>
<div>
<div class="field-label">
{{ _("Course Description") }}
</div>
<div class="field-description">
{{ _("Add a detailed description") }}
</div>
</div>
<textarea id="course-description" class="field-input">{{ course.description }}</textarea>
</div>
<div>
<div class="field-group">
<label for="published" class="mb-0">
<input type="checkbox" id="published" {% if course.published %} checked {% endif %}>
{{ _("Published") }}
@@ -112,20 +96,58 @@
</label>
</div>
<div>
<div class="field-group">
<div>
<div class="field-label">
{{ _("Course Image") }}
</div>
<div class="field-description">
{{ _("Add an appropriate image") }}
</div>
</div>
<div class="">
<button class="btn btn-secondary btn-sm btn-upload mt-2">
{{ _("Upload Image") }}
</button>
</div>
<img {% if course.image %} class="image-preview" src="{{ course.image }}" {% endif %}>
</div>
<div class="field-group">
<div>
<div class="field-label">
{{ _("Course Description") }}
</div>
<div class="field-description">
{{ _("Add a detailed description") }}
</div>
</div>
<div id="description" class=""></div>
{% if course.description %}
<div id="description-data" class="hide">
{{ course.description }}
</div>
{% endif %}
</div>
<div class="field-group">
<div class="field-label">
{{ _("Instructor") }}
</div>
<div>
{{ widgets.Avatar(member=member, avatar_class="avatar-medium") }} {{ member.full_name }}
<div class="mt-2">
{{ widgets.Avatar(member=member, avatar_class="avatar-medium") }}
<span class="ml-2">
{{ member.full_name }}
</span>
</div>
</div>
<button class="btn btn-primary btn-sm btn-save-course">
{{ _("Save") }}
</button>
</div>
</div>
</main>
{% endblock %}
{%- block script %}
{{ super() }}
{{ include_script('controls.bundle.js') }}
{% endblock %}

View File

@@ -1,4 +1,6 @@
frappe.ready(() => {
pin_header();
$(".tags").click((e) => {
e.preventDefault();
$("#tags-input").focus();
@@ -12,17 +14,25 @@ frappe.ready(() => {
$(e.target).parent().parent().remove();
});
$("#image").change((e) => {
$(e.target)
.parent()
.siblings("img")
.addClass("image-preview")
.attr("src", URL.createObjectURL(e.target.files[0]));
});
$(".btn-save-course").click((e) => {
save_course(e);
});
if ($("#description").length) {
make_editor();
}
$("#tags-input").focus((e) => {
$(e.target).keypress((e) => {
if (e.which == 13) {
create_tag(e);
}
});
});
$(".btn-upload").click((e) => {
upload_file(e);
});
});
const create_tag = (e) => {
@@ -50,11 +60,11 @@ const save_course = (e) => {
method: "lms.lms.doctype.lms_course.lms_course.save_course",
args: {
tags: tags.join(", "),
title: $("#title").text(),
short_introduction: $("#intro").text(),
video_link: $("#video-link").text(),
image: $("#image").attr("href"),
description: this.code_field_group.fields_dict["code_md"].value,
title: $("#title").val(),
short_introduction: $("#intro").val(),
video_link: $("#video-link").val(),
image: $(".image-preview").attr("src"),
description: this.description.fields_dict["description"].value,
course: $("#title").data("course")
? $("#title").data("course")
: "",
@@ -67,8 +77,54 @@ const save_course = (e) => {
indicator: "green",
});
setTimeout(() => {
window.location.href = `/courses/${data.message}?edit=1`;
window.location.href = `/courses/${data.message}`;
}, 1000);
},
});
};
const make_editor = () => {
this.description = new frappe.ui.FieldGroup({
fields: [
{
fieldname: "description",
fieldtype: "Text Editor",
default: $("#description-data").html(),
},
],
body: $("#description").get(0),
});
this.description.make();
$("#description .form-section:last").removeClass("empty-section");
$("#description .frappe-control").removeClass("hide-control");
$("#description .form-column").addClass("p-0");
};
const pin_header = () => {
const el = document.querySelector(".sticky");
const observer = new IntersectionObserver(
([e]) =>
e.target.classList.toggle("is-pinned", e.intersectionRatio < 1),
{ threshold: [1] }
);
observer.observe(el);
};
const upload_file = (e) => {
new frappe.ui.FileUploader({
disable_file_browser: true,
folder: "Home/Attachments",
make_attachments_public: true,
restrictions: {
allowed_file_types: ["image/*"],
},
on_success: (file_doc) => {
$(e.target)
.parent()
.siblings("img")
.addClass("image-preview")
.attr("src", file_doc.file_url);
},
});
};

View File

@@ -5,24 +5,26 @@ from frappe import _
def get_context(context):
context.no_cache = 1
try:
course_name = frappe.form_dict["course"]
except KeyError:
redirect_to_courses_list()
if not can_create_courses():
message = "You do not have permission to access this page."
if frappe.session.user == "Guest":
message = "Please login to access this page."
raise frappe.PermissionError(_(message))
if course_name == "new-course":
if not can_create_courses():
message = "You do not have permission to access this page."
if frappe.session.user == "Guest":
message = "Please login to access this page."
raise frappe.PermissionError(_(message))
context.course = frappe._dict()
context.course.edit_mode = True
context.membership = None
else:
set_course_context(context, course_name)
context.member = frappe.db.get_value(
"User", frappe.session.user, ["full_name", "username"], as_dict=True
)

View File

@@ -0,0 +1,37 @@
{% extends "lms/templates/lms_base.html" %}
{% block title %}
{{ _("Outline") }} - {{ course.title }}
{% endblock %}
{% block page_content %}
<main class="common-page-style">
<div class="container">
{{ EmptyState() }}
</div>
</main>
{% endblock %}
{% macro EmptyState() %}
<article class="empty-state">
<div class="text-center">
<div class="bold-heading">
{{ _("You have not added any chapter yet") }}
</div>
<div>
{{ _("Create and manage your chapters from here.") }}
</div>
<div class="mt-4">
<button class="btn btn-default btn-sm">
<svg class="icon icon-xs">
<use class="" href="#icon-add"></use>
</svg>
<span>
{{ _("Add Chapter") }}
</span>
</button>
</div>
</div>
</article>
{% endmacro %}

View File

@@ -0,0 +1,8 @@
import frappe
def get_context(context):
context.no_cache = 1
context.course = frappe.db.get_value(
"LMS Course", frappe.form_dict["course"], ["name", "title"], as_dict=True
)

View File

@@ -25,6 +25,7 @@ def get_common_context(context):
context.lessons = get_lessons(course.name)
membership = get_membership(course.name, frappe.session.user, batch_name)
context.membership = membership
context.progress = frappe.utils.cint(membership.progress) if membership else 0
context.batch = membership.batch if membership and membership.batch else None
context.course.query_parameter = (
"?batch=" + membership.batch if membership and membership.batch else ""