feat: new course ui
This commit is contained in:
@@ -190,7 +190,8 @@ jinja = {
|
||||
"lms.lms.utils.convert_number_to_character",
|
||||
"lms.lms.utils.get_signup_optin_checks",
|
||||
"lms.lms.utils.get_popular_courses",
|
||||
"lms.lms.utils.format_amount"
|
||||
"lms.lms.utils.format_amount",
|
||||
"lms.lms.utils.first_lesson_exists"
|
||||
],
|
||||
"filters": []
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"actions": [],
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
"autoname": "format: JOB-{#####}",
|
||||
"creation": "2022-02-07 12:01:41.074418",
|
||||
@@ -13,7 +14,7 @@
|
||||
"column_break_5",
|
||||
"type",
|
||||
"status",
|
||||
"section_break_6",
|
||||
"section_break_6",``
|
||||
"description",
|
||||
"company_details_section",
|
||||
"company_name",
|
||||
@@ -113,7 +114,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2022-02-24 12:37:45.666484",
|
||||
"modified": "2022-07-28 13:41:29.224332",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Job",
|
||||
"name": "Job Opportunity",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from codecs import ignore_errors
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
import json
|
||||
@@ -203,3 +204,47 @@ def submit_for_review(course):
|
||||
return "No Chp"
|
||||
frappe.db.set_value("LMS Course", course, "status", "Under Review")
|
||||
return "OK"
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_course(tags, title, short_introduction, video_link, image, description, course):
|
||||
if course:
|
||||
doc = frappe.get_doc("LMS Course", course)
|
||||
else:
|
||||
doc = frappe.get_doc({
|
||||
"doctype": "LMS Course"
|
||||
})
|
||||
|
||||
doc.update({
|
||||
"title": title,
|
||||
"short_introduction": short_introduction,
|
||||
"video_link": video_link,
|
||||
"image": image,
|
||||
"description": description,
|
||||
"tags": tags
|
||||
})
|
||||
doc.save(ignore_permissions=True)
|
||||
return doc.name
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def save_chapter(course, chapter, chapter_description, idx):
|
||||
chapter = frappe.get_doc({
|
||||
"doctype": "Course Chapter",
|
||||
"course": course,
|
||||
"title": chapter,
|
||||
"description": chapter_description
|
||||
})
|
||||
chapter.save(ignore_permissions=True)
|
||||
|
||||
chapter_reference = frappe.get_doc({
|
||||
"doctype": "Chapter Reference",
|
||||
"parent": course,
|
||||
"chapter": chapter.name,
|
||||
"parenttype": "LMS Course",
|
||||
"parentfield": "chapters",
|
||||
"idx": idx
|
||||
})
|
||||
chapter_reference.save(ignore_permissions=True)
|
||||
|
||||
return chapter.name
|
||||
|
||||
@@ -53,6 +53,8 @@ def get_membership(course, member, batch=None):
|
||||
def get_chapters(course):
|
||||
"""Returns all chapters of this course.
|
||||
"""
|
||||
if not course:
|
||||
return []
|
||||
chapters = frappe.get_all("Chapter Reference", {"parent": course},
|
||||
["idx", "chapter"], order_by="idx")
|
||||
for chapter in chapters:
|
||||
@@ -373,3 +375,15 @@ def format_amount(amount, currency):
|
||||
return amount
|
||||
precision = 0 if amount % 1000 == 0 else 1
|
||||
return _("{0}k").format(fmt_money(amount_reduced, precision, currency))
|
||||
|
||||
|
||||
def first_lesson_exists(course):
|
||||
first_chapter = frappe.db.get_value("Chapter Reference", {"parent": course, "idx": 1}, "name")
|
||||
if not first_chapter:
|
||||
return False
|
||||
|
||||
first_lesson = frappe.db.get_value("Lesson Reference", {"parent": first_chapter, "idx": 1}, "name")
|
||||
if not first_lesson:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@@ -1,109 +1,98 @@
|
||||
{% if get_chapters(course.name) | length %}
|
||||
<div class="course-home-outline">
|
||||
<div class="course-home-headings">
|
||||
{{ _("Course Content") }}
|
||||
</div>
|
||||
{% for chapter in get_chapters(course.name) %}
|
||||
<div class="">
|
||||
<div class="chapter-title" data-target="#{{ get_slugified_chapter_title(chapter.title) }}"
|
||||
data-toggle="collapse" aria-expanded="false">
|
||||
<img class="chapter-icon" src="/assets/lms/icons/chevron-right.svg">
|
||||
<div>{{ chapter.title }}</div>
|
||||
<div class="course-home-headings">
|
||||
{{ _("Course Content") }}
|
||||
</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 }}
|
||||
{% for chapter in get_chapters(course.name) %}
|
||||
<div class="">
|
||||
<div class="chapter-title" data-target="#{{ get_slugified_chapter_title(chapter.title) }}"
|
||||
data-toggle="collapse" aria-expanded="false">
|
||||
{% if not course.edit_mode %}
|
||||
<img class="chapter-icon" src="/assets/lms/icons/chevron-right.svg">
|
||||
{% endif %}
|
||||
<div class="w-100 chapter-title-main" {% if course.edit_mode %} contenteditable="true" {% endif %} >{{ chapter.title }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% set is_instructor = is_instructor(course.name) %}
|
||||
<div class="lessons">
|
||||
<div class="chapter-content collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.title) }}">
|
||||
|
||||
{% for lesson in get_lessons(course.name, chapter) %}
|
||||
{% set active = membership.current_lesson == lesson.name %}
|
||||
<div class="lesson-info {% if active %} 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 }}">
|
||||
<svg class="icon icon-sm mr-2">
|
||||
<use class="" href="#{{ lesson.icon }}">
|
||||
</svg>
|
||||
<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>
|
||||
{% 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="{{ get_lesson_url(course.name, lesson.number) }}{{course.query_parameter}}"
|
||||
data-course="{{ course.name }}">
|
||||
|
||||
<svg class="icon icon-sm mr-2">
|
||||
<use class="" href="#icon-lock">
|
||||
</svg>
|
||||
<div>{{ lesson.title }}</div>
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
<div class="no-preview" title="This lesson is not available for preview" data-course="{{ course.name }}">
|
||||
<div class="lesson-links">
|
||||
<svg class="icon icon-sm mr-2">
|
||||
<use class="" href="#icon-lock-gray">
|
||||
</svg>
|
||||
<div>{{ lesson.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if chapter.description or course.edit_mode %}
|
||||
<div {% if course.edit_mode %} contenteditable="true" {% endif %} class="chapter-description
|
||||
{% if not course.edit_mode %} mx-8 mb-2 {% endif %} "
|
||||
data-placeholder="{{ _('Short Description') }}">{{ chapter.description }}</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if course.edit_mode %}
|
||||
<button class="btn btn-sm btn-secondary d-block btn-save-chapter mt-2 mb-8"> {{ _('Save') }} </button>
|
||||
{% endif %}
|
||||
|
||||
{% set is_instructor = is_instructor(course.name) %}
|
||||
<div class="lessons">
|
||||
|
||||
{% for lesson in get_lessons(course.name, chapter) %}
|
||||
{% set active = membership.current_lesson == lesson.name %}
|
||||
<div class="lesson-info {% if active and not course.edit_mode %} 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 }}">
|
||||
<svg class="icon icon-sm mr-2">
|
||||
<use class="" href="#{{ lesson.icon }}">
|
||||
</svg>
|
||||
<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>
|
||||
{% 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="{{ get_lesson_url(course.name, lesson.number) }}{{course.query_parameter}}"
|
||||
data-course="{{ course.name }}">
|
||||
|
||||
<svg class="icon icon-sm mr-2">
|
||||
<use class="" href="#icon-lock">
|
||||
</svg>
|
||||
<div>{{ lesson.title }}</div>
|
||||
</a>
|
||||
|
||||
{% else %}
|
||||
<div class="no-preview" title="This lesson is not available for preview" data-course="{{ course.name }}">
|
||||
<div class="lesson-links">
|
||||
<svg class="icon icon-sm mr-2">
|
||||
<use class="" href="#icon-lock-gray">
|
||||
</svg>
|
||||
<div>{{ lesson.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
<div>
|
||||
<button class="btn btn-md btn-secondary btn-chapter" data-index=" {{ chapters | length + 1 }} "> {{ _("Add Chapter") }} </button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- No Preview Modal -->
|
||||
<div class="modal fade no-preview-modal" id="no-preview-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="font-weight-bold">{{ _("Not available for preview") }}</div>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{% if is_user_interested %}
|
||||
<div class=""> {{ _("You have opted to be notified for this course. You will receive an email when the course becomes available.") }} </div>
|
||||
{% else %}
|
||||
<div class=""> {{ _("This lesson is not available for preview. Please join the course to access it.") }} </div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not is_user_interested %}
|
||||
<div class="modal-footer">
|
||||
{% if course.upcoming %}
|
||||
<div class="button is-primary notify-me" data-course="{{course.name | urlencode}}">
|
||||
{{ _("Notify me when available") }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="button is-primary join-batch" data-course="{{ course.name | urlencode}}">
|
||||
{{ _("Start Learning") }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ widgets.NoPreviewModal(course=course) }}
|
||||
|
||||
{% elif course.edit_mode and course.name %}
|
||||
<div class="course-home-outline">
|
||||
<div class="course-home-headings">
|
||||
{{ _("Course Content") }}
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-md btn-secondary btn-chapter" data-index="1"> {{ _("Add Chapter") }} </button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
32
lms/lms/widgets/NoPreviewModal.html
Normal file
32
lms/lms/widgets/NoPreviewModal.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<div class="modal fade no-preview-modal" id="no-preview-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="font-weight-bold">{{ _("Not available for preview") }}</div>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{% if is_user_interested %}
|
||||
<div class=""> {{ _("You have opted to be notified for this course. You will receive an email when the course becomes available.") }} </div>
|
||||
{% else %}
|
||||
<div class=""> {{ _("This lesson is not available for preview. Please join the course to access it.") }} </div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if not is_user_interested %}
|
||||
<div class="modal-footer">
|
||||
{% if course.upcoming %}
|
||||
<div class="button is-primary notify-me" data-course="{{course.name | urlencode}}">
|
||||
{{ _("Notify me when available") }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="button is-primary join-batch" data-course="{{ course.name | urlencode}}">
|
||||
{{ _("Start Learning") }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -376,16 +376,17 @@ input[type=checkbox] {
|
||||
}
|
||||
|
||||
.chapter-title {
|
||||
cursor: pointer;
|
||||
border-radius: var(--border-radius-lg);
|
||||
padding: 0.5rem 0;
|
||||
color: var(--gray-900);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border-radius: var(--border-radius-lg);
|
||||
padding: 0.5rem 0;
|
||||
color: var(--gray-900);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chapter-description {
|
||||
margin: 0 2rem 0.5rem;
|
||||
color: var(--gray-900);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.course-content-parent .chapter-description {
|
||||
@@ -1500,3 +1501,30 @@ li {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
[contenteditable] {
|
||||
border: 1px solid var(--gray-400);
|
||||
padding: 0.5rem;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
[contenteditable] {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[contenteditable]:empty:before{
|
||||
content: attr(data-placeholder);
|
||||
color: var(--gray-600);
|
||||
}
|
||||
|
||||
.course-image-attachment {
|
||||
margin-top: 1rem;
|
||||
border: 1px solid var(--gray-400);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 0.25rem 0.5rem;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.btn-delete-tag {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
frappe.ready(() => {
|
||||
|
||||
setup_vue_and_file_size();
|
||||
|
||||
hide_wrapped_mentor_cards();
|
||||
|
||||
$("#cancel-request").click((e) => {
|
||||
@@ -50,116 +52,165 @@ frappe.ready(() => {
|
||||
select_slot(e);
|
||||
});
|
||||
|
||||
$(".btn-attach").click((e) => {
|
||||
show_upload_modal(e);
|
||||
});
|
||||
|
||||
$(".btn-clear").click((e) => {
|
||||
clear_image(e);
|
||||
});
|
||||
|
||||
$(".btn-tag").click((e) => {
|
||||
add_tag(e);
|
||||
});
|
||||
|
||||
$(".btn-save-course").click((e) => {
|
||||
save_course(e);
|
||||
});
|
||||
|
||||
$(".btn-delete-tag").click((e) => {
|
||||
remove_tag(e);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var hide_wrapped_mentor_cards = () => {
|
||||
var offset_top_prev;
|
||||
|
||||
$(".member-parent .member-card").each(function () {
|
||||
var offset_top = $(this).offset().top;
|
||||
if (offset_top > offset_top_prev) {
|
||||
$(this).addClass('wrapped').slideUp("fast");
|
||||
const setup_vue_and_file_size = () => {
|
||||
frappe.require("/assets/frappe/node_modules/vue/dist/vue.js", () => {
|
||||
Vue.prototype.__ = window.__;
|
||||
Vue.prototype.frappe = window.frappe;
|
||||
});
|
||||
|
||||
frappe.provide("frappe.form.formatters");
|
||||
frappe.form.formatters.FileSize = file_size;
|
||||
};
|
||||
|
||||
|
||||
const file_size = (value) => {
|
||||
if(value > 1048576) {
|
||||
value = flt(flt(value) / 1048576, 1) + "M";
|
||||
} else if (value > 1024) {
|
||||
value = flt(flt(value) / 1024, 1) + "K";
|
||||
}
|
||||
if (!offset_top_prev) {
|
||||
offset_top_prev = offset_top;
|
||||
return value;
|
||||
};
|
||||
|
||||
|
||||
const hide_wrapped_mentor_cards = () => {
|
||||
let offset_top_prev;
|
||||
|
||||
$(".member-parent .member-card").each(function () {
|
||||
var offset_top = $(this).offset().top;
|
||||
if (offset_top > offset_top_prev) {
|
||||
$(this).addClass('wrapped').slideUp("fast");
|
||||
}
|
||||
if (!offset_top_prev) {
|
||||
offset_top_prev = offset_top;
|
||||
}
|
||||
});
|
||||
|
||||
if ($(".wrapped").length < 1) {
|
||||
$(".view-all-mentors").hide();
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
if ($(".wrapped").length < 1) {
|
||||
$(".view-all-mentors").hide();
|
||||
}
|
||||
}
|
||||
const cancel_mentor_request = (e) => {
|
||||
e.preventDefault();
|
||||
frappe.call({
|
||||
"method": "lms.lms.doctype.lms_mentor_request.lms_mentor_request.cancel_request",
|
||||
"args": {
|
||||
"course": decodeURIComponent($(e.currentTarget).attr("data-course"))
|
||||
},
|
||||
"callback": (data) => {
|
||||
if (data.message == "OK") {
|
||||
$("#mentor-request").removeClass("hide");
|
||||
$("#already-applied").addClass("hide")
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var cancel_mentor_request = (e) => {
|
||||
e.preventDefault()
|
||||
frappe.call({
|
||||
"method": "lms.lms.doctype.lms_mentor_request.lms_mentor_request.cancel_request",
|
||||
"args": {
|
||||
"course": decodeURIComponent($(e.currentTarget).attr("data-course"))
|
||||
},
|
||||
"callback": (data) => {
|
||||
if (data.message == "OK") {
|
||||
$("#mentor-request").removeClass("hide");
|
||||
$("#already-applied").addClass("hide")
|
||||
}
|
||||
|
||||
const view_all_mentors = (e) => {
|
||||
$(".wrapped").each((i, element) => {
|
||||
$(element).slideToggle("slow");
|
||||
})
|
||||
var text_element = $(".view-all-mentors .course-instructor .all-mentors-text");
|
||||
var text = text_element.text() == "View all mentors" ? "View less" : "View all mentors";
|
||||
text_element.text(text);
|
||||
|
||||
if ($(".mentor-icon").css("transform") == "none") {
|
||||
$(".mentor-icon").css("transform", "rotate(180deg)");
|
||||
} else {
|
||||
$(".mentor-icon").css("transform", "");
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
var view_all_mentors = (e) => {
|
||||
$(".wrapped").each((i, element) => {
|
||||
$(element).slideToggle("slow");
|
||||
})
|
||||
var text_element = $(".view-all-mentors .course-instructor .all-mentors-text");
|
||||
var text = text_element.text() == "View all mentors" ? "View less" : "View all mentors";
|
||||
text_element.text(text);
|
||||
|
||||
if ($(".mentor-icon").css("transform") == "none") {
|
||||
$(".mentor-icon").css("transform", "rotate(180deg)");
|
||||
} else {
|
||||
$(".mentor-icon").css("transform", "");
|
||||
}
|
||||
}
|
||||
const show_review_dialog = (e) => {
|
||||
e.preventDefault();
|
||||
$("#review-modal").modal("show");
|
||||
};
|
||||
|
||||
var show_review_dialog = (e) => {
|
||||
e.preventDefault();
|
||||
$("#review-modal").modal("show");
|
||||
}
|
||||
|
||||
var highlight_rating = (e) => {
|
||||
var rating = $(e.currentTarget).attr("data-rating");
|
||||
$(".icon-rating").removeClass("star-click");
|
||||
$(".icon-rating").each((i, elem) => {
|
||||
if (i <= rating-1) {
|
||||
$(elem).addClass("star-click");
|
||||
}
|
||||
})
|
||||
}
|
||||
const highlight_rating = (e) => {
|
||||
var rating = $(e.currentTarget).attr("data-rating");
|
||||
$(".icon-rating").removeClass("star-click");
|
||||
$(".icon-rating").each((i, elem) => {
|
||||
if (i <= rating-1) {
|
||||
$(elem).addClass("star-click");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var submit_review = (e) => {
|
||||
e.preventDefault();
|
||||
var rating = $(".rating-field").children(".star-click").length;
|
||||
var review = $(".review-field").val();
|
||||
if (!rating) {
|
||||
$(".error-field").text("Please provide a rating.");
|
||||
return;
|
||||
}
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_course_review.lms_course_review.submit_review",
|
||||
args: {
|
||||
"rating": rating,
|
||||
"review": review,
|
||||
"course": decodeURIComponent($(e.currentTarget).attr("data-course"))
|
||||
},
|
||||
callback: (data) => {
|
||||
if (data.message == "OK") {
|
||||
$(".review-modal").modal("hide");
|
||||
window.location.reload();
|
||||
}
|
||||
e.preventDefault();
|
||||
var rating = $(".rating-field").children(".star-click").length;
|
||||
var review = $(".review-field").val();
|
||||
if (!rating) {
|
||||
$(".error-field").text("Please provide a rating.");
|
||||
return;
|
||||
}
|
||||
})
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_course_review.lms_course_review.submit_review",
|
||||
args: {
|
||||
"rating": rating,
|
||||
"review": review,
|
||||
"course": decodeURIComponent($(e.currentTarget).attr("data-course"))
|
||||
},
|
||||
callback: (data) => {
|
||||
if (data.message == "OK") {
|
||||
$(".review-modal").modal("hide");
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const create_certificate = (e) => {
|
||||
e.preventDefault();
|
||||
course = $(e.currentTarget).attr("data-course");
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate",
|
||||
args: {
|
||||
"course": course
|
||||
},
|
||||
callback: (data) => {
|
||||
window.location.href = `/courses/${course}/${data.message.name}`;
|
||||
}
|
||||
})
|
||||
e.preventDefault();
|
||||
course = $(e.currentTarget).attr("data-course");
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate",
|
||||
args: {
|
||||
"course": course
|
||||
},
|
||||
callback: (data) => {
|
||||
window.location.href = `/courses/${course}/${data.message.name}`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const element_not_in_viewport = (el) => {
|
||||
const rect = el.getBoundingClientRect();
|
||||
return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
|
||||
const rect = el.getBoundingClientRect();
|
||||
return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
|
||||
};
|
||||
|
||||
|
||||
const submit_for_review = (e) => {
|
||||
let course = $(e.currentTarget).data("course");
|
||||
frappe.call({
|
||||
@@ -184,12 +235,12 @@ const submit_for_review = (e) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const apply_cetificate = (e) => {
|
||||
$("#slot-modal").modal("show");
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
const submit_slot = (e) => {
|
||||
e.preventDefault();
|
||||
const slot = window.selected_slot;
|
||||
@@ -215,6 +266,7 @@ const submit_slot = (e) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const display_slots = (e) => {
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
|
||||
@@ -249,18 +301,73 @@ const display_slots = (e) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const select_slot = (e) => {
|
||||
$(".slot").removeClass("btn-outline-primary");
|
||||
$(e.currentTarget).addClass("btn-outline-primary");
|
||||
window.selected_slot = $(e.currentTarget);
|
||||
};
|
||||
|
||||
|
||||
const format_time = (time) => {
|
||||
let date = moment(new Date()).format("ddd MMM DD YYYY");
|
||||
return moment(`${date} ${time}`).format("HH:mm a");
|
||||
};
|
||||
|
||||
|
||||
const close_slot_modal = (e) => {
|
||||
$("#slot-date").val("");
|
||||
$(".slot-label").addClass("hide");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const show_upload_modal = () => {
|
||||
new frappe.ui.FileUploader({
|
||||
folder: "Home/Attachments",
|
||||
restrictions: {
|
||||
allowed_file_types: ['image/*']
|
||||
},
|
||||
on_success: (file_doc) => {
|
||||
$(".course-image-attachment").removeClass("hide");
|
||||
$(".course-image-attachment a").attr("href", file_doc.file_url).text(file_doc.file_url);
|
||||
$(".btn-attach").addClass("hide");
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const clear_image = () => {
|
||||
$(".course-image-attachment").addClass("hide");
|
||||
$(".course-image-attachment a").removeAttr("href");
|
||||
$(".btn-attach").removeClass("hide");
|
||||
};
|
||||
|
||||
|
||||
const add_tag = (e) => {
|
||||
$(`<div class="course-card-pills" contenteditable="true"
|
||||
data-placeholder="${__('Tags')}"></div>`).insertBefore(`.btn-tag`);
|
||||
};
|
||||
|
||||
|
||||
const save_course = (e) => {
|
||||
let course = $("#title").data("course");
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_course.lms_course.save_course",
|
||||
args: {
|
||||
"tags": $('.course-card-pills').map((i, el) => $(el).text().trim()).get().join(", "),
|
||||
"title": $("#title").text(),
|
||||
"short_introduction": $("#intro").text(),
|
||||
"video_link": $("#video-link").text(),
|
||||
"image": $("#image").attr("href"),
|
||||
"description": $("#description").text(),
|
||||
"course": course ? course : ""
|
||||
},
|
||||
callback: (data) => {
|
||||
window.location.href = `/courses/${data.message}?edit=1`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const remove_tag = (e) => {
|
||||
$(e.currentTarget).closest(".course-card-pills").remove();
|
||||
};
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
import frappe
|
||||
from lms.lms.doctype.lms_settings.lms_settings import check_profile_restriction
|
||||
from lms.lms.utils import get_membership, is_instructor, is_certified, get_evaluation_details
|
||||
from frappe.utils import add_months, getdate
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
|
||||
try:
|
||||
print(frappe.form_dict)
|
||||
course_name = frappe.form_dict["course"]
|
||||
except KeyError:
|
||||
frappe.local.flags.redirect_location = "/courses"
|
||||
raise frappe.Redirect
|
||||
|
||||
if course_name == "new-course":
|
||||
context.course = frappe._dict()
|
||||
context.course.edit_mode = True
|
||||
context.membership = None
|
||||
else:
|
||||
set_course_context(context, course_name)
|
||||
|
||||
def set_course_context(context, course_name):
|
||||
course = frappe.db.get_value("LMS Course", course_name,
|
||||
["name", "title", "image", "short_introduction", "description", "published", "upcoming", "disable_self_learning",
|
||||
"status", "video_link", "enable_certification", "grant_certificate_after", "paid_certificate",
|
||||
@@ -43,6 +51,9 @@ def get_context(context):
|
||||
if context.course.upcoming:
|
||||
context.is_user_interested = get_user_interest(context.course.name)
|
||||
|
||||
if frappe.form_dict.get("edit"):
|
||||
context.course.edit_mode = True
|
||||
|
||||
context.metatags = {
|
||||
"title": course.title,
|
||||
"image": course.image,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<div class="common-page-style dashboard">
|
||||
<div class="container">
|
||||
{% if portal_course_creation %}
|
||||
<a class="button is-default button-links pull-right hide" id="create-course-link" href="/course">
|
||||
<a class="button is-default button-links pull-right hide" id="create-course-link" href="/courses/new-course">
|
||||
<svg class="icon icon-sm mr-1"><use href="#icon-add"></use></svg>
|
||||
{{ _("New Course")}}
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user