feat: new course ui
This commit is contained in:
@@ -190,7 +190,8 @@ jinja = {
|
|||||||
"lms.lms.utils.convert_number_to_character",
|
"lms.lms.utils.convert_number_to_character",
|
||||||
"lms.lms.utils.get_signup_optin_checks",
|
"lms.lms.utils.get_signup_optin_checks",
|
||||||
"lms.lms.utils.get_popular_courses",
|
"lms.lms.utils.get_popular_courses",
|
||||||
"lms.lms.utils.format_amount"
|
"lms.lms.utils.format_amount",
|
||||||
|
"lms.lms.utils.first_lesson_exists"
|
||||||
],
|
],
|
||||||
"filters": []
|
"filters": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"actions": [],
|
"actions": [],
|
||||||
|
"allow_import": 1,
|
||||||
"allow_rename": 1,
|
"allow_rename": 1,
|
||||||
"autoname": "format: JOB-{#####}",
|
"autoname": "format: JOB-{#####}",
|
||||||
"creation": "2022-02-07 12:01:41.074418",
|
"creation": "2022-02-07 12:01:41.074418",
|
||||||
@@ -13,7 +14,7 @@
|
|||||||
"column_break_5",
|
"column_break_5",
|
||||||
"type",
|
"type",
|
||||||
"status",
|
"status",
|
||||||
"section_break_6",
|
"section_break_6",``
|
||||||
"description",
|
"description",
|
||||||
"company_details_section",
|
"company_details_section",
|
||||||
"company_name",
|
"company_name",
|
||||||
@@ -113,7 +114,7 @@
|
|||||||
],
|
],
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2022-02-24 12:37:45.666484",
|
"modified": "2022-07-28 13:41:29.224332",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Job",
|
"module": "Job",
|
||||||
"name": "Job Opportunity",
|
"name": "Job Opportunity",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from codecs import ignore_errors
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
import json
|
import json
|
||||||
@@ -203,3 +204,47 @@ def submit_for_review(course):
|
|||||||
return "No Chp"
|
return "No Chp"
|
||||||
frappe.db.set_value("LMS Course", course, "status", "Under Review")
|
frappe.db.set_value("LMS Course", course, "status", "Under Review")
|
||||||
return "OK"
|
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):
|
def get_chapters(course):
|
||||||
"""Returns all chapters of this course.
|
"""Returns all chapters of this course.
|
||||||
"""
|
"""
|
||||||
|
if not course:
|
||||||
|
return []
|
||||||
chapters = frappe.get_all("Chapter Reference", {"parent": course},
|
chapters = frappe.get_all("Chapter Reference", {"parent": course},
|
||||||
["idx", "chapter"], order_by="idx")
|
["idx", "chapter"], order_by="idx")
|
||||||
for chapter in chapters:
|
for chapter in chapters:
|
||||||
@@ -373,3 +375,15 @@ def format_amount(amount, currency):
|
|||||||
return amount
|
return amount
|
||||||
precision = 0 if amount % 1000 == 0 else 1
|
precision = 0 if amount % 1000 == 0 else 1
|
||||||
return _("{0}k").format(fmt_money(amount_reduced, precision, currency))
|
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 %}
|
{% if get_chapters(course.name) | length %}
|
||||||
<div class="course-home-outline">
|
<div class="course-home-outline">
|
||||||
<div class="course-home-headings">
|
<div class="course-home-headings">
|
||||||
{{ _("Course Content") }}
|
{{ _("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>
|
</div>
|
||||||
|
{% for chapter in get_chapters(course.name) %}
|
||||||
<div class="chapter-content collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.title) }}">
|
<div class="">
|
||||||
|
<div class="chapter-title" data-target="#{{ get_slugified_chapter_title(chapter.title) }}"
|
||||||
{% if chapter.description %}
|
data-toggle="collapse" aria-expanded="false">
|
||||||
<div class="chapter-description muted-text">
|
{% if not course.edit_mode %}
|
||||||
{{ chapter.description }}
|
<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>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% set is_instructor = is_instructor(course.name) %}
|
<div class="chapter-content collapse navbar-collapse" id="{{ get_slugified_chapter_title(chapter.title) }}">
|
||||||
<div class="lessons">
|
|
||||||
|
|
||||||
{% for lesson in get_lessons(course.name, chapter) %}
|
{% if chapter.description or course.edit_mode %}
|
||||||
{% set active = membership.current_lesson == lesson.name %}
|
<div {% if course.edit_mode %} contenteditable="true" {% endif %} class="chapter-description
|
||||||
<div class="lesson-info {% if active %} active-lesson {% endif %}">
|
{% if not course.edit_mode %} mx-8 mb-2 {% endif %} "
|
||||||
|
data-placeholder="{{ _('Short Description') }}">{{ chapter.description }}</div>
|
||||||
{% 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 %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
{% if course.edit_mode %}
|
||||||
{% endfor %}
|
<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>
|
</div>
|
||||||
</div>
|
{% endfor %}
|
||||||
{% endfor %}
|
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-md btn-secondary btn-chapter" data-index=" {{ chapters | length + 1 }} "> {{ _("Add Chapter") }} </button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- No Preview Modal -->
|
<!-- No Preview Modal -->
|
||||||
<div class="modal fade no-preview-modal" id="no-preview-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
{{ widgets.NoPreviewModal(course=course) }}
|
||||||
aria-hidden="true">
|
|
||||||
<div class="modal-dialog" role="document">
|
{% elif course.edit_mode and course.name %}
|
||||||
<div class="modal-content">
|
<div class="course-home-outline">
|
||||||
<div class="modal-header">
|
<div class="course-home-headings">
|
||||||
<div class="font-weight-bold">{{ _("Not available for preview") }}</div>
|
{{ _("Course Content") }}
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
</div>
|
||||||
<span aria-hidden="true">×</span>
|
<div>
|
||||||
</button>
|
<button class="btn btn-md btn-secondary btn-chapter" data-index="1"> {{ _("Add Chapter") }} </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>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% 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 {
|
.chapter-title {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: var(--border-radius-lg);
|
border-radius: var(--border-radius-lg);
|
||||||
padding: 0.5rem 0;
|
padding: 0.5rem 0;
|
||||||
color: var(--gray-900);
|
color: var(--gray-900);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chapter-description {
|
.chapter-description {
|
||||||
margin: 0 2rem 0.5rem;
|
color: var(--gray-900);
|
||||||
|
font-size: var(--text-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-content-parent .chapter-description {
|
.course-content-parent .chapter-description {
|
||||||
@@ -1500,3 +1501,30 @@ li {
|
|||||||
margin-top: 1rem;
|
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(() => {
|
frappe.ready(() => {
|
||||||
|
|
||||||
|
setup_vue_and_file_size();
|
||||||
|
|
||||||
hide_wrapped_mentor_cards();
|
hide_wrapped_mentor_cards();
|
||||||
|
|
||||||
$("#cancel-request").click((e) => {
|
$("#cancel-request").click((e) => {
|
||||||
@@ -50,116 +52,165 @@ frappe.ready(() => {
|
|||||||
select_slot(e);
|
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 () {
|
const setup_vue_and_file_size = () => {
|
||||||
var offset_top = $(this).offset().top;
|
frappe.require("/assets/frappe/node_modules/vue/dist/vue.js", () => {
|
||||||
if (offset_top > offset_top_prev) {
|
Vue.prototype.__ = window.__;
|
||||||
$(this).addClass('wrapped').slideUp("fast");
|
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) {
|
return value;
|
||||||
offset_top_prev = offset_top;
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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) {
|
const cancel_mentor_request = (e) => {
|
||||||
$(".view-all-mentors").hide();
|
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()
|
const view_all_mentors = (e) => {
|
||||||
frappe.call({
|
$(".wrapped").each((i, element) => {
|
||||||
"method": "lms.lms.doctype.lms_mentor_request.lms_mentor_request.cancel_request",
|
$(element).slideToggle("slow");
|
||||||
"args": {
|
})
|
||||||
"course": decodeURIComponent($(e.currentTarget).attr("data-course"))
|
var text_element = $(".view-all-mentors .course-instructor .all-mentors-text");
|
||||||
},
|
var text = text_element.text() == "View all mentors" ? "View less" : "View all mentors";
|
||||||
"callback": (data) => {
|
text_element.text(text);
|
||||||
if (data.message == "OK") {
|
|
||||||
$("#mentor-request").removeClass("hide");
|
if ($(".mentor-icon").css("transform") == "none") {
|
||||||
$("#already-applied").addClass("hide")
|
$(".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") {
|
const show_review_dialog = (e) => {
|
||||||
$(".mentor-icon").css("transform", "rotate(180deg)");
|
e.preventDefault();
|
||||||
} else {
|
$("#review-modal").modal("show");
|
||||||
$(".mentor-icon").css("transform", "");
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var show_review_dialog = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
$("#review-modal").modal("show");
|
|
||||||
}
|
|
||||||
|
|
||||||
var highlight_rating = (e) => {
|
const highlight_rating = (e) => {
|
||||||
var rating = $(e.currentTarget).attr("data-rating");
|
var rating = $(e.currentTarget).attr("data-rating");
|
||||||
$(".icon-rating").removeClass("star-click");
|
$(".icon-rating").removeClass("star-click");
|
||||||
$(".icon-rating").each((i, elem) => {
|
$(".icon-rating").each((i, elem) => {
|
||||||
if (i <= rating-1) {
|
if (i <= rating-1) {
|
||||||
$(elem).addClass("star-click");
|
$(elem).addClass("star-click");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
var submit_review = (e) => {
|
var submit_review = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var rating = $(".rating-field").children(".star-click").length;
|
var rating = $(".rating-field").children(".star-click").length;
|
||||||
var review = $(".review-field").val();
|
var review = $(".review-field").val();
|
||||||
if (!rating) {
|
if (!rating) {
|
||||||
$(".error-field").text("Please provide a rating.");
|
$(".error-field").text("Please provide a rating.");
|
||||||
return;
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
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) => {
|
const create_certificate = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
course = $(e.currentTarget).attr("data-course");
|
course = $(e.currentTarget).attr("data-course");
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate",
|
method: "lms.lms.doctype.lms_certificate.lms_certificate.create_certificate",
|
||||||
args: {
|
args: {
|
||||||
"course": course
|
"course": course
|
||||||
},
|
},
|
||||||
callback: (data) => {
|
callback: (data) => {
|
||||||
window.location.href = `/courses/${course}/${data.message.name}`;
|
window.location.href = `/courses/${course}/${data.message.name}`;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const element_not_in_viewport = (el) => {
|
const element_not_in_viewport = (el) => {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
|
return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const submit_for_review = (e) => {
|
const submit_for_review = (e) => {
|
||||||
let course = $(e.currentTarget).data("course");
|
let course = $(e.currentTarget).data("course");
|
||||||
frappe.call({
|
frappe.call({
|
||||||
@@ -184,12 +235,12 @@ const submit_for_review = (e) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const apply_cetificate = (e) => {
|
const apply_cetificate = (e) => {
|
||||||
$("#slot-modal").modal("show");
|
$("#slot-modal").modal("show");
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const submit_slot = (e) => {
|
const submit_slot = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const slot = window.selected_slot;
|
const slot = window.selected_slot;
|
||||||
@@ -215,6 +266,7 @@ const submit_slot = (e) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const display_slots = (e) => {
|
const display_slots = (e) => {
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
|
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
|
||||||
@@ -249,18 +301,73 @@ const display_slots = (e) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const select_slot = (e) => {
|
const select_slot = (e) => {
|
||||||
$(".slot").removeClass("btn-outline-primary");
|
$(".slot").removeClass("btn-outline-primary");
|
||||||
$(e.currentTarget).addClass("btn-outline-primary");
|
$(e.currentTarget).addClass("btn-outline-primary");
|
||||||
window.selected_slot = $(e.currentTarget);
|
window.selected_slot = $(e.currentTarget);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const format_time = (time) => {
|
const format_time = (time) => {
|
||||||
let date = moment(new Date()).format("ddd MMM DD YYYY");
|
let date = moment(new Date()).format("ddd MMM DD YYYY");
|
||||||
return moment(`${date} ${time}`).format("HH:mm a");
|
return moment(`${date} ${time}`).format("HH:mm a");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const close_slot_modal = (e) => {
|
const close_slot_modal = (e) => {
|
||||||
$("#slot-date").val("");
|
$("#slot-date").val("");
|
||||||
$(".slot-label").addClass("hide");
|
$(".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
|
import frappe
|
||||||
from lms.lms.doctype.lms_settings.lms_settings import check_profile_restriction
|
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 lms.lms.utils import get_membership, is_instructor, is_certified, get_evaluation_details
|
||||||
from frappe.utils import add_months, getdate
|
|
||||||
|
|
||||||
def get_context(context):
|
def get_context(context):
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
print(frappe.form_dict)
|
||||||
course_name = frappe.form_dict["course"]
|
course_name = frappe.form_dict["course"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
frappe.local.flags.redirect_location = "/courses"
|
frappe.local.flags.redirect_location = "/courses"
|
||||||
raise frappe.Redirect
|
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,
|
course = frappe.db.get_value("LMS Course", course_name,
|
||||||
["name", "title", "image", "short_introduction", "description", "published", "upcoming", "disable_self_learning",
|
["name", "title", "image", "short_introduction", "description", "published", "upcoming", "disable_self_learning",
|
||||||
"status", "video_link", "enable_certification", "grant_certificate_after", "paid_certificate",
|
"status", "video_link", "enable_certification", "grant_certificate_after", "paid_certificate",
|
||||||
@@ -43,6 +51,9 @@ def get_context(context):
|
|||||||
if context.course.upcoming:
|
if context.course.upcoming:
|
||||||
context.is_user_interested = get_user_interest(context.course.name)
|
context.is_user_interested = get_user_interest(context.course.name)
|
||||||
|
|
||||||
|
if frappe.form_dict.get("edit"):
|
||||||
|
context.course.edit_mode = True
|
||||||
|
|
||||||
context.metatags = {
|
context.metatags = {
|
||||||
"title": course.title,
|
"title": course.title,
|
||||||
"image": course.image,
|
"image": course.image,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<div class="common-page-style dashboard">
|
<div class="common-page-style dashboard">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{% if portal_course_creation %}
|
{% 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>
|
<svg class="icon icon-sm mr-1"><use href="#icon-add"></use></svg>
|
||||||
{{ _("New Course")}}
|
{{ _("New Course")}}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user