249 lines
6.8 KiB
JavaScript
249 lines
6.8 KiB
JavaScript
|
|
||
|
frappe.Leaderboard = Class.extend({
|
||
|
|
||
|
init: function (parent) {
|
||
|
this.page = frappe.ui.make_app_page({
|
||
|
parent: parent,
|
||
|
title: "Leaderboard",
|
||
|
single_column: true
|
||
|
});
|
||
|
|
||
|
// const list of doctypes
|
||
|
this.doctypes = ["Customer", "Item", "Supplier", "Sales Partner"];
|
||
|
this.timelines = ["Week", "Month", "Quarter", "Year"];
|
||
|
this.desc_fields = ["total_amount", "total_request", "annual_billing", "commission_rate"];
|
||
|
this.filters = {
|
||
|
"Customer": this.map_array(["title", "total_amount", "total_item_purchased", "modified"]),
|
||
|
"Item": this.map_array(["title", "total_request", "total_purchase", "avg_price", "modified"]),
|
||
|
"Supplier": this.map_array(["title", "annual_billing", "total_unpaid", "modified"]),
|
||
|
"Sales Partner": this.map_array(["title", "commission_rate", "target_qty", "target_amount", "modified"]),
|
||
|
};
|
||
|
|
||
|
// for saving current selected filters
|
||
|
const _selected_filter = this.filters[this.doctypes[0]];
|
||
|
this.options = {
|
||
|
selected_doctype: this.doctypes[0],
|
||
|
selected_filter: _selected_filter,
|
||
|
selected_filter_item: _selected_filter[1],
|
||
|
selected_timeline: this.timelines[0],
|
||
|
};
|
||
|
|
||
|
this.message = null;
|
||
|
this.make();
|
||
|
},
|
||
|
|
||
|
|
||
|
|
||
|
make: function () {
|
||
|
var me = this;
|
||
|
|
||
|
var $leaderboard = $(frappe.render_template("leaderboard", this)).appendTo(this.page.main);
|
||
|
|
||
|
// events
|
||
|
$leaderboard.find(".select-doctype")
|
||
|
.on("change", function () {
|
||
|
me.options.selected_doctype = this.value;
|
||
|
me.options.selected_filter = me.filters[this.value];
|
||
|
me.options.selected_filter_item = me.filters[this.value][1];
|
||
|
me.make_request($leaderboard);
|
||
|
});
|
||
|
|
||
|
$leaderboard.find(".select-time")
|
||
|
.on("change", function () {
|
||
|
me.options.selected_timeline = this.value;
|
||
|
me.make_request($leaderboard);
|
||
|
});
|
||
|
|
||
|
// now get leaderboard
|
||
|
me.make_request($leaderboard);
|
||
|
},
|
||
|
|
||
|
make_request: function ($leaderboard) {
|
||
|
var me = this;
|
||
|
|
||
|
frappe.model.with_doctype(me.options.selected_doctype, function () {
|
||
|
me.get_leaderboard(me.get_leaderboard_data, $leaderboard);
|
||
|
});
|
||
|
},
|
||
|
|
||
|
get_leaderboard: function (notify, $leaderboard) {
|
||
|
var me = this;
|
||
|
|
||
|
frappe.call({
|
||
|
method: "erpnext.utilities.page.leaderboard.leaderboard.get_leaderboard",
|
||
|
args: {
|
||
|
obj: JSON.stringify(me.options)
|
||
|
},
|
||
|
callback: function (res) {
|
||
|
console.log(res)
|
||
|
notify(me, res, $leaderboard);
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
get_leaderboard_data: function (me, res, $leaderboard) {
|
||
|
if (res && res.message) {
|
||
|
me.message = null;
|
||
|
$leaderboard.find(".leaderboard").html(me.render_list_view(res.message));
|
||
|
|
||
|
// event to change arrow
|
||
|
$leaderboard.find(".leaderboard-item")
|
||
|
.click(function () {
|
||
|
const field = this.innerText.trim().toLowerCase().replace(new RegExp(" ", "g"), "_");
|
||
|
if (field && field !== "title") {
|
||
|
const _selected_filter_item = me.options.selected_filter
|
||
|
.filter(i => i.field === field);
|
||
|
if (_selected_filter_item.length > 0) {
|
||
|
me.options.selected_filter_item = _selected_filter_item[0];
|
||
|
me.options.selected_filter_item.value = _selected_filter_item[0].value === "ASC" ? "DESC" : "ASC";
|
||
|
|
||
|
const new_class_name = `icon-${me.options.selected_filter_item.field} fa fa-chevron-${me.options.selected_filter_item.value === "ASC" ? "up" : "down"}`;
|
||
|
$leaderboard.find(`.icon-${me.options.selected_filter_item.field}`)
|
||
|
.attr("class", new_class_name);
|
||
|
|
||
|
// now make request to web
|
||
|
me.make_request($leaderboard);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
me.message = "No items found.";
|
||
|
$leaderboard.find(".leaderboard").html(me.render_list_view());
|
||
|
}
|
||
|
},
|
||
|
|
||
|
render_list_view: function (items = []) {
|
||
|
var me = this;
|
||
|
|
||
|
var html =
|
||
|
`${me.render_message()}
|
||
|
<div class="result" style="${me.message ? "display:none;" : ""}">
|
||
|
${me.render_result(items)}
|
||
|
</div>`;
|
||
|
|
||
|
return $(html);
|
||
|
},
|
||
|
|
||
|
render_result: function (items) {
|
||
|
var me = this;
|
||
|
|
||
|
var html =
|
||
|
`${me.render_list_header()}
|
||
|
${me.render_list_result(items)}`;
|
||
|
|
||
|
return html;
|
||
|
},
|
||
|
|
||
|
render_list_header: function () {
|
||
|
var me = this;
|
||
|
const _selected_filter = me.options.selected_filter
|
||
|
.map(i => me.map_field(i.field)).slice(1);
|
||
|
|
||
|
const html =
|
||
|
`<div class="list-headers">
|
||
|
<div class="list-item list-item--head" data-list-renderer="${"List"}">
|
||
|
${
|
||
|
me.options.selected_filter
|
||
|
.map(filter => {
|
||
|
const col = me.map_field(filter.field);
|
||
|
return (
|
||
|
`<div class="leaderboard-item list-item_content ellipsis text-muted list-item__content--flex-2
|
||
|
header-btn-base ${(col !== "Title" && col !== "Modified") ? "hidden-xs" : ""}
|
||
|
${(col && _selected_filter.indexOf(col) !== -1) ? "text-right" : ""}">
|
||
|
<span class="list-col-title ellipsis">
|
||
|
${col}
|
||
|
<i class="${"icon-" + filter.field} fa ${filter.value === "ASC" ? "fa-chevron-up" : "fa-chevron-down"}"
|
||
|
style="${col === "Title" ? "display:none;" : ""}"></i>
|
||
|
</span>
|
||
|
</div>`);
|
||
|
}).join("")
|
||
|
}
|
||
|
</div>
|
||
|
</div>`;
|
||
|
return html;
|
||
|
},
|
||
|
|
||
|
render_list_result: function (items) {
|
||
|
var me = this;
|
||
|
|
||
|
let _html = items.map((item) => {
|
||
|
const $value = $(me.get_item_html(item));
|
||
|
const $item_container = $(`<div class="list-item-container">`).append($value);
|
||
|
return $item_container[0].outerHTML;
|
||
|
}).join("");
|
||
|
|
||
|
let html =
|
||
|
`<div class="result-list">
|
||
|
<div class="list-items">
|
||
|
${_html}
|
||
|
</div>
|
||
|
</div>`;
|
||
|
|
||
|
return html;
|
||
|
},
|
||
|
|
||
|
render_message: function () {
|
||
|
var me = this;
|
||
|
|
||
|
let html =
|
||
|
`<div class="no-result text-center" style="${me.message ? "" : "display:none;"}">
|
||
|
<div class="msg-box no-border">
|
||
|
<p>No Item found</p>
|
||
|
</div>
|
||
|
</div>`;
|
||
|
|
||
|
return html;
|
||
|
},
|
||
|
|
||
|
get_item_html: function (item) {
|
||
|
var me = this;
|
||
|
const _selected_filter = me.options.selected_filter
|
||
|
.map(i => me.map_field(i.field)).slice(1);
|
||
|
|
||
|
const html =
|
||
|
`<div class="list-item">
|
||
|
${
|
||
|
me.options.selected_filter
|
||
|
.map(filter => {
|
||
|
const col = me.map_field(filter.field);
|
||
|
let val = item[filter.field];
|
||
|
if (col === "Modified") {
|
||
|
val = comment_when(val);
|
||
|
}
|
||
|
return (
|
||
|
`<div class="list-item_content ellipsis list-item__content--flex-2
|
||
|
${(col !== "Title" && col !== "Modified") ? "hidden-xs" : ""}
|
||
|
${(col && _selected_filter.indexOf(col) !== -1) ? "text-right" : ""}">
|
||
|
${
|
||
|
col === "Title"
|
||
|
? `<a class="grey list-id ellipsis" href="${item["href"]}"> ${val} </a>`
|
||
|
: `<span class="text-muted ellipsis"> ${val}</span>`
|
||
|
}
|
||
|
</div>`);
|
||
|
}).join("")
|
||
|
}
|
||
|
</div>`;
|
||
|
|
||
|
return html;
|
||
|
},
|
||
|
|
||
|
map_field: function (field) {
|
||
|
return field.replace(new RegExp("_", "g"), " ").replace(/(^|\s)[a-z]/g, f => f.toUpperCase())
|
||
|
},
|
||
|
|
||
|
map_array: function (_array) {
|
||
|
var me = this;
|
||
|
return _array.map((str) => {
|
||
|
let value = me.desc_fields.indexOf(str) > -1 ? "DESC" : "ASC";
|
||
|
return {
|
||
|
field: str,
|
||
|
value: value
|
||
|
};
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
frappe.pages["leaderboard"].on_page_load = function (wrapper) {
|
||
|
frappe.leaderboard = new frappe.Leaderboard(wrapper);
|
||
|
}
|