feat: Product Details Tabbed Section and Add to Wishlist in Item Full Page
- Add to Wishlist button next to add to cart
- Beautified Product Specifications table section
- Product Specifications can be optionally in a tabbed section with custom tabs added
- Removed hard coded gray bg to allow custom theme overwrites
- Fixed resizing issues in Item Full Page view
- Cleaned up inline styles and ported to scss
diff --git a/erpnext/templates/generators/item/item.html b/erpnext/templates/generators/item/item.html
index 17f6880..eebfb92 100644
--- a/erpnext/templates/generators/item/item.html
+++ b/erpnext/templates/generators/item/item.html
@@ -9,17 +9,33 @@
{% endblock %}
{% block page_content %}
-<div class="product-container">
+<div class="product-container col-md-12">
{% from "erpnext/templates/includes/macros.html" import product_image %}
<div class="item-content">
<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
+ <!-- Image, Description, Add to Cart -->
<div class="row mb-5">
{% include "templates/generators/item/item_image.html" %}
{% include "templates/generators/item/item_details.html" %}
</div>
- {% include "templates/generators/item/item_specifications.html" %}
+ <!-- Product Specifications Table Section -->
+ {% if show_tabs and tabs %}
+ <div class="category-tabs">
+ <!-- tabs -->
+ {{ web_block(
+ "Section with Tabs",
+ values=tabs,
+ add_container=0,
+ add_top_padding=0,
+ add_bottom_padding=0
+ ) }}
+ </div>
+ {% elif website_specifications %}
+ {% include "templates/generators/item/item_specifications.html"%}
+ {% endif %}
+ <!-- Advanced Custom Website Content -->
{{ doc.website_content or '' }}
</div>
</div>
diff --git a/erpnext/templates/generators/item/item_add_to_cart.html b/erpnext/templates/generators/item/item_add_to_cart.html
index 167c848..c7713c1 100644
--- a/erpnext/templates/generators/item/item_add_to_cart.html
+++ b/erpnext/templates/generators/item/item_add_to_cart.html
@@ -5,6 +5,7 @@
<div class="item-cart row mt-2" data-variant-item-code="{{ item_code }}">
<div class="col-md-12">
+ <!-- Price and Availability -->
{% if cart_settings.show_price and product_info.price %}
<div class="product-price">
{{ product_info.price.formatted_price_sales_uom }}
@@ -30,17 +31,21 @@
{% endif %}
</div>
{% endif %}
+
+ <!-- Add to Cart / View in Cart, Contact Us -->
<div class="mt-5 mb-5">
- {% if product_info.price and (cart_settings.allow_items_not_in_stock or product_info.in_stock) %}
+ <div style="display: flex;" class="mb-4">
+ <!-- Add to Cart -->
+ {% if product_info.price and (cart_settings.allow_items_not_in_stock or product_info.in_stock) %}
<a href="/cart"
- class="btn btn-light btn-view-in-cart {% if not product_info.qty %}hidden{% endif %}"
+ class="btn btn-light btn-view-in-cart hidden mr-2"
role="button"
>
{{ _("View in Cart") }}
</a>
<button
data-item-code="{{item_code}}"
- class="btn btn-primary btn-add-to-cart {% if product_info.qty %}hidden{% endif %} w-100"
+ class="btn btn-primary btn-add-to-cart w-50 mr-2"
>
<span class="mr-2">
<svg class="icon icon-md">
@@ -49,7 +54,37 @@
</span>
{{ _("Add to Cart") }}
</button>
- {% endif %}
+ {% endif %}
+
+ <!-- Add to Wishlist -->
+ <a href="/wishlist"
+ class="btn btn-view-in-wishlist hidden"
+ role="button"
+ >
+ <span class="mr-2">
+ <svg class="icon icon-md">
+ <use href="#icon-heart"></use>
+ </svg>
+ </span>
+ {{ _("View in Wishlist") }}
+ </a>
+
+ {% set price = product_info.get("price") or {} %}
+ <button
+ data-item-code="{{item_code}}"
+ data-price="{{ price.get('price_list_rate') or 0}}"
+ data-formatted-price="{{ price.get('formatted_price') or 0 }}"
+ class="btn btn-add-to-wishlist"
+ >
+ <span class="mr-2">
+ <svg class="icon icon-md">
+ <use href="#icon-heart"></use>
+ </svg>
+ </span>
+ {{ _("Add to Wishlist") }}
+ </button>
+ </div>
+
{% if cart_settings.show_contact_us_button %}
{% include "templates/generators/item/item_inquiry.html" %}
{% endif %}
@@ -60,6 +95,7 @@
<script>
frappe.ready(() => {
$('.page_content').on('click', '.btn-add-to-cart', (e) => {
+ // Bind action on add to cart button
const $btn = $(e.currentTarget);
$btn.prop('disabled', true);
const item_code = $btn.data('item-code');
@@ -74,6 +110,28 @@
}
});
});
+
+ $('.page_content').on('click', '.btn-add-to-wishlist', (e) => {
+ // Bind action on wishlist button
+ const $btn = $(e.currentTarget);
+ $btn.prop('disabled', true);
+
+ let args = {
+ item_code: $btn.data('item-code'),
+ price: $btn.data('price'),
+ formatted_price: $btn.data('formatted-price')
+ };
+ let failure_action = function() {
+ $btn.prop('disabled', false);
+ };
+ let success_action = function() {
+ $btn.prop('disabled', false);
+ erpnext.wishlist.set_wishlist_count();
+ $('.btn-add-to-wishlist, .btn-view-in-wishlist').toggleClass('hidden');
+
+ };
+ erpnext.wishlist.add_remove_from_wishlist("add", args, success_action, failure_action);
+ });
});
</script>
diff --git a/erpnext/templates/generators/item/item_details.html b/erpnext/templates/generators/item/item_details.html
index 3b77585..9559129 100644
--- a/erpnext/templates/generators/item/item_details.html
+++ b/erpnext/templates/generators/item/item_details.html
@@ -1,11 +1,12 @@
-<div class="col-md-7 product-details">
+{% set width_class = "expand" if not slides else "" %}
+<div class="col-md-7 product-details {{ width_class }}">
<!-- title -->
<h1 class="product-title" itemprop="name">
{{ item_name }}
</h1>
<p class="product-code">
<span>{{ _("Item Code") }}:</span>
- <span itemprop="productID">{{ doc.name }}</span>
+ <span itemprop="productID">{{ doc.item_code }}</span>
</p>
{% if has_variants %}
<!-- configure template -->
diff --git a/erpnext/templates/generators/item/item_image.html b/erpnext/templates/generators/item/item_image.html
index e9b0916..4de3b62 100644
--- a/erpnext/templates/generators/item/item_image.html
+++ b/erpnext/templates/generators/item/item_image.html
@@ -1,4 +1,5 @@
-<div class="col-md-5 h-100 d-flex">
+{% set column_size = 5 if slides else 4 %}
+<div class="col-md-{{ column_size }} h-100 d-flex mb-4">
{% if slides %}
<div class="item-slideshow d-flex flex-column mr-3">
{% for item in slides %}
diff --git a/erpnext/templates/generators/item/item_specifications.html b/erpnext/templates/generators/item/item_specifications.html
index d4dfa8e..1dccff9 100644
--- a/erpnext/templates/generators/item/item_specifications.html
+++ b/erpnext/templates/generators/item/item_specifications.html
@@ -1,10 +1,13 @@
-{% if doc.website_specifications -%}
-<div class="row item-website-specification mt-5">
- <div class="col-md-12">
- <table class="table table-bordered">
- {% for d in doc.website_specifications -%}
+{% if website_specifications -%}
+<div class="row mt-5 item-website-specification">
+ <div class="col-md-11">
+ {% if not show_tabs %}
+ <h2 class="product-title mb-5">Product Details</h2>
+ {% endif %}
+ <table class="table table-bordered table-hover">
+ {% for d in website_specifications -%}
<tr>
- <td class="text-muted" style="width: 30%;">{{ d.label }}</td>
+ <td class="text-muted" style="width: 30%; font-weight: bold;">{{ d.label }}</td>
<td>{{ d.description }}</td>
</tr>
{%- endfor %}
diff --git a/erpnext/templates/includes/macros.html b/erpnext/templates/includes/macros.html
index aec201e..77c5649 100644
--- a/erpnext/templates/includes/macros.html
+++ b/erpnext/templates/includes/macros.html
@@ -172,9 +172,7 @@
<a href="/{{ item.route or '#' }}" style="text-decoration: none;">
<img class="card-img" src="{{ item.image }}" alt="{{ title }}">
</a>
- <div class="remove-wish"
- style="position:absolute; top:10px; right: 20px; border-radius: 50%; border: 1px solid var(--gray-100); width: 25px; height: 25px;"
- data-item-code="{{ item.item_code }}">
+ <div class="remove-wish" data-item-code="{{ item.item_code }}">
<span style="padding-bottom: 2px;">
<svg class="icon sm remove-wish-icon" style="margin-bottom: 4px; margin-left: 0.5px;">
<use class="close" href="#icon-close"></use>
@@ -199,7 +197,7 @@
{%- endmacro -%}
{%- macro wishlist_card_body(item, settings) %}
-<div class="card-body text-center" style="width:100%">
+<div class="card-body text-center" style="width: 100%;">
<div style="margin-top: 16px;">
<div class="product-title">{{ item.item_name or item.item_code or ''}}</div>
</div>