feat: Product View toggling

- Added fully functional list and grid view toggling
- Added ProductGrid and ProductList controllers
- Moved html snippets, rendered via JS now
- Item Group page also rendered via common controller
- Paging section rendered via JS
- Minor style changes
diff --git a/erpnext/e_commerce/product_grid.js b/erpnext/e_commerce/product_grid.js
new file mode 100644
index 0000000..638f017
--- /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 += `<div class="col-sm-4 item-card"><div class="card text-left">`;
+			html += me.get_image_html(item, title);
+			html += me.get_card_body_html(item, title, me.settings);
+			html += `</div></div>`;
+		})
+
+		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 `
+				<div class="card-img-container">
+					<a href="/${ item.route || '#' }" style="text-decoration: none;">
+						<img class="card-img" src="${ image }" alt="${ title }">
+					</a>
+				</div>
+			`;
+		} else {
+			return `
+				<a href="/${ item.route || '#' }" style="text-decoration: none;">
+					<div class="card-img-top no-image">
+						${ frappe.get_abbr(title) }
+					</div>
+				</a>
+			`;
+		}
+	}
+
+	get_card_body_html(item, title, settings) {
+		let body_html = `
+			<div class="card-body text-left" style="width:100%">
+				<div style="margin-top: 16px; display: flex;">
+		`;
+		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 += `</div>`; // close div on line 50
+		body_html += `<div class="product-category">${ item.item_group || '' }</div>`;
+
+		if (item.formatted_price) {
+			body_html += this.get_price_html(item);
+		}
+
+		body_html += this.get_primary_button(item, settings);
+		body_html += `</div>`; // close div on line 49
+
+		return body_html;
+	}
+
+	get_title_with_indicator(item, title, settings) {
+		let title_html = `
+			<a href="/${ item.route || '#' }">
+				<div class="product-title">
+					${ title || '' }
+		`;
+		if (item.in_stock) {
+			title_html += `<span class="indicator ${ item.in_stock } card-indicator"></span>`;
+		}
+		title_html += `</div></a>`;
+		return title_html
+	}
+
+	get_wishlist_icon(item) {
+		let icon_class = item.wished ? "wished" : "not-wished";
+		return `
+			<div class="like-action"
+				data-item-code="${ item.item_code }"
+				data-price="${ item.price || '' }"
+				data-formatted-price="${ item.formatted_price || '' }">
+				<svg class="icon sm">
+					<use class="${ icon_class } wish-icon" href="#icon-heart"></use>
+				</svg>
+			</div>
+		`;
+	}
+
+	get_price_html(item) {
+		let price_html = `
+			<div class="product-price">
+				${ item.formatted_price || '' }
+		`;
+
+		if (item.formatted_mrp) {
+			price_html += `
+				<small class="ml-1 text-muted">
+					<s>${ item.formatted_mrp }</s>
+				</small>
+				<small class="ml-1" style="color: #F47A7A; font-weight: 500;">
+					${ item.discount } OFF
+				</small>
+			`;
+		}
+		price_html += `</div>`;
+		return price_html;
+	}
+
+	get_primary_button(item, settings) {
+		if (item.has_variants) {
+			return `
+				<a href="/${ item.route || '#' }">
+					<div class="btn btn-sm btn-explore-variants w-100 mt-4">
+						${ __('Explore') }
+					</div>
+				</a>
+			`;
+		} else if (settings.enabled && (settings.allow_items_not_in_stock || item.in_stock !== "red")) {
+			return `
+				<div id="${ item.name }" class="btn
+					btn-sm btn-add-to-cart-list not-added w-100 mt-4"
+					data-item-code="${ item.item_code }">
+					${ __('Add to Cart') }
+				</div>
+			`;
+		}
+	}
+}
\ 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 0000000..e693f1e
--- /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 = `<br><br>`;
+
+		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 += `<div class='row mt-6 w-100' style="border-bottom: 1px solid var(--table-border-color); padding-bottom: 1rem;">`;
+			html += me.get_image_html(item, title);
+			html += me.get_row_body_html(item, title, me.settings);
+			html += `</div>`;
+		})
+
+		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 `
+				<div class="col-2 border text-center rounded product-image" style="overflow: hidden; max-height: 200px;">
+					<a class="product-link product-list-link" href="/${ item.route || '#' }">
+						<img itemprop="image" class="website-image h-100 w-100" alt="${ title }"
+							src="${ image }">
+					</a>
+				</div>
+			`;
+		} else {
+			return `
+				<a href="/${ item.route || '#' }" style="text-decoration: none;">
+					<div class="card-img-top no-image">
+						${ frappe.get_abbr(title) }
+					</div>
+				</a>
+			`;
+		}
+	}
+
+	get_row_body_html(item, title, settings) {
+		let body_html = `<div class='col-9 text-left'>`;
+		body_html += this.get_title_html(item, title, settings);
+		body_html += this.get_item_details(item, settings);
+		body_html += `</div>`;
+		return body_html;
+	}
+
+	get_title_html(item, title, settings) {
+		let title_html = `<div style="display: flex; margin-left: -15px;">`;
+		title_html += `
+			<div class="col-8" style="margin-right: -15px;">
+				<a class="" href="/${ item.route || '#' }"
+					style="color: var(--gray-800); font-weight: 500;">
+					${ title }
+				</a>
+		`;
+
+		if (item.in_stock) {
+			title_html += `<span class="indicator ${ item.in_stock } card-indicator"></span>`;
+		}
+		title_html += `</div>`;
+
+		if (settings.enable_wishlist || settings.enabled) {
+			title_html += `<div class="col-4" style="display:flex">`;
+			if (!item.has_variants && settings.enable_wishlist) {
+				title_html += this.get_wishlist_icon(item);
+			}
+			title_html += this.get_primary_button(item, settings);
+			title_html += `</div>`;
+		}
+		title_html += `</div>`;
+
+		return title_html;
+	}
+
+	get_item_details(item, settings) {
+		let details = `
+			<p class="product-code">
+				Item Code : ${ item.item_code }
+			</p>
+			<div class="text-muted mt-2">
+				${ item.description || '' }
+			</div>
+			<div class="product-price">
+				${ item.formatted_price || '' }
+		`;
+
+		if(item.formatted_mrp) {
+			details += `
+				<small class="ml-1 text-muted">
+					<s>${ item.formatted_mrp }</s>
+				</small>
+				<small class="ml-1" style="color: #F47A7A; font-weight: 500;">
+					${ item.discount } OFF
+				</small>
+			`;
+		}
+		details += `</div>`;
+
+		return details;
+	}
+
+	get_wishlist_icon(item) {
+		let icon_class = item.wished ? "wished" : "not-wished";
+
+		return `
+			<div class="like-action mr-4"
+			data-item-code="${ item.item_code }"
+			data-price="${ item.price || '' }"
+			data-formatted-price="${ item.formatted_price || '' }">
+				<svg class="icon sm">
+					<use class="${ icon_class } wish-icon" href="#icon-heart"></use>
+				</svg>
+			</div>
+		`;
+	}
+
+	get_primary_button(item, settings) {
+		if (item.has_variants) {
+			return `
+				<a href="/${ item.route || '#' }">
+					<div class="btn btn-sm btn-explore-variants" style="margin-bottom: 0; margin-top: 4px; max-height: 30px;">
+						${ __('Explore') }
+					</div>
+				</a>
+			`;
+		} else if (settings.enabled && (settings.allow_items_not_in_stock || item.in_stock !== "red")) {
+			return `
+				<div id="${ item.name }" class="btn
+					btn-sm btn-add-to-cart-list not-added"
+					data-item-code="${ item.item_code }"
+					style="margin-bottom: 0; margin-top: 0px; max-height: 30px;">
+					${ __('Add to Cart') }
+				</div>
+			`;
+		}
+	}
+
+}
diff --git a/erpnext/e_commerce/product_view.js b/erpnext/e_commerce/product_view.js
index 660db66..923bdb1 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(`
-			<div class="form-group mb-0" id="toggle-view">
-				<button id="${icon}" class="btn ${view} mr-2">
-					<span>
-						<svg class="icon icon-md">
-							<use href="#icon-${icon}"></use>
-						</svg>
-					</span>
-				</button>
-			</div>`);
-		});
-
-		$("#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(`
-			<br><br>
-			<div id="products-area" class="row products-list mt-4"></div>
-		`);
+	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;
+		let args = this.get_query_filters();
 
-		field_filters = field_filters ? JSON.parse(field_filters) : {};
-		attribute_filters = attribute_filters ? JSON.parse(attribute_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(`
-						<div class="d-flex justify-content-center p-3 text-muted">
-							${__('No products found')}
-						</div>`);
-
+					me.render_no_products_section();
 				}
+
+				$('#list').prop('disabled', false);
+				$('#image-view').prop('disabled', false);
 			}
 		});
 	}
@@ -83,11 +59,159 @@
 		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(`
+			<br>
+			<div id="products-${view}-area" class="row products-list ${ top_margin } ${ left_margin }"></div>
+		`);
+	}
+
+	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 = `
+				<div class="row product-paging-area mt-5">
+					<div class="col-3">
+					</div>
+					<div class="col-9 text-right">
+			`;
+			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 += `
+					<button class="btn btn-default btn-prev" data-start="${ start - page_length }" style="float: left">
+						${ __("Prev") }
+					</button>`;
+			}
+			if(this.products.length > page_length || this.products.length == page_length) {
+				paging_html += `
+					<button class="btn btn-default btn-next" data-start="${ start + page_length }">
+						${ __("Next") }
+					</button>
+				`;
+			}
+			paging_html += `</div></div>`;
+
+			$(".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(`
+			<div class="form-group mb-0" id="toggle-view">
+				<button id="${ icon }" class="btn ${ view } mr-2">
+					<span>
+						<svg class="icon icon-md">
+							<use href="#icon-${ icon }"></use>
+						</svg>
+					</span>
+				</button>
+			</div>`);
+		});
+	}
+
+	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(`
 				<div id="discount-filters" class="mb-4 filter-block pb-5">
-					<div class="filter-label mb-3">${__("Discounts")}</div>
+					<div class="filter-label mb-3">${ __("Discounts") }</div>
 				</div>
 			`);
 
@@ -95,13 +219,13 @@
 			filter_data.forEach(filter => {
 				html += `
 					<div class="checkbox">
-						<label data-value="${filter[0]}">
+						<label data-value="${ filter[0] }">
 							<input type="radio" class="product-filter discount-filter"
-								name="discount" id="${filter[0]}"
-								data-filter-name="discount" data-filter-value="${filter[0]}"
+								name="discount" id="${ filter[0] }"
+								data-filter-name="discount" data-filter-value="${ filter[0] }"
 							>
-								<span class="label-area" for="${filter[0]}">
-									${filter[1]}
+								<span class="label-area" for="${ filter[0] }">
+									${ filter[1] }
 								</span>
 						</label>
 					</div>
@@ -113,12 +237,35 @@
 		}
 	}
 
-	render_list_view() {
-		// loop over data and add list html to it
+	render_no_products_section() {
+		$("#products-area").append(`
+			<div class="d-flex justify-content-center p-3 text-muted">
+				${ __('No products found') }
+			</div>
+		`);
 	}
 
-	render_grid_view() {
-		// loop over data and add grid html to it
-	}
+	render_item_sub_categories(categories) {
+		if(categories) {
+			let sub_group_html = `
+				<div class="sub-category-container">
+					<div class="heading"> ${ __('Sub Categories') } </div>
+				</div>
+				<div class="sub-category-container scroll-categories">
+			`;
 
+			categories.forEach(category => {
+				sub_group_html += `
+					<a href="${ category.route || '#' }" style="text-decoration: none;">
+						<div class="category-pill">
+							${ category.name }
+						</div>
+					</a>
+				`;
+			})
+			sub_group_html += `</div>`;
+
+			$("#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 aa8ef6d..51082bd 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -68,6 +68,8 @@
 		"public/js/hierarchy_chart/hierarchy_chart_mobile.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 acd97ad..33bd88f 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -229,11 +229,6 @@
 		color: var(--text-color);
 	}
 
-	.product-code {
-		color: var(--text-muted);
-		font-size: 13px;
-	}
-
 	.product-description {
 		font-size: 13px;
 		color: var(--gray-800);
@@ -303,6 +298,11 @@
 	}
 }
 
+.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 1823680..d8ae763 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -79,7 +79,6 @@
 			"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 3ae9a89..20ad7fb 100644
--- a/erpnext/templates/generators/item_group.html
+++ b/erpnext/templates/generators/item_group.html
@@ -35,24 +35,9 @@
 	</div>
 	<div class="row">
 		<div id="product-listing" class="col-12 order-2 col-md-9 order-md-2 item-card-group-section">
-			{% if sub_categories %}
-			<div class="sub-category-container">
-				<div class="heading"> {{ _('Sub Categories') }} </div>
-			</div>
-			<div class="sub-category-container scroll-categories">
-				{% for row in sub_categories%}
-				<a href="{{ row.route or '#' }}" style="text-decoration: none;">
-					<div class="category-pill">
-						{{ row.name }}
-					</div>
-				</a>
-				{% endfor %}
-			</div>
-			{% endif %}
-
 			<!-- Products Rendered in all-products/index.js-->
-
 		</div>
+
 		<div class="col-12 order-1 col-md-3 order-md-1">
 			<div class="collapse d-md-block mr-4 filters-section" id="product-filters">
 				<div class="d-flex justify-content-between align-items-center mb-5 title-section">
@@ -87,23 +72,6 @@
 			</script>
 		</div>
 	</div>
-	<div class="row mt-6">
-		<div class="col-3">
-		</div>
-		<div class="col-9">
-			{% if frappe.form_dict.start|int > 0 %}
-			<button class="btn btn-outline-secondary btn-prev" data-start="{{ frappe.form_dict.start|int - page_length }}">
-				{{ _("Prev") }}
-			</button>
-			{% endif %}
-			{% if items|length >= page_length %}
-			<button class="btn btn-outline-secondary btn-next" data-start="{{ frappe.form_dict.start|int + page_length }}"
-				style="float: right;">
-				{{ _("Next") }}
-			</button>
-			{% endif %}
-		</div>
-	</div>
 </div>
 
 <script>
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index d6d6629..aec23a2 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 @@
 				<img class="card-img" src="{{ image }}" alt="{{ title }}">
 			</div>
 			<div class="col-md-6">
-				{{ item_card_body(title, settings, description, item, is_featured, align) }}
+				{{ item_card_body(title, description, item, is_featured, align) }}
 			</div>
 		</div>
 		{% else %}
 			<div class="col-md-12">
-				{{ item_card_body(title, settings, description, item, is_featured, align) }}
+				{{ item_card_body(title, description, item, is_featured, align) }}
 			</div>
 		{% endif %}
 	</div>
@@ -106,13 +106,13 @@
 			</div>
 		</a>
 		{% endif %}
-		{{ item_card_body(title, settings, description, item, is_featured, align) }}
+		{{ item_card_body(title, description, item, is_featured, align) }}
 	</div>
 </div>
 {% 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 %}
 			</div>
 		</a>
-		{% if not item.has_variants and settings.enable_wishlist %}
-			<div class="like-action"
-				data-item-code="{{ item.item_code }}"
-				data-price="{{ item.price }}"
-				data-formatted-price="{{ item.get('formatted_price') }}">
-				<svg class="icon sm">
-					{%- set icon_class = "wished" if item.wished else "not-wished"-%}
-					<use class="{{ icon_class }} wish-icon" href="#icon-heart"></use>
-				</svg>
-			</div>
-		{% endif %}
 	</div>
 	{% if is_featured %}
 		<div class="product-price">{{ item.formatted_price or '' }}</div>
 		<div class="product-description ellipsis">{{ description or '' }}</div>
 	{% else %}
 		<div class="product-category">{{ item.item_group or '' }}</div>
-
-		{% if item.formatted_price %}
-			<div class="product-price">
-				{{ item.formatted_price or '' }}
-
-				{% if item.get("formatted_mrp") %}
-					<small class="ml-1 text-muted">
-						<s>{{ item.formatted_mrp }}</s>
-					</small>
-					<small class="ml-1" style="color: #F47A7A; font-weight: 500;">
-						{{ item.discount }} OFF
-					</small>
-				{% endif %}
-
-			</div>
-		{% endif %}
-
-		{% if item.has_variants %}
-			<a href="/{{ item.route or '#' }}">
-				<div class="btn btn-sm btn-explore-variants w-100 mt-4">
-					{{ _('Explore') }}
-				</div>
-			</a>
-		{% elif settings.enabled and (settings.allow_items_not_in_stock or item.in_stock != "red")%}
-			<div id="{{ item.name }}" class="btn btn-sm btn-add-to-cart-list not-added w-100 mt-4"
-				data-item-code="{{ item.item_code }}">
-				{{ _('Add to Cart') }}
-			</div>
-		{% endif %}
 	{% endif %}
 </div>
 {%- endmacro -%}
diff --git a/erpnext/templates/includes/products_as_list.html b/erpnext/templates/includes/products_as_list.html
index 976d614..a9369bb 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 %}
-
+<!-- Used in Product Search -->
 <a class="product-link product-list-link" href="{{ route|abs_url }}">
 	<div class='row'>
 		<div class='col-xs-3 col-sm-2 product-image-wrapper'>
diff --git a/erpnext/www/all-products/index.html b/erpnext/www/all-products/index.html
index ad40796..f89ee65 100644
--- a/erpnext/www/all-products/index.html
+++ b/erpnext/www/all-products/index.html
@@ -32,8 +32,8 @@
 	</div>
 </div> -->
 
-<!-- Items section -->
 <div class="row">
+	<!-- Items section -->
 	<div id="product-listing" class="col-12 order-2 col-md-9 order-md-2 item-card-group-section">
 		<!-- Rendered via JS -->
 	</div>
@@ -82,21 +82,6 @@
 	</div>
 </div>
 
-<!-- TODO -->
-<!-- Paging Section -->
-<!-- <div class="row product-paging-area mt-5">
-	<div class="col-3">
-	</div>
-	<div class="col-9 text-right">
-		{% if frappe.form_dict.start|int > 0 %}
-		<button class="btn btn-default btn-prev" data-start="{{ frappe.form_dict.start|int - page_length }}">{{ _("Prev") }}</button>
-		{% endif %}
-		{% if items|length >= page_length %}
-		<button class="btn btn-default btn-next" data-start="{{ frappe.form_dict.start|int + page_length }}">{{ _("Next") }}</button>
-		{% endif %}
-	</div>
-</div> -->
-
 <script>
 	frappe.ready(() => {
 		$('.btn-prev, .btn-next').click((e) => {
diff --git a/erpnext/www/all-products/index.js b/erpnext/www/all-products/index.js
index 94b4c6f..acf42f2 100644
--- a/erpnext/www/all-products/index.js
+++ b/erpnext/www/all-products/index.js
@@ -1,14 +1,16 @@
 $(() => {
 	class ProductListing {
 		constructor() {
+			let me = this;
 			let is_item_group_page = $(".item-group-content").data("item-group");
-			let item_group = is_item_group_page || null;
+			this.item_group = is_item_group_page || null;
 
-			// Render Products
+			// Render Products and Discount Filters
 			frappe.require('assets/js/e-commerce.min.js', function() {
 				new erpnext.ProductView({
+					view_type: "List",
 					products_section: $('#product-listing'),
-					item_group: item_group
+					item_group: me.item_group
 				});
 			});
 
@@ -19,6 +21,7 @@
 		}
 
 		bind_filters() {
+			let me = this;
 			this.field_filters = {};
 			this.attribute_filters = {};
 
@@ -73,17 +76,14 @@
 				window.history.pushState('filters', '', `${location.pathname}?` + query_string);
 
 				$('.page_content input').prop('disabled', true);
-				this.get_items_with_filters()
-					.then(html => {
-						$('.products-list').html(html);
-					})
-					.then(data => {
-						$('.page_content input').prop('disabled', false);
-						return data;
-					})
-					.catch(() => {
-						$('.page_content input').prop('disabled', false);
+				frappe.require('assets/js/e-commerce.min.js', function() {
+					new erpnext.ProductView({
+						view_type: "List",
+						products_section: $('#product-listing'),
+						item_group: me.item_group
 					});
+					$('.page_content input').prop('disabled', false);
+				});
 			}, 1000));
 		}
 
@@ -133,27 +133,6 @@
 				this.attribute_filters = attribute_filters;
 			}
 		}
-
-		get_items_with_filters() {
-			const { attribute_filters, field_filters } = this;
-			const args = {
-				field_filters: if_key_exists(field_filters),
-				attribute_filters: if_key_exists(attribute_filters)
-			};
-
-			const item_group = $(".item-group-content").data('item-group');
-			if (item_group) {
-				Object.assign(field_filters, { item_group });
-			}
-			return new Promise((resolve, reject) => {
-				frappe.call('erpnext.www.all-products.index.get_products_html_for_website', args)
-					.then(r => {
-						if (r.exc) reject(r.exc);
-						else resolve(r.message);
-					})
-					.fail(reject);
-			});
-		}
 	}
 
 	new ProductListing();
diff --git a/erpnext/www/all-products/index.py b/erpnext/www/all-products/index.py
index 2472dad..a6c39db 100644
--- a/erpnext/www/all-products/index.py
+++ b/erpnext/www/all-products/index.py
@@ -2,6 +2,7 @@
 from frappe.utils import cint
 from erpnext.e_commerce.product_query import ProductQuery
 from erpnext.e_commerce.filters import ProductFiltersBuilder
+from erpnext.setup.doctype.item_group.item_group import get_child_groups
 
 sitemap = 1
 
@@ -24,56 +25,25 @@
 		search = frappe.form_dict.search
 		field_filters = frappe.parse_json(frappe.form_dict.field_filters)
 		attribute_filters = frappe.parse_json(frappe.form_dict.attribute_filters)
-		start = cint(frappe.parse_json(frappe.form_dict.start))
+		start = cint(frappe.parse_json(frappe.form_dict.start)) if frappe.form_dict.start else 0
 		item_group = frappe.form_dict.item_group
 	else:
 		search, attribute_filters, item_group = None, None, None
 		field_filters = {}
 		start = 0
 
+	sub_categories = []
 	if item_group:
 		field_filters['item_group'] = item_group
+		sub_categories = get_child_groups(item_group)
 
 	engine = ProductQuery()
 	items, discounts = engine.query(attribute_filters, field_filters, search_term=search, start=start)
 
-	item_html = []
-	for item in items:
-		item_html.append(frappe.render_template('erpnext/www/all-products/item_row.html', {
-			'item': item,
-			'e_commerce_settings': engine.settings
-		}))
-	html = ''.join(item_html)
-
-	if not items:
-		html = frappe.render_template('erpnext/www/all-products/not_found.html', {})
-
 	# discount filter data
 	filters = {}
 	if discounts:
 		filter_engine = ProductFiltersBuilder()
 		filters["discount_filters"] = filter_engine.get_discount_filters(discounts)
 
-	return html, filters
-
-@frappe.whitelist(allow_guest=True)
-def get_products_html_for_website(field_filters=None, attribute_filters=None):
-	"""Get Products on filter change."""
-	field_filters = frappe.parse_json(field_filters)
-	attribute_filters = frappe.parse_json(attribute_filters)
-
-	engine = ProductQuery()
-	items, discounts = engine.query(attribute_filters, field_filters, search_term=None, start=0)
-
-	item_html = []
-	for item in items:
-		item_html.append(frappe.render_template('erpnext/www/all-products/item_row.html', {
-			'item': item,
-			'e_commerce_settings': engine.settings
-		}))
-	html = ''.join(item_html)
-
-	if not items:
-		html = frappe.render_template('erpnext/www/all-products/not_found.html', {})
-
-	return html
+	return items or [], filters, engine.settings, sub_categories
\ No newline at end of file
diff --git a/erpnext/www/all-products/item_row.html b/erpnext/www/all-products/item_row.html
deleted file mode 100644
index 538ce3b..0000000
--- a/erpnext/www/all-products/item_row.html
+++ /dev/null
@@ -1,4 +0,0 @@
-{% from "erpnext/templates/includes/macros.html" import item_card, item_card_body %}
-
-{{ item_card(item, e_commerce_settings) }}
-