Merge pull request #323 from pateljannat/start-learning-fixes
This commit is contained in:
@@ -33,6 +33,18 @@ class CourseEvaluator(Document):
|
||||
frappe.throw(_("Slot Times are overlapping for some schedules."))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_schedule(course):
|
||||
def get_schedule(course, date):
|
||||
evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
|
||||
return frappe.get_all("Evaluator Schedule", filters={"parent": evaluator}, fields=["day", "start_time", "end_time"])
|
||||
all_slots = frappe.get_all("Evaluator Schedule",
|
||||
filters = { "parent": evaluator },
|
||||
fields = ["day", "start_time", "end_time"])
|
||||
booked_slots = frappe.get_all("LMS Certificate Request",
|
||||
filters = {"course": course, "date": date},
|
||||
fields = ["start_time"])
|
||||
|
||||
for slot in booked_slots:
|
||||
same_slot = list(filter(lambda x: x.start_time == slot.start_time, all_slots))
|
||||
if len(same_slot):
|
||||
all_slots.remove(same_slot[0])
|
||||
|
||||
return all_slots
|
||||
|
||||
@@ -191,6 +191,7 @@
|
||||
"fieldname": "evaluator",
|
||||
"fieldtype": "Link",
|
||||
"label": "Evaluator",
|
||||
"mandatory_depends_on": "eval: doc.grant_certificate_after == \"Evaluation\"",
|
||||
"options": "Course Evaluator"
|
||||
},
|
||||
{
|
||||
@@ -236,7 +237,7 @@
|
||||
"link_fieldname": "course"
|
||||
}
|
||||
],
|
||||
"modified": "2022-04-07 12:27:05.353788",
|
||||
"modified": "2022-04-08 14:36:22.254656",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "LMS Course",
|
||||
|
||||
@@ -1410,3 +1410,7 @@ pre {
|
||||
.course-content-parent .course-details-outline .course-home-headings {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn-outline-primary {
|
||||
border: 1px solid var(--primary-color);
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@
|
||||
|
||||
{% macro BreadCrumb(course, lesson) %}
|
||||
<div class="breadcrumb">
|
||||
<a class="dark-links" href="/courses">{{ _("All Courses") }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/lms/icons/chevron-right.svg">
|
||||
<a class="dark-links" href="/courses/{{ course.name }}">{{ course.title }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/lms/icons/chevron-right.svg">
|
||||
<span class="breadcrumb-destination">{{ lesson.title }}</span>
|
||||
<a class="dark-links" href="/courses">{{ _("All Courses") }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/lms/icons/chevron-right.svg">
|
||||
<a class="dark-links" href="/courses/{{ course.name }}">{{ course.title }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/lms/icons/chevron-right.svg">
|
||||
<span class="breadcrumb-destination">{{ lesson.title }}</span>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
{{ render_html(lesson.body) }}
|
||||
{% else %}
|
||||
<div class="">
|
||||
<a class="button is-primary pull-right" href="/courses/{{ course.name }}"> {{ _("Start Learning") }} </a>
|
||||
<div class="button is-primary pull-right join-batch" data-course="{{ course.name | urlencode }}"> {{ _("Start Learning") }} </div>
|
||||
<div class=""> {{ _("This lesson is not available for preview. Please join the course to access it.") }} </div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,49 +1,53 @@
|
||||
frappe.ready(() => {
|
||||
|
||||
localStorage.removeItem($("#quiz-title").text());
|
||||
fetch_assignments();
|
||||
localStorage.removeItem($("#quiz-title").text());
|
||||
fetch_assignments();
|
||||
|
||||
save_current_lesson();
|
||||
save_current_lesson();
|
||||
|
||||
$(".option").click((e) => {
|
||||
enable_check(e);
|
||||
})
|
||||
$(".option").click((e) => {
|
||||
enable_check(e);
|
||||
})
|
||||
|
||||
$(".mark-progress").click((e) => {
|
||||
mark_progress(e);
|
||||
});
|
||||
$(".mark-progress").click((e) => {
|
||||
mark_progress(e);
|
||||
});
|
||||
|
||||
$(".next").click((e) => {
|
||||
mark_progress(e);
|
||||
});
|
||||
$(".next").click((e) => {
|
||||
mark_progress(e);
|
||||
});
|
||||
|
||||
$("#summary").click((e) => {
|
||||
quiz_summary(e);
|
||||
});
|
||||
$("#summary").click((e) => {
|
||||
quiz_summary(e);
|
||||
});
|
||||
|
||||
$("#check").click((e) => {
|
||||
check_answer(e);
|
||||
});
|
||||
$("#check").click((e) => {
|
||||
check_answer(e);
|
||||
});
|
||||
|
||||
$("#next").click((e) => {
|
||||
mark_active_question(e);
|
||||
});
|
||||
$("#next").click((e) => {
|
||||
mark_active_question(e);
|
||||
});
|
||||
|
||||
$("#try-again").click((e) => {
|
||||
try_quiz_again(e);
|
||||
});
|
||||
$("#try-again").click((e) => {
|
||||
try_quiz_again(e);
|
||||
});
|
||||
|
||||
$("#certification").click((e) => {
|
||||
create_certificate(e);
|
||||
});
|
||||
$("#certification").click((e) => {
|
||||
create_certificate(e);
|
||||
});
|
||||
|
||||
$(".submit-work").click((e) => {
|
||||
attach_work(e);
|
||||
});
|
||||
$(".submit-work").click((e) => {
|
||||
attach_work(e);
|
||||
});
|
||||
|
||||
$(".clear-work").click((e) => {
|
||||
clear_work(e);
|
||||
});
|
||||
$(".clear-work").click((e) => {
|
||||
clear_work(e);
|
||||
});
|
||||
|
||||
$(".join-batch").click((e) => {
|
||||
join_course(e)
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -240,6 +244,36 @@ const add_to_local_storage = (quiz_name, current_index, answer, is_correct) => {
|
||||
localStorage.setItem(quiz_name, JSON.stringify(quiz_stored))
|
||||
};
|
||||
|
||||
const join_course = (e) => {
|
||||
e.preventDefault();
|
||||
let course = $(e.currentTarget).attr("data-course")
|
||||
if (frappe.session.user == "Guest") {
|
||||
window.location.href = `/login?redirect-to=/courses/${course}`;
|
||||
return;
|
||||
}
|
||||
|
||||
let batch = $(e.currentTarget).attr("data-batch");
|
||||
batch = batch ? decodeURIComponent(batch) : "";
|
||||
frappe.call({
|
||||
"method": "lms.lms.doctype.lms_batch_membership.lms_batch_membership.create_membership",
|
||||
"args": {
|
||||
"batch": batch ? batch : "",
|
||||
"course": course
|
||||
},
|
||||
"callback": (data) => {
|
||||
if (data.message == "OK") {
|
||||
frappe.msgprint({
|
||||
"title": __("Successfully Enrolled"),
|
||||
"message": __("You are now a student of this course.")
|
||||
});
|
||||
setTimeout(function () {
|
||||
window.location.href = `/courses/${course}/learn/1.1`;
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const create_certificate = (e) => {
|
||||
e.preventDefault();
|
||||
course = $(".title").attr("data-course");
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
{{ _("You have opted to be notified for this course. You will receive an email when the course becomes available.") }}
|
||||
</div>
|
||||
|
||||
{% if certificate_request %}
|
||||
{% if certificate_request and not certificate %}
|
||||
<p class="mb-2"> <b>{{ _("Evaluation On: ") }}</b>
|
||||
{{ _("{0} at {1}").format(frappe.utils.format_date(certificate_request.date, "medium"),
|
||||
frappe.utils.format_time(certificate_request.start_time, "short")) }} </p>
|
||||
@@ -199,7 +199,6 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% set certificate = is_certified(course.name) %}
|
||||
{% set progress = frappe.utils.cint(membership.progress) %}
|
||||
{% if membership and course.enable_certification %}
|
||||
{% if certificate %}
|
||||
@@ -225,7 +224,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="font-weight-bold">{{ _("Pick a Slot") }}</div>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<button type="button" class="close close-slot-modal" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -238,8 +237,8 @@
|
||||
</div>
|
||||
<div class="control-input-wrapper">
|
||||
<div class="control-input">
|
||||
<input type="date" class="input-with-feedback form-control bold" data-fieldtype="Date"
|
||||
id="slot-date" min="{{ frappe.utils.format_date(frappe.utils.getdate(), 'yyyy-mm-dd') }}">
|
||||
<input type="date" class="input-with-feedback form-control bold" data-fieldtype="Date" data-course="{{ course.name | urlencode }}"
|
||||
id="slot-date" min="{{ frappe.utils.format_date(frappe.utils.add_days(frappe.utils.getdate(), 1), 'yyyy-mm-dd') }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -256,6 +255,10 @@
|
||||
<p id="no-slots-message" class="small text-danger hide"> {{ _("There are no slots available on this day.") }} </p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="button is-primary" data-course="{{ course.name | urlencode}}" id="submit-slot">
|
||||
{{ _("Submit") }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@ frappe.ready(() => {
|
||||
});
|
||||
|
||||
$(".join-batch").click((e) => {
|
||||
join_course(e)
|
||||
join_course(e);
|
||||
});
|
||||
|
||||
$(".view-all-mentors").click((e) => {
|
||||
@@ -46,10 +46,18 @@ frappe.ready(() => {
|
||||
display_slots(e);
|
||||
});
|
||||
|
||||
$(document).on("click", ".slot", (e) => {
|
||||
$("#submit-slot").click((e) => {
|
||||
submit_slot(e);
|
||||
});
|
||||
|
||||
$(".close-slot-modal").click((e) => {
|
||||
close_slot_modal(e);
|
||||
});
|
||||
|
||||
$(document).on("click", ".slot", (e) => {
|
||||
select_slot(e);
|
||||
});
|
||||
|
||||
$(document).scroll(function() {
|
||||
let timer;
|
||||
clearTimeout(timer);
|
||||
@@ -93,31 +101,35 @@ var cancel_mentor_request = (e) => {
|
||||
})
|
||||
}
|
||||
|
||||
var join_course = (e) => {
|
||||
e.preventDefault();
|
||||
var course = $(e.currentTarget).attr("data-course")
|
||||
if (frappe.session.user == "Guest") {
|
||||
window.location.href = `/login?redirect-to=/courses/${course}`;
|
||||
return;
|
||||
}
|
||||
var batch = $(e.currentTarget).attr("data-batch");
|
||||
batch = batch ? decodeURIComponent(batch) : "";
|
||||
frappe.call({
|
||||
"method": "lms.lms.doctype.lms_batch_membership.lms_batch_membership.create_membership",
|
||||
"args": {
|
||||
"batch": batch ? batch : "",
|
||||
"course": course
|
||||
},
|
||||
"callback": (data) => {
|
||||
if (data.message == "OK") {
|
||||
frappe.msgprint(__("You are now a student of this course."));
|
||||
setTimeout(function () {
|
||||
window.location.href = `/courses/${course}/learn/1.1`;
|
||||
}, 2000);
|
||||
}
|
||||
const join_course = (e) => {
|
||||
e.preventDefault();
|
||||
let course = $(e.currentTarget).attr("data-course");
|
||||
if (frappe.session.user == "Guest") {
|
||||
window.location.href = `/login?redirect-to=/courses/${course}`;
|
||||
return;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let batch = $(e.currentTarget).attr("data-batch");
|
||||
batch = batch ? decodeURIComponent(batch) : "";
|
||||
frappe.call({
|
||||
"method": "lms.lms.doctype.lms_batch_membership.lms_batch_membership.create_membership",
|
||||
"args": {
|
||||
"batch": batch ? batch : "",
|
||||
"course": course
|
||||
},
|
||||
"callback": (data) => {
|
||||
if (data.message == "OK") {
|
||||
frappe.msgprint({
|
||||
"title": __("Successfully Enrolled"),
|
||||
"message": __("You are now a student of this course.")
|
||||
});
|
||||
setTimeout(function () {
|
||||
window.location.href = `/courses/${course}/learn/1.1`;
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
var view_all_mentors = (e) => {
|
||||
$(".wrapped").each((i, element) => {
|
||||
@@ -251,29 +263,14 @@ const submit_for_review = (e) => {
|
||||
};
|
||||
|
||||
const apply_cetificate = (e) => {
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
|
||||
args: {
|
||||
"course": $(e.currentTarget).data("course")
|
||||
},
|
||||
callback: (data) => {
|
||||
let options = "";
|
||||
data.message.forEach((obj) => {
|
||||
options += `<button type="button" class="btn btn-sm btn-secondary mr-3 slot hide"
|
||||
data-course="${$(e.currentTarget).data("course")}"
|
||||
data-day="${obj.day}" data-start="${obj.start_time}" data-end="${obj.end_time}">
|
||||
${obj.day} ${obj.start_time} - ${obj.end_time}</button>`;
|
||||
});
|
||||
e.preventDefault();
|
||||
$("#slot-modal .slots").html(options);
|
||||
$("#slot-modal").modal("show");
|
||||
}
|
||||
})
|
||||
$("#slot-modal").modal("show");
|
||||
|
||||
|
||||
};
|
||||
|
||||
const submit_slot = (e) => {
|
||||
e.preventDefault();
|
||||
const slot = $(e.currentTarget);
|
||||
const slot = window.selected_slot;
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_certificate_request",
|
||||
args: {
|
||||
@@ -294,17 +291,51 @@ const submit_slot = (e) => {
|
||||
};
|
||||
|
||||
const display_slots = (e) => {
|
||||
const weekday = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
|
||||
const day = weekday[new Date($(e.currentTarget).val()).getDay()]
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
|
||||
args: {
|
||||
"course": $(e.currentTarget).data("course"),
|
||||
"date": $(e.currentTarget).val()
|
||||
},
|
||||
callback: (data) => {
|
||||
let options = "";
|
||||
data.message.forEach((obj) => {
|
||||
options += `<button type="button" class="btn btn-sm btn-secondary mr-3 slot hide"
|
||||
data-course="${$(e.currentTarget).data("course")}"
|
||||
data-day="${obj.day}" data-start="${obj.start_time}" data-end="${obj.end_time}">
|
||||
${format_time(obj.start_time)} - ${format_time(obj.end_time)}</button>`;
|
||||
});
|
||||
e.preventDefault();
|
||||
$("#slot-modal .slots").html(options);
|
||||
const weekday = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
|
||||
const day = weekday[new Date($(e.currentTarget).val()).getDay()]
|
||||
|
||||
$(".slot").addClass("hide");
|
||||
$(".slot-label").addClass("hide");
|
||||
$(".slot").addClass("hide");
|
||||
$(".slot-label").addClass("hide");
|
||||
|
||||
if ($(`[data-day='${day}']`).length) {
|
||||
$(".slot-label").removeClass("hide");
|
||||
$(`[data-day='${day}']`).removeClass("hide");
|
||||
$("#no-slots-message").addClass("hide");
|
||||
} else {
|
||||
$("#no-slots-message").removeClass("hide");
|
||||
}
|
||||
if ($(`[data-day='${day}']`).length) {
|
||||
$(".slot-label").removeClass("hide");
|
||||
$(`[data-day='${day}']`).removeClass("hide");
|
||||
$("#no-slots-message").addClass("hide");
|
||||
} else {
|
||||
$("#no-slots-message").removeClass("hide");
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import frappe
|
||||
from lms.lms.doctype.lms_settings.lms_settings import check_profile_restriction
|
||||
from lms.lms.utils import get_membership, is_instructor
|
||||
from lms.lms.utils import get_membership, is_instructor, is_certified
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
@@ -32,6 +32,7 @@ def get_context(context):
|
||||
context.membership = membership
|
||||
context.restriction = check_profile_restriction()
|
||||
context.show_start_learing_cta = show_start_learing_cta(course, membership, context.restriction)
|
||||
context.certificate = is_certified(course.name)
|
||||
context.certificate_request = frappe.db.get_value("LMS Certificate Request",
|
||||
{
|
||||
"course": course.name,
|
||||
|
||||
@@ -14,9 +14,9 @@ def get_context(context):
|
||||
|
||||
def get_courses():
|
||||
courses = frappe.get_all("LMS Course",
|
||||
filters={"published": True},
|
||||
fields=["name", "upcoming", "title", "image", "enable_certification",
|
||||
"paid_certificate", "price_certificate", "currency"])
|
||||
filters={"published": True},
|
||||
fields=["name", "upcoming", "title", "image", "enable_certification",
|
||||
"paid_certificate", "price_certificate", "currency"])
|
||||
|
||||
live_courses, upcoming_courses = [], []
|
||||
for course in courses:
|
||||
|
||||
Reference in New Issue
Block a user