feat: schedule evaluations
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "evaluator",
|
"fieldname": "evaluator",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
"label": "Evaluator",
|
"label": "Evaluator",
|
||||||
"options": "Course Evaluator"
|
"options": "Course Evaluator"
|
||||||
}
|
}
|
||||||
@@ -37,7 +38,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2023-07-13 14:21:49.953345",
|
"modified": "2023-07-13 17:51:36.278393",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "LMS",
|
"module": "LMS",
|
||||||
"name": "Class Course",
|
"name": "Class Course",
|
||||||
|
|||||||
@@ -36,14 +36,26 @@ class CourseEvaluator(Document):
|
|||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_schedule(course, date):
|
def get_schedule(course, date, class_name=None):
|
||||||
evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
|
evaluator = None
|
||||||
|
|
||||||
|
if class_name:
|
||||||
|
evaluator = frappe.db.get_value(
|
||||||
|
"Class Course",
|
||||||
|
{"parent": class_name, "course": course},
|
||||||
|
"evaluator",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not evaluator:
|
||||||
|
evaluator = frappe.db.get_value("LMS Course", course, "evaluator")
|
||||||
|
|
||||||
all_slots = frappe.get_all(
|
all_slots = frappe.get_all(
|
||||||
"Evaluator Schedule",
|
"Evaluator Schedule",
|
||||||
filters={"parent": evaluator},
|
filters={"parent": evaluator},
|
||||||
fields=["day", "start_time", "end_time"],
|
fields=["day", "start_time", "end_time"],
|
||||||
order_by="start_time",
|
order_by="start_time",
|
||||||
)
|
)
|
||||||
|
|
||||||
booked_slots = frappe.get_all(
|
booked_slots = frappe.get_all(
|
||||||
"LMS Certificate Request",
|
"LMS Certificate Request",
|
||||||
filters={"evaluator": evaluator, "date": date},
|
filters={"evaluator": evaluator, "date": date},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
frappe.ready(() => {
|
frappe.ready(() => {
|
||||||
setup_file_size();
|
setup_file_size();
|
||||||
pin_header();
|
pin_header();
|
||||||
|
setup_router();
|
||||||
|
|
||||||
$(".join-batch").click((e) => {
|
$(".join-batch").click((e) => {
|
||||||
join_course(e);
|
join_course(e);
|
||||||
@@ -42,6 +43,14 @@ frappe.ready(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setup_router = () => {
|
||||||
|
frappe.router = {
|
||||||
|
slug(name) {
|
||||||
|
return name.toLowerCase().replace(/ /g, "-");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const pin_header = () => {
|
const pin_header = () => {
|
||||||
const el = document.querySelector(".sticky");
|
const el = document.querySelector(".sticky");
|
||||||
if (el) {
|
if (el) {
|
||||||
|
|||||||
@@ -30,21 +30,27 @@
|
|||||||
{{ class_info.name }}
|
{{ class_info.name }}
|
||||||
</a>
|
</a>
|
||||||
<img class="icon icon-sm mr-0" src="/assets/lms/icons/chevron-right.svg">
|
<img class="icon icon-sm mr-0" src="/assets/lms/icons/chevron-right.svg">
|
||||||
<span class="breadcrumb-destination">{{ _("Student Progress").format(student.full_name) }}</span>
|
<span class="breadcrumb-destination">
|
||||||
|
{{ _("Student Progress").format(student.full_name) }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if is_moderator %}
|
|
||||||
<div class="align-self-center">
|
<div class="align-self-center">
|
||||||
<a class="btn btn-default btn-sm mr-2" href="/users/{{ student.username }}">
|
<a class="btn btn-default btn-sm" href="/users/{{ student.username }}">
|
||||||
{{ _("View Profile") }}
|
{{ _("View Profile") }}
|
||||||
</a>
|
</a>
|
||||||
<a class="btn btn-primary btn-sm btn-evaluate" href=/evaluation/new?member={{student.name}}&date={{frappe.utils.getdate()}}&class={{class_info.name}}">
|
{% if student.name == frappe.session.user %}
|
||||||
|
<button class="btn btn-default btn-sm btn-schedule-eval ml-2">
|
||||||
|
{{ _("Schedule Evaluation") }}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
{% if is_moderator %}
|
||||||
|
<a class="btn btn-primary btn-sm btn-evaluate ml-2" href=/evaluation/new?member={{student.name}}&date={{frappe.utils.getdate()}}&class={{class_info.name}}">
|
||||||
{{ _("Evaluate") }}
|
{{ _("Evaluate") }}
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -108,3 +114,17 @@
|
|||||||
<p class="text-muted mt-3"> {{ _("No Assessments") }} </p>
|
<p class="text-muted mt-3"> {{ _("No Assessments") }} </p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{%- block script %}
|
||||||
|
{{ super() }}
|
||||||
|
<script>
|
||||||
|
frappe.boot.user = {
|
||||||
|
"can_create": [],
|
||||||
|
"can_select": ["LMS Course"],
|
||||||
|
"can_read": ["LMS Course"]
|
||||||
|
};
|
||||||
|
let courses = {{ courses | json }};
|
||||||
|
let class_name = "{{ class_info.name }}";
|
||||||
|
</script>
|
||||||
|
{{ include_script('controls.bundle.js') }}
|
||||||
|
{% endblock %}
|
||||||
@@ -2,4 +2,134 @@ frappe.ready(() => {
|
|||||||
$(".clickable-row").click((e) => {
|
$(".clickable-row").click((e) => {
|
||||||
window.location.href = $(e.currentTarget).data("href");
|
window.location.href = $(e.currentTarget).data("href");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".btn-schedule-eval").click((e) => {
|
||||||
|
open_evaluation_form(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).on("click", ".slot", (e) => {
|
||||||
|
mark_active_slot(e);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const open_evaluation_form = (e) => {
|
||||||
|
this.eval_form = new frappe.ui.Dialog({
|
||||||
|
title: __("Schedule Evaluation"),
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
fieldtype: "Link",
|
||||||
|
fieldname: "course",
|
||||||
|
label: __("Course"),
|
||||||
|
options: "LMS Course",
|
||||||
|
reqd: 1,
|
||||||
|
get_query: () => {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
name: ["in", courses],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "Date",
|
||||||
|
fieldname: "date",
|
||||||
|
label: __("Date"),
|
||||||
|
reqd: 1,
|
||||||
|
min_date: frappe.datetime.add_days(
|
||||||
|
frappe.datetime.get_today(),
|
||||||
|
1
|
||||||
|
),
|
||||||
|
change: () => {
|
||||||
|
get_slots();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldtype: "HTML",
|
||||||
|
fieldname: "slots",
|
||||||
|
label: __("Slots"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
primary_action: (values) => {
|
||||||
|
submit_evaluation_form(values);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.eval_form.show();
|
||||||
|
setTimeout(() => {
|
||||||
|
$(".modal-body").css("min-height", "300px");
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const get_slots = () => {
|
||||||
|
frappe.call({
|
||||||
|
method: "lms.lms.doctype.course_evaluator.course_evaluator.get_schedule",
|
||||||
|
args: {
|
||||||
|
course: this.eval_form.get_value("course"),
|
||||||
|
date: this.eval_form.get_value("date"),
|
||||||
|
class_name: class_name,
|
||||||
|
},
|
||||||
|
callback: (r) => {
|
||||||
|
if (r.message) {
|
||||||
|
console.log(r.message);
|
||||||
|
display_slots(r.message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const display_slots = (slots) => {
|
||||||
|
let slot_html = "";
|
||||||
|
let day = moment(this.eval_form.get_value("date")).format("dddd");
|
||||||
|
|
||||||
|
slots.forEach((slot) => {
|
||||||
|
if (slot.day == day) {
|
||||||
|
slot_html += `<div class="slot" data-day="${
|
||||||
|
slot.day
|
||||||
|
}" data-start="${slot.start_time}" data-end="${slot.end_time}">
|
||||||
|
${moment(slot.start_time, "hh:mm").format("hh:mm a")} - ${moment(
|
||||||
|
slot.end_time,
|
||||||
|
"hh:mm"
|
||||||
|
).format("hh:mm a")}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!slot_html) {
|
||||||
|
slot_html = `<div class="alert alert-danger" role="alert">
|
||||||
|
No slots available for this date.
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
$("[data-fieldname='slots']").html(slot_html);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mark_active_slot = (e) => {
|
||||||
|
$(".slot").removeClass("btn-outline-primary");
|
||||||
|
$(e.currentTarget).addClass("btn-outline-primary");
|
||||||
|
this.current_slot = $(e.currentTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit_evaluation_form = (values) => {
|
||||||
|
if (!this.current_slot) {
|
||||||
|
frappe.throw(__("Please select a slot"));
|
||||||
|
}
|
||||||
|
|
||||||
|
frappe.call({
|
||||||
|
method: "lms.lms.doctype.lms_certificate_request.lms_certificate_request.create_certificate_request",
|
||||||
|
args: {
|
||||||
|
course: values.course,
|
||||||
|
date: values.date,
|
||||||
|
start_time: this.current_slot.data("start"),
|
||||||
|
end_time: this.current_slot.data("end"),
|
||||||
|
day: this.current_slot.data("day"),
|
||||||
|
},
|
||||||
|
callback: (r) => {
|
||||||
|
if (r.message) {
|
||||||
|
frappe.msgprint({
|
||||||
|
title: __("Success"),
|
||||||
|
message: __("Evaluation scheduled successfully"),
|
||||||
|
});
|
||||||
|
this.eval_form.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -21,4 +21,8 @@ def get_context(context):
|
|||||||
"LMS Class", class_name, ["name"], as_dict=True
|
"LMS Class", class_name, ["name"], as_dict=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
context.courses = frappe.get_all(
|
||||||
|
"Class Course", {"parent": class_name}, pluck="course"
|
||||||
|
)
|
||||||
|
|
||||||
context.assessments = get_assessments(class_name, context.student.name)
|
context.assessments = get_assessments(class_name, context.student.name)
|
||||||
|
|||||||
Reference in New Issue
Block a user