Ayush Shukla | a111f78 | 2017-06-20 13:04:45 +0530 | [diff] [blame] | 1 | |
| 2 | frappe.Leaderboard = Class.extend({ |
| 3 | |
| 4 | init: function (parent) { |
| 5 | this.page = frappe.ui.make_app_page({ |
| 6 | parent: parent, |
| 7 | title: "Leaderboard", |
| 8 | single_column: true |
| 9 | }); |
| 10 | |
| 11 | // const list of doctypes |
| 12 | this.doctypes = ["Customer", "Item", "Supplier", "Sales Partner"]; |
| 13 | this.timelines = ["Week", "Month", "Quarter", "Year"]; |
| 14 | this.desc_fields = ["total_amount", "total_request", "annual_billing", "commission_rate"]; |
| 15 | this.filters = { |
| 16 | "Customer": this.map_array(["title", "total_amount", "total_item_purchased", "modified"]), |
| 17 | "Item": this.map_array(["title", "total_request", "total_purchase", "avg_price", "modified"]), |
| 18 | "Supplier": this.map_array(["title", "annual_billing", "total_unpaid", "modified"]), |
| 19 | "Sales Partner": this.map_array(["title", "commission_rate", "target_qty", "target_amount", "modified"]), |
| 20 | }; |
| 21 | |
| 22 | // for saving current selected filters |
| 23 | const _selected_filter = this.filters[this.doctypes[0]]; |
| 24 | this.options = { |
| 25 | selected_doctype: this.doctypes[0], |
| 26 | selected_filter: _selected_filter, |
| 27 | selected_filter_item: _selected_filter[1], |
| 28 | selected_timeline: this.timelines[0], |
| 29 | }; |
| 30 | |
| 31 | this.message = null; |
| 32 | this.make(); |
| 33 | }, |
| 34 | |
| 35 | |
| 36 | |
| 37 | make: function () { |
| 38 | var me = this; |
| 39 | |
| 40 | var $leaderboard = $(frappe.render_template("leaderboard", this)).appendTo(this.page.main); |
| 41 | |
| 42 | // events |
| 43 | $leaderboard.find(".select-doctype") |
| 44 | .on("change", function () { |
| 45 | me.options.selected_doctype = this.value; |
| 46 | me.options.selected_filter = me.filters[this.value]; |
| 47 | me.options.selected_filter_item = me.filters[this.value][1]; |
| 48 | me.make_request($leaderboard); |
| 49 | }); |
| 50 | |
| 51 | $leaderboard.find(".select-time") |
| 52 | .on("change", function () { |
| 53 | me.options.selected_timeline = this.value; |
| 54 | me.make_request($leaderboard); |
| 55 | }); |
| 56 | |
| 57 | // now get leaderboard |
| 58 | me.make_request($leaderboard); |
| 59 | }, |
| 60 | |
| 61 | make_request: function ($leaderboard) { |
| 62 | var me = this; |
| 63 | |
| 64 | frappe.model.with_doctype(me.options.selected_doctype, function () { |
| 65 | me.get_leaderboard(me.get_leaderboard_data, $leaderboard); |
| 66 | }); |
| 67 | }, |
| 68 | |
| 69 | get_leaderboard: function (notify, $leaderboard) { |
| 70 | var me = this; |
| 71 | |
| 72 | frappe.call({ |
| 73 | method: "erpnext.utilities.page.leaderboard.leaderboard.get_leaderboard", |
| 74 | args: { |
| 75 | obj: JSON.stringify(me.options) |
| 76 | }, |
| 77 | callback: function (res) { |
| 78 | console.log(res) |
| 79 | notify(me, res, $leaderboard); |
| 80 | } |
| 81 | }); |
| 82 | }, |
| 83 | |
| 84 | get_leaderboard_data: function (me, res, $leaderboard) { |
| 85 | if (res && res.message) { |
| 86 | me.message = null; |
| 87 | $leaderboard.find(".leaderboard").html(me.render_list_view(res.message)); |
| 88 | |
| 89 | // event to change arrow |
| 90 | $leaderboard.find(".leaderboard-item") |
| 91 | .click(function () { |
| 92 | const field = this.innerText.trim().toLowerCase().replace(new RegExp(" ", "g"), "_"); |
| 93 | if (field && field !== "title") { |
| 94 | const _selected_filter_item = me.options.selected_filter |
| 95 | .filter(i => i.field === field); |
| 96 | if (_selected_filter_item.length > 0) { |
| 97 | me.options.selected_filter_item = _selected_filter_item[0]; |
| 98 | me.options.selected_filter_item.value = _selected_filter_item[0].value === "ASC" ? "DESC" : "ASC"; |
| 99 | |
| 100 | const new_class_name = `icon-${me.options.selected_filter_item.field} fa fa-chevron-${me.options.selected_filter_item.value === "ASC" ? "up" : "down"}`; |
| 101 | $leaderboard.find(`.icon-${me.options.selected_filter_item.field}`) |
| 102 | .attr("class", new_class_name); |
| 103 | |
| 104 | // now make request to web |
| 105 | me.make_request($leaderboard); |
| 106 | } |
| 107 | } |
| 108 | }); |
| 109 | } else { |
| 110 | me.message = "No items found."; |
| 111 | $leaderboard.find(".leaderboard").html(me.render_list_view()); |
| 112 | } |
| 113 | }, |
| 114 | |
| 115 | render_list_view: function (items = []) { |
| 116 | var me = this; |
| 117 | |
| 118 | var html = |
| 119 | `${me.render_message()} |
| 120 | <div class="result" style="${me.message ? "display:none;" : ""}"> |
| 121 | ${me.render_result(items)} |
| 122 | </div>`; |
| 123 | |
| 124 | return $(html); |
| 125 | }, |
| 126 | |
| 127 | render_result: function (items) { |
| 128 | var me = this; |
| 129 | |
| 130 | var html = |
| 131 | `${me.render_list_header()} |
| 132 | ${me.render_list_result(items)}`; |
| 133 | |
| 134 | return html; |
| 135 | }, |
| 136 | |
| 137 | render_list_header: function () { |
| 138 | var me = this; |
| 139 | const _selected_filter = me.options.selected_filter |
| 140 | .map(i => me.map_field(i.field)).slice(1); |
| 141 | |
| 142 | const html = |
| 143 | `<div class="list-headers"> |
| 144 | <div class="list-item list-item--head" data-list-renderer="${"List"}"> |
| 145 | ${ |
| 146 | me.options.selected_filter |
| 147 | .map(filter => { |
| 148 | const col = me.map_field(filter.field); |
| 149 | return ( |
| 150 | `<div class="leaderboard-item list-item_content ellipsis text-muted list-item__content--flex-2 |
| 151 | header-btn-base ${(col !== "Title" && col !== "Modified") ? "hidden-xs" : ""} |
| 152 | ${(col && _selected_filter.indexOf(col) !== -1) ? "text-right" : ""}"> |
| 153 | <span class="list-col-title ellipsis"> |
| 154 | ${col} |
| 155 | <i class="${"icon-" + filter.field} fa ${filter.value === "ASC" ? "fa-chevron-up" : "fa-chevron-down"}" |
| 156 | style="${col === "Title" ? "display:none;" : ""}"></i> |
| 157 | </span> |
| 158 | </div>`); |
| 159 | }).join("") |
| 160 | } |
| 161 | </div> |
| 162 | </div>`; |
| 163 | return html; |
| 164 | }, |
| 165 | |
| 166 | render_list_result: function (items) { |
| 167 | var me = this; |
| 168 | |
| 169 | let _html = items.map((item) => { |
| 170 | const $value = $(me.get_item_html(item)); |
| 171 | const $item_container = $(`<div class="list-item-container">`).append($value); |
| 172 | return $item_container[0].outerHTML; |
| 173 | }).join(""); |
| 174 | |
| 175 | let html = |
| 176 | `<div class="result-list"> |
| 177 | <div class="list-items"> |
| 178 | ${_html} |
| 179 | </div> |
| 180 | </div>`; |
| 181 | |
| 182 | return html; |
| 183 | }, |
| 184 | |
| 185 | render_message: function () { |
| 186 | var me = this; |
| 187 | |
| 188 | let html = |
| 189 | `<div class="no-result text-center" style="${me.message ? "" : "display:none;"}"> |
| 190 | <div class="msg-box no-border"> |
| 191 | <p>No Item found</p> |
| 192 | </div> |
| 193 | </div>`; |
| 194 | |
| 195 | return html; |
| 196 | }, |
| 197 | |
| 198 | get_item_html: function (item) { |
| 199 | var me = this; |
| 200 | const _selected_filter = me.options.selected_filter |
| 201 | .map(i => me.map_field(i.field)).slice(1); |
| 202 | |
| 203 | const html = |
| 204 | `<div class="list-item"> |
| 205 | ${ |
| 206 | me.options.selected_filter |
| 207 | .map(filter => { |
| 208 | const col = me.map_field(filter.field); |
| 209 | let val = item[filter.field]; |
| 210 | if (col === "Modified") { |
| 211 | val = comment_when(val); |
| 212 | } |
| 213 | return ( |
| 214 | `<div class="list-item_content ellipsis list-item__content--flex-2 |
| 215 | ${(col !== "Title" && col !== "Modified") ? "hidden-xs" : ""} |
| 216 | ${(col && _selected_filter.indexOf(col) !== -1) ? "text-right" : ""}"> |
| 217 | ${ |
| 218 | col === "Title" |
| 219 | ? `<a class="grey list-id ellipsis" href="${item["href"]}"> ${val} </a>` |
| 220 | : `<span class="text-muted ellipsis"> ${val}</span>` |
| 221 | } |
| 222 | </div>`); |
| 223 | }).join("") |
| 224 | } |
| 225 | </div>`; |
| 226 | |
| 227 | return html; |
| 228 | }, |
| 229 | |
| 230 | map_field: function (field) { |
| 231 | return field.replace(new RegExp("_", "g"), " ").replace(/(^|\s)[a-z]/g, f => f.toUpperCase()) |
| 232 | }, |
| 233 | |
| 234 | map_array: function (_array) { |
| 235 | var me = this; |
| 236 | return _array.map((str) => { |
| 237 | let value = me.desc_fields.indexOf(str) > -1 ? "DESC" : "ASC"; |
| 238 | return { |
| 239 | field: str, |
| 240 | value: value |
| 241 | }; |
| 242 | }); |
| 243 | } |
| 244 | }); |
| 245 | |
| 246 | frappe.pages["leaderboard"].on_page_load = function (wrapper) { |
| 247 | frappe.leaderboard = new frappe.Leaderboard(wrapper); |
| 248 | } |