diff --git a/erpnext/e_commerce/product_grid.js b/erpnext/e_commerce/product_grid.js
new file mode 100644
index 00000000000..638f01701b7
--- /dev/null
+++ b/erpnext/e_commerce/product_grid.js
@@ -0,0 +1,148 @@
+erpnext.ProductGrid = class {
+ /* Options:
+ - items: Items
+ - settings: E Commerce Settings
+ - products_section: Products Wrapper
+ - preference: If preference is not grid view, render but hide
+ */
+ constructor(options) {
+ Object.assign(this, options);
+
+ if (this.preference !== "Grid View") {
+ this.products_section.addClass("hidden");
+ }
+
+ this.make();
+ }
+
+ make() {
+ let me = this;
+ let html = ``;
+
+ this.items.forEach(item => {
+ let title = item.web_item_name || item.item_name || item.item_code || "";
+ title = title.length > 50 ? title.substr(0, 50) + "..." : title;
+
+ html += `
`;
+ html += me.get_image_html(item, title);
+ html += me.get_card_body_html(item, title, me.settings);
+ html += `
`;
+ })
+
+ let $product_wrapper = this.products_section;
+ $product_wrapper.append(html);
+ }
+
+ get_image_html(item, title) {
+ let image = item.website_image || item.image;
+
+ if(image) {
+ return `
+
+ `;
+ } else {
+ return `
+
+
+ ${ frappe.get_abbr(title) }
+
+
+ `;
+ }
+ }
+
+ get_card_body_html(item, title, settings) {
+ let body_html = `
+
+
+ `;
+ body_html += this.get_title_with_indicator(item, title);
+
+ if (!item.has_variants && settings.enable_wishlist) {
+ body_html += this.get_wishlist_icon(item);
+ }
+
+ body_html += `
`; // close div on line 50
+ body_html += `
${ item.item_group || '' }
`;
+
+ if (item.formatted_price) {
+ body_html += this.get_price_html(item);
+ }
+
+ body_html += this.get_primary_button(item, settings);
+ body_html += `
`; // close div on line 49
+
+ return body_html;
+ }
+
+ get_title_with_indicator(item, title, settings) {
+ let title_html = `
+
+
+ ${ title || '' }
+ `;
+ if (item.in_stock) {
+ title_html += ` `;
+ }
+ title_html += `
`;
+ return title_html
+ }
+
+ get_wishlist_icon(item) {
+ let icon_class = item.wished ? "wished" : "not-wished";
+ return `
+
+
+
+
+
+ `;
+ }
+
+ get_price_html(item) {
+ let price_html = `
+
+ ${ item.formatted_price || '' }
+ `;
+
+ if (item.formatted_mrp) {
+ price_html += `
+
+ ${ item.formatted_mrp }
+
+
+ ${ item.discount } OFF
+
+ `;
+ }
+ price_html += `
`;
+ return price_html;
+ }
+
+ get_primary_button(item, settings) {
+ if (item.has_variants) {
+ return `
+
+
+ ${ __('Explore') }
+
+
+ `;
+ } else if (settings.enabled && (settings.allow_items_not_in_stock || item.in_stock !== "red")) {
+ return `
+
+ ${ __('Add to Cart') }
+
+ `;
+ }
+ }
+}
\ No newline at end of file
diff --git a/erpnext/e_commerce/product_list.js b/erpnext/e_commerce/product_list.js
new file mode 100644
index 00000000000..e693f1e24ca
--- /dev/null
+++ b/erpnext/e_commerce/product_list.js
@@ -0,0 +1,158 @@
+erpnext.ProductList = class {
+ /* Options:
+ - items: Items
+ - settings: E Commerce Settings
+ - products_section: Products Wrapper
+ - preference: If preference is not list view, render but hide
+ */
+ constructor(options) {
+ Object.assign(this, options);
+
+ if (this.preference !== "List View") {
+ this.products_section.addClass("hidden");
+ }
+
+ this.make();
+ }
+
+ make() {
+ let me = this;
+ let html = ` `;
+
+ this.items.forEach(item => {
+ let title = item.web_item_name || item.item_name || item.item_code || "";
+ title = title.length > 200 ? title.substr(0, 200) + "..." : title;
+
+ html += ``;
+ html += me.get_image_html(item, title);
+ html += me.get_row_body_html(item, title, me.settings);
+ html += `
`;
+ })
+
+ let $product_wrapper = this.products_section;
+ $product_wrapper.append(html);
+ }
+
+ get_image_html(item, title) {
+ let image = item.website_image || item.image;
+
+ if(image) {
+ return `
+
+
+
+
+
+ `;
+ } else {
+ return `
+
+
+ ${ frappe.get_abbr(title) }
+
+
+ `;
+ }
+ }
+
+ get_row_body_html(item, title, settings) {
+ let body_html = ``;
+ body_html += this.get_title_html(item, title, settings);
+ body_html += this.get_item_details(item, settings);
+ body_html += `
`;
+ return body_html;
+ }
+
+ get_title_html(item, title, settings) {
+ let title_html = ``;
+ title_html += `
+
+
+ ${ title }
+
+ `;
+
+ if (item.in_stock) {
+ title_html += `
`;
+ }
+ title_html += `
`;
+
+ if (settings.enable_wishlist || settings.enabled) {
+ title_html += `
`;
+ if (!item.has_variants && settings.enable_wishlist) {
+ title_html += this.get_wishlist_icon(item);
+ }
+ title_html += this.get_primary_button(item, settings);
+ title_html += `
`;
+ }
+ title_html += `
`;
+
+ return title_html;
+ }
+
+ get_item_details(item, settings) {
+ let details = `
+
+ Item Code : ${ item.item_code }
+
+
+ ${ item.description || '' }
+
+
+ ${ item.formatted_price || '' }
+ `;
+
+ if(item.formatted_mrp) {
+ details += `
+
+ ${ item.formatted_mrp }
+
+
+ ${ item.discount } OFF
+
+ `;
+ }
+ details += `
`;
+
+ return details;
+ }
+
+ get_wishlist_icon(item) {
+ let icon_class = item.wished ? "wished" : "not-wished";
+
+ return `
+
+
+
+
+
+ `;
+ }
+
+ get_primary_button(item, settings) {
+ if (item.has_variants) {
+ return `
+
+
+ ${ __('Explore') }
+
+
+ `;
+ } else if (settings.enabled && (settings.allow_items_not_in_stock || item.in_stock !== "red")) {
+ return `
+
+ ${ __('Add to Cart') }
+
+ `;
+ }
+ }
+
+}
diff --git a/erpnext/e_commerce/product_view.js b/erpnext/e_commerce/product_view.js
index 660db660215..923bdb12720 100644
--- a/erpnext/e_commerce/product_view.js
+++ b/erpnext/e_commerce/product_view.js
@@ -1,80 +1,56 @@
erpnext.ProductView = class {
- /* Options: View Type */
+ /* Options:
+ - View Type
+ - Products Section Wrapper,
+ - Item Group: If its an Item Group page
+ */
constructor(options) {
Object.assign(this, options);
- this.render_view_toggler();
+ this.preference = "List View";
+
+ this.products_section.empty();
+ this.prepare_view_toggler();
this.get_item_filter_data();
- this.render_list_view();
- this.render_grid_view();
}
- render_view_toggler() {
- ["btn-list-view", "btn-grid-view"].forEach(view => {
- let icon = view === "btn-list-view" ? "list" : "image-view";
- this.products_section.append(`
-
-
-
-
-
-
-
-
-
`);
- });
-
- $("#list").click(function() {
- let $btn = $(this);
- $btn.removeClass('btn-primary');
- $btn.addClass('btn-primary');
- $(".btn-grid-view").removeClass('btn-primary');
- })
-
- $("#image-view").click(function() {
- let $btn = $(this);
- $btn.removeClass('btn-primary');
- $btn.addClass('btn-primary');
- $(".btn-list-view").removeClass('btn-primary');
- });
-
- this.products_area = this.products_section.append(`
-
-
- `);
+ prepare_view_toggler() {
+ if(!$("#list").length || !$("#image-view").length) {
+ this.render_view_toggler();
+ this.bind_view_toggler_actions();
+ this.set_view_state();
+ }
}
get_item_filter_data() {
- // Get Items and Discount Filters to render
+ // Get and render all Items related components
let me = this;
- const filters = frappe.utils.get_query_params();
- let {field_filters, attribute_filters} = filters;
-
- field_filters = field_filters ? JSON.parse(field_filters) : {};
- attribute_filters = attribute_filters ? JSON.parse(attribute_filters) : {};
+ let args = this.get_query_filters();
+ $('#list').prop('disabled', true);
+ $('#image-view').prop('disabled', true);
frappe.call({
method: 'erpnext.www.all-products.index.get_product_filter_data',
- args: {
- field_filters: field_filters,
- attribute_filters: attribute_filters,
- item_group: me.item_group
- },
+ args: args,
callback: function(result) {
- if (!result.exc) {
+ if (!result.exc && result) {
me.render_filters(result.message[1]);
- // Append pre-rendered products
- // TODO: get products as is and style via js
- me.products = result.message;
- $("#products-area").append(result.message[0]);
+ if (me.item_group) {
+ me.render_item_sub_categories(result.message[3]);
+ }
+ // Render views
+ me.render_list_view(result.message[0], result.message[2]);
+ me.render_grid_view(result.message[0], result.message[2]);
+ me.products = result.message[0];
+ // Bottom paging
+ me.add_paging_section(result.message[2]);
} else {
- $("#products-area").append(`
-
- ${__('No products found')}
-
`);
-
+ me.render_no_products_section();
}
+
+ $('#list').prop('disabled', false);
+ $('#image-view').prop('disabled', false);
}
});
}
@@ -83,11 +59,159 @@ erpnext.ProductView = class {
this.get_discount_filter_html(filter_data.discount_filters);
}
+ render_grid_view(items, settings) {
+ // loop over data and add grid html to it
+ let me = this;
+ this.prepare_product_area_wrapper("grid");
+
+ frappe.require('assets/js/e-commerce.min.js', function() {
+ new erpnext.ProductGrid({
+ items: items,
+ products_section: $("#products-grid-area"),
+ settings: settings,
+ preference: me.preference
+ });
+ });
+ }
+
+ render_list_view(items, settings) {
+ let me = this;
+ this.prepare_product_area_wrapper("list");
+
+ frappe.require('assets/js/e-commerce.min.js', function() {
+ new erpnext.ProductList({
+ items: items,
+ products_section: $("#products-list-area"),
+ settings: settings,
+ preference: me.preference
+ });
+ });
+ }
+
+ prepare_product_area_wrapper(view) {
+ let left_margin = view == "list" ? "ml-2" : "";
+ let top_margin = view == "list" ? "mt-8" : "mt-4";
+ return this.products_section.append(`
+
+
+ `);
+ }
+
+ get_query_filters() {
+ const filters = frappe.utils.get_query_params();
+ let {field_filters, attribute_filters} = filters;
+
+ field_filters = field_filters ? JSON.parse(field_filters) : {};
+ attribute_filters = attribute_filters ? JSON.parse(attribute_filters) : {};
+
+ return {
+ field_filters: field_filters,
+ attribute_filters: attribute_filters,
+ item_group: this.item_group,
+ start: filters.start || null
+ }
+ }
+
+ add_paging_section(settings) {
+ $(".product-paging-area").remove();
+
+ if(this.products) {
+ let paging_html = `
+
+
+
+
+ `;
+ let query_params = frappe.utils.get_query_params();
+ let start = query_params.start ? cint(JSON.parse(query_params.start)) : 0;
+ let page_length = settings.products_per_page || 0;
+
+ if(start > 0) {
+ paging_html += `
+
+ ${ __("Prev") }
+ `;
+ }
+ if(this.products.length > page_length || this.products.length == page_length) {
+ paging_html += `
+
+ ${ __("Next") }
+
+ `;
+ }
+ paging_html += `
`;
+
+ $(".page_content").append(paging_html);
+ this.bind_paging_action();
+ }
+ }
+
+ render_view_toggler() {
+ ["btn-list-view", "btn-grid-view"].forEach(view => {
+ let icon = view === "btn-list-view" ? "list" : "image-view";
+ this.products_section.append(`
+
+
+
+
+
+
+
+
+
`);
+ });
+ }
+
+ bind_view_toggler_actions() {
+ $("#list").click(function() {
+ let $btn = $(this);
+ $btn.removeClass('btn-primary');
+ $btn.addClass('btn-primary');
+ $(".btn-grid-view").removeClass('btn-primary');
+
+ $("#products-grid-area").addClass("hidden");
+ $("#products-list-area").removeClass("hidden");
+ })
+
+ $("#image-view").click(function() {
+ let $btn = $(this);
+ $btn.removeClass('btn-primary');
+ $btn.addClass('btn-primary');
+ $(".btn-list-view").removeClass('btn-primary');
+
+ $("#products-list-area").addClass("hidden");
+ $("#products-grid-area").removeClass("hidden");
+ });
+ }
+
+ set_view_state() {
+ if (this.preference === "List View") {
+ $("#list").addClass('btn-primary');
+ $("#image-view").removeClass('btn-primary');
+ } else {
+ $("#image-view").addClass('btn-primary');
+ $("#list").removeClass('btn-primary');
+ }
+ }
+
+ bind_paging_action() {
+ $('.btn-prev, .btn-next').click((e) => {
+ const $btn = $(e.target);
+ $btn.prop('disabled', true);
+ const start = $btn.data('start');
+ let query_params = frappe.utils.get_query_params();
+ query_params.start = start;
+ let path = window.location.pathname + '?' + frappe.utils.get_url_from_dict(query_params);
+ window.location.href = path;
+ });
+ }
+
get_discount_filter_html(filter_data) {
+ $("#discount-filters").remove();
if (filter_data) {
$("#product-filters").append(`
-
${__("Discounts")}
+
${ __("Discounts") }
`);
@@ -95,13 +219,13 @@ erpnext.ProductView = class {
filter_data.forEach(filter => {
html += `
-
+
-
- ${filter[1]}
+
+ ${ filter[1] }
@@ -113,12 +237,35 @@ erpnext.ProductView = class {
}
}
- render_list_view() {
- // loop over data and add list html to it
+ render_no_products_section() {
+ $("#products-area").append(`
+
+ ${ __('No products found') }
+
+ `);
}
- render_grid_view() {
- // loop over data and add grid html to it
- }
+ render_item_sub_categories(categories) {
+ if(categories) {
+ let sub_group_html = `
+
+
${ __('Sub Categories') }
+
+ `;
+
+ $("#product-listing").prepend(sub_group_html);
+ }
+ }
}
\ No newline at end of file
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 0181d463097..69db1857dcd 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -69,6 +69,8 @@
"public/js/bank_reconciliation_tool/dialog_manager.js"
],
"js/e-commerce.min.js": [
- "e_commerce/product_view.js"
+ "e_commerce/product_view.js",
+ "e_commerce/product_grid.js",
+ "e_commerce/product_list.js"
]
}
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 3482ac37871..95e8636b8ef 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -229,11 +229,6 @@ body.product-page {
color: var(--text-color);
}
- .product-code {
- color: var(--text-muted);
- font-size: 13px;
- }
-
.product-description {
font-size: 13px;
color: var(--gray-800);
@@ -302,6 +297,11 @@ body.product-page {
}
}
+.product-code {
+ color: var(--text-muted);
+ font-size: 13px;
+}
+
.item-configurator-dialog {
.modal-header {
padding: var(--padding-md) var(--padding-xl);
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 1788f92e68c..fd22d94b67d 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -81,7 +81,6 @@ class ItemGroup(NestedSet, WebsiteGenerator):
"title": self.name
})
- context.sub_categories = get_child_groups(self.name)
if self.slideshow:
values = {
'show_indicators': 1,
diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html
index 9f3cf85d46c..72c5d502add 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -35,24 +35,9 @@
- {% if sub_categories %}
-
-
{{ _('Sub Categories') }}
-
-
- {% endif %}
-
-
+
-
-
- {% if frappe.form_dict.start|int > 0 %}
- {{ _("Prev") }}
- {% endif %}
- {% if items|length >= page_length %}
- {{ _("Next") }}
- {% endif %}
-
-
{% endblock %}
\ No newline at end of file
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index aa6e9f35e96..e8d527ee3cd 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -59,7 +59,7 @@
{% endmacro %}
-{%- macro item_card(item, settings=None, is_featured=False, is_full_width=False, align="Left") -%}
+{%- macro item_card(item, is_featured=False, is_full_width=False, align="Left") -%}
{%- set align_items_class = resolve_class({
'align-items-end': align == 'Right',
'align-items-center': align == 'Center',
@@ -80,12 +80,12 @@
- {{ item_card_body(title, settings, description, item, is_featured, align) }}
+ {{ item_card_body(title, description, item, is_featured, align) }}
{% else %}
- {{ item_card_body(title, settings, description, item, is_featured, align) }}
+ {{ item_card_body(title, description, item, is_featured, align) }}
{% endif %}
@@ -106,13 +106,13 @@
{% endif %}
- {{ item_card_body(title, settings, description, item, is_featured, align) }}
+ {{ item_card_body(title, description, item, is_featured, align) }}
{% endif %}
{%- endmacro -%}
-{%- macro item_card_body(title, settings, description, item, is_featured, align) -%}
+{%- macro item_card_body(title, description, item, is_featured, align) -%}
{%- set align_class = resolve_class({
'text-right': align == 'Right',
'text-center': align == 'Center' and not is_featured,
@@ -128,52 +128,12 @@
{% endif %}
- {% if not item.has_variants and settings.enable_wishlist %}
-
-
- {%- set icon_class = "wished" if item.wished else "not-wished"-%}
-
-
-
- {% endif %}
{% if is_featured %}
{{ item.formatted_price or '' }}
{{ description or '' }}
{% else %}
{{ item.item_group or '' }}
-
- {% if item.formatted_price %}
-
- {{ item.formatted_price or '' }}
-
- {% if item.get("formatted_mrp") %}
-
- {{ item.formatted_mrp }}
-
-
- {{ item.discount }} OFF
-
- {% endif %}
-
-
- {% endif %}
-
- {% if item.has_variants %}
-
-
- {{ _('Explore') }}
-
-
- {% elif settings.enabled and (settings.allow_items_not_in_stock or item.in_stock != "red")%}
-
- {{ _('Add to Cart') }}
-
- {% endif %}
{% endif %}
{%- endmacro -%}
diff --git a/erpnext/templates/includes/products_as_list.html b/erpnext/templates/includes/products_as_list.html
index 976d6147bc3..a9369bb8def 100644
--- a/erpnext/templates/includes/products_as_list.html
+++ b/erpnext/templates/includes/products_as_list.html
@@ -1,5 +1,5 @@
{% from "erpnext/templates/includes/macros.html" import item_card, item_card_body, product_image_square %}
-
+
diff --git a/erpnext/www/all-products/index.html b/erpnext/www/all-products/index.html
index fa44101f9ec..bf84fd51697 100644
--- a/erpnext/www/all-products/index.html
+++ b/erpnext/www/all-products/index.html
@@ -32,8 +32,8 @@
-->
-
-
-
-
-