@@ -77,4 +103,4 @@ frappe.views.HubFactory = frappe.views.Factory.extend({
return;
}
-});
+}
diff --git a/erpnext/public/js/hub/hub_listing.js b/erpnext/public/js/hub/hub_listing.js
index 9ac1b848eaa..a6a9ac975bb 100644
--- a/erpnext/public/js/hub/hub_listing.js
+++ b/erpnext/public/js/hub/hub_listing.js
@@ -1,5 +1,404 @@
frappe.provide('erpnext.hub');
+erpnext.hub.Marketplace = class Marketplace {
+ constructor({ parent }) {
+ this.$parent = $(parent);
+ this.page = parent.page;
+
+ this.setup_header();
+ this.make_sidebar();
+ this.make_body();
+ this.setup_events();
+ this.refresh();
+ }
+
+ setup_header() {
+ this.page.set_title(__('Marketplace'));
+ }
+
+ setup_events() {
+ this.$parent.on('click', '[data-route]', (e) => {
+ const $target = $(e.currentTarget);
+ const route = $target.data().route;
+ frappe.set_route(route);
+ });
+ }
+
+ make_sidebar() {
+ this.$sidebar = this.$parent.find('.layout-side-section');
+
+ this.$sidebar.append(`
+
+ `);
+
+ this.make_sidebar_categories();
+ }
+
+ make_sidebar_categories() {
+ frappe.call('erpnext.hub_node.get_categories')
+ .then(r => {
+ const categories = r.message.map(d => d.value).sort();
+ const sidebar_items = [
+ ``,
+ ``,
+ ...categories.map(category => `
+
+ `)
+ ];
+
+ this.$sidebar.append(`
+
+ `);
+
+ this.update_sidebar();
+ });
+ }
+
+ make_body() {
+ this.$body = this.$parent.find('.layout-main-section');
+ }
+
+ update_sidebar() {
+ const route = frappe.get_route_str();
+ const $sidebar_item = this.$sidebar.find(`[data-route="${route}"]`);
+
+ const $siblings = this.$sidebar.find('[data-route]');
+ $siblings.removeClass('active').addClass('text-muted');
+
+ $sidebar_item.addClass('active').removeClass('text-muted');
+ }
+
+ refresh() {
+ const route = frappe.get_route();
+ this.subpages = this.subpages || {};
+
+ for (let page in this.subpages) {
+ this.subpages[page].hide();
+ }
+
+ if (route[1] === 'home' && !this.subpages.home) {
+ this.subpages.home = new erpnext.hub.Home(this.$body);
+ }
+
+ if (route[1] === 'favourites' && !this.subpages.favourites) {
+ this.subpages.favourites = new erpnext.hub.Favourites(this.$body);
+ }
+
+ if (route[1] === 'category' && route[2] && !this.subpages.category) {
+ this.subpages.category = new erpnext.hub.Category(this.$body);
+ }
+
+ if (route[1] === 'item' && route[2] && !this.subpages.item) {
+ this.subpages.item = new erpnext.hub.Item(this.$body);
+ }
+
+ if (!Object.keys(this.subpages).includes(route[1])) {
+ frappe.show_not_found();
+ return;
+ }
+
+ this.update_sidebar();
+ frappe.utils.scroll_to(0);
+ this.subpages[route[1]].show();
+ }
+}
+
+class SubPage {
+ constructor(parent) {
+ this.$parent = $(parent);
+ this.make_wrapper();
+ }
+
+ make_wrapper() {
+ const page_name = frappe.get_route()[1];
+ this.$wrapper = $(`
`).appendTo(this.$parent);
+ this.hide();
+ }
+
+ show() {
+ this.refresh();
+ this.$wrapper.show();
+ }
+
+ hide() {
+ this.$wrapper.hide();
+ }
+}
+
+erpnext.hub.Home = class Home extends SubPage {
+ make_wrapper() {
+ super.make_wrapper();
+ this.make_search_bar();
+ }
+
+ refresh() {
+ this.get_items_and_render();
+ }
+
+ get_items_and_render() {
+ this.get_items()
+ .then(r => {
+ erpnext.hub.hub_item_cache = r.message;
+ this.render(r.message);
+ });
+ }
+
+ get_items() {
+ return frappe.call('erpnext.hub_node.get_list', {
+ doctype: 'Hub Item',
+ filters: {
+ image: ['like', 'http%']
+ }
+ });
+ }
+
+ make_search_bar() {
+ const $search = $(`
+
+
+
`
+ );
+ this.$wrapper.append($search);
+ const $search_input = $search.find('input');
+
+ $search_input.on('keydown', frappe.utils.debounce((e) => {
+ if (e.which === frappe.ui.keyCode.ENTER) {
+ this.search_value = $search_input.val();
+ this.get_items_and_render();
+ }
+ }, 300));
+ }
+
+ render(items) {
+ const html = get_item_card_container_html(items, __('Recently Published'));
+ this.$wrapper.html(html)
+ }
+}
+
+erpnext.hub.Favourites = class Favourites extends SubPage {
+ refresh() {
+ this.get_favourites()
+ .then(r => {
+ this.render(r.message);
+ });
+ }
+
+ get_favourites() {
+ return frappe.call('erpnext.hub_node.get_item_favourites');
+ }
+
+ render(items) {
+ const html = get_item_card_container_html(items, __('Favourites'));
+ this.$wrapper.html(html)
+ }
+}
+
+erpnext.hub.Category = class Category extends SubPage {
+ refresh() {
+ this.category = frappe.get_route()[2];
+ this.get_items_for_category(this.category)
+ .then(r => {
+ this.render(r.message);
+ });
+ }
+
+ get_items_for_category(category) {
+ return frappe.call('erpnext.hub_node.get_list', {
+ doctype: 'Hub Item',
+ filters: {
+ hub_category: category
+ }
+ });
+ }
+
+ render(items) {
+ const html = get_item_card_container_html(items, __(this.category));
+ this.$wrapper.html(html)
+ }
+}
+
+erpnext.hub.Item = class Item extends SubPage {
+ refresh() {
+ const hub_item_code = frappe.get_route()[2];
+
+ this.get_item(hub_item_code)
+ .then(item => {
+ this.render(item);
+ });
+ }
+
+ get_item(hub_item_code) {
+ return new Promise(resolve => {
+ const item = (erpnext.hub.hub_item_cache || []).find(item => item.name === hub_item_code)
+
+ if (item) {
+ resolve(item);
+ } else {
+ frappe.call('erpnext.hub_node.get_list', {
+ doctype: 'Hub Item',
+ filters: {
+ name: hub_item_code
+ }
+ })
+ .then(r => {
+ resolve(r.message[0]);
+ });
+ }
+ });
+ }
+
+ render(item) {
+ const title = item.item_name || item.name;
+ const company = item.company_name;
+
+ const who = __('Posted By {0}', [company]);
+ const when = comment_when(item.creation);
+
+ const city = item.seller_city ? item.seller_city + ', ' : '';
+ const country = item.country ? item.country : '';
+ const where = `${city}${country}`;
+
+ const dot_spacer = '
· ';
+
+ const description = item.description || '';
+
+ const rating_html = get_rating_html(item);
+ const rating_count = item.reviews.length > 0 ? `(${item.reviews.length} reviews)` : '';
+
+ const html = `
+
+
+
+
+

+
+
+
+
${title}
+
+
${where}${dot_spacer}${when}
+
${rating_html}${rating_count}
+
+
+
+ ${description ?
+ `
${__('Description')}
+
${description}
+ ` : __('No description')
+ }
+
+
+
+
+
+ Seller Information
+
+
+

+
+
+
+
+ `;
+
+ this.$wrapper.html(html);
+ }
+}
+
+
+
+function get_item_card_container_html(items, title) {
+ const html = (items || []).map(item => get_item_card_html(item)).join('');
+
+ return `
+
+
+ ${title}
+
+ ${html}
+
+ `;
+}
+
+function get_item_card_html(item) {
+ const item_name = item.item_name || item.name;
+ const title = strip_html(item_name);
+
+ const img_url = item.image;
+ const company_name = item.company_name;
+ const route = `marketplace/item/${item.hub_item_code}`;
+
+ let subtitle = [comment_when(item.creation)];
+ const rating = get_rating(item);
+ if (rating > 0) {
+ subtitle.push(rating + `
`)
+ }
+ subtitle.push(company_name);
+
+ let dot_spacer = '
· ';
+ subtitle = subtitle.join(dot_spacer);
+
+ const item_html = `
+
+
+
+
+

+
+
+
+
+ `;
+
+ return item_html;
+}
+
+function get_rating(item) {
+ const review_length = (item.reviews || []).length;
+ return review_length
+ ? item.reviews
+ .map(r => r.rating)
+ .reduce((a, b) => a + b, 0) / review_length
+ : 0;
+}
+
+function get_rating_html(item) {
+ const rating = get_rating(item);
+ let rating_html = ``;
+ for (var i = 0; i < 5; i++) {
+ let star_class = 'fa-star';
+ if (i >= rating) star_class = 'fa-star-o';
+ rating_html += `
`;
+ }
+ return rating_html;
+}
+
erpnext.hub.HubListing = class HubListing extends frappe.views.BaseList {
setup_defaults() {
super.setup_defaults();
@@ -40,7 +439,7 @@ erpnext.hub.HubListing = class HubListing extends frappe.views.BaseList {
get_meta() {
return new Promise(resolve =>
- frappe.call('erpnext.hub_node.get_meta', {doctype: this.doctype}, resolve));
+ frappe.call('erpnext.hub_node.get_meta', { doctype: this.doctype }, resolve));
}
set_breadcrumbs() { }
@@ -83,7 +482,7 @@ erpnext.hub.HubListing = class HubListing extends frappe.views.BaseList {
}
setup_view() {
- if(frappe.route_options){
+ if (frappe.route_options) {
const filters = [];
for (let field in frappe.route_options) {
var value = frappe.route_options[field];
@@ -146,9 +545,9 @@ erpnext.hub.HubListing = class HubListing extends frappe.views.BaseList {
{{ _("Payment Cancelled") }}