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
This commit is contained in:
parent
cd117149e1
commit
25ffafae81
@ -34,6 +34,9 @@
|
|||||||
"copy_from_item_group",
|
"copy_from_item_group",
|
||||||
"column_break_27",
|
"column_break_27",
|
||||||
"web_long_description",
|
"web_long_description",
|
||||||
|
"display_additional_information_section",
|
||||||
|
"show_tabbed_section",
|
||||||
|
"tabs",
|
||||||
"section_break_6",
|
"section_break_6",
|
||||||
"ranking",
|
"ranking",
|
||||||
"set_meta_tags",
|
"set_meta_tags",
|
||||||
@ -234,7 +237,7 @@
|
|||||||
"collapsible": 1,
|
"collapsible": 1,
|
||||||
"fieldname": "advanced_display_section",
|
"fieldname": "advanced_display_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Advanced Display"
|
"label": "Advanced Display Content"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "display_section",
|
"fieldname": "display_section",
|
||||||
@ -265,13 +268,31 @@
|
|||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "WEB-ITM-.####",
|
"options": "WEB-ITM-.####",
|
||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "display_additional_information_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Display Additional Information"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "show_tabbed_section",
|
||||||
|
"fieldname": "tabs",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Tabs",
|
||||||
|
"options": "Website Item Tabbed Section"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "show_tabbed_section",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Add Section with Tabs"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 1,
|
"has_web_view": 1,
|
||||||
"image_field": "image",
|
"image_field": "image",
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-02-18 13:23:18.286883",
|
"modified": "2021-03-18 20:37:54.955364",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "Website Item",
|
"name": "Website Item",
|
||||||
|
@ -11,6 +11,7 @@ from frappe import _
|
|||||||
|
|
||||||
from frappe.website.website_generator import WebsiteGenerator
|
from frappe.website.website_generator import WebsiteGenerator
|
||||||
from frappe.utils import cstr, random_string, cint, flt
|
from frappe.utils import cstr, random_string, cint, flt
|
||||||
|
from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow
|
||||||
|
|
||||||
from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
|
from erpnext.setup.doctype.item_group.item_group import (get_parent_item_groups, invalidate_cache_for)
|
||||||
|
|
||||||
@ -166,7 +167,6 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
context.search_link = '/search'
|
context.search_link = '/search'
|
||||||
|
|
||||||
context.parents = get_parent_item_groups(self.item_group, from_item=True)
|
context.parents = get_parent_item_groups(self.item_group, from_item=True)
|
||||||
context.body_class = "product-page"
|
|
||||||
self.attributes = frappe.get_all("Item Variant Attribute",
|
self.attributes = frappe.get_all("Item Variant Attribute",
|
||||||
fields=["attribute", "attribute_value"],
|
fields=["attribute", "attribute_value"],
|
||||||
filters={"parent": self.item_code})
|
filters={"parent": self.item_code})
|
||||||
@ -175,6 +175,11 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
self.set_disabled_attributes(context)
|
self.set_disabled_attributes(context)
|
||||||
self.set_metatags(context)
|
self.set_metatags(context)
|
||||||
self.set_shopping_cart_data(context)
|
self.set_shopping_cart_data(context)
|
||||||
|
self.get_product_details_section(context)
|
||||||
|
|
||||||
|
context.wished = False
|
||||||
|
if frappe.db.exists("Wishlist Items", {"item_code": self.item_code, "parent": frappe.session.user}):
|
||||||
|
context.wished = True
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -205,6 +210,12 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
|
|
||||||
context[fieldname] = value
|
context[fieldname] = value
|
||||||
|
|
||||||
|
if self.slideshow:
|
||||||
|
if context.variant and context.variant.slideshow:
|
||||||
|
context.update(get_slideshow(context.variant))
|
||||||
|
else:
|
||||||
|
context.update(get_slideshow(self))
|
||||||
|
|
||||||
def set_attribute_context(self, context):
|
def set_attribute_context(self, context):
|
||||||
if self.has_variants:
|
if self.has_variants:
|
||||||
attribute_values_available = {}
|
attribute_values_available = {}
|
||||||
@ -326,6 +337,30 @@ class WebsiteItem(WebsiteGenerator):
|
|||||||
row.label = label
|
row.label = label
|
||||||
row.description = desc
|
row.description = desc
|
||||||
|
|
||||||
|
def get_product_details_section(self, context):
|
||||||
|
""" Get section with tabs or website specifications. """
|
||||||
|
context.show_tabs = self.show_tabbed_section
|
||||||
|
if self.show_tabbed_section and self.tabs:
|
||||||
|
context.tabs = self.get_tabs()
|
||||||
|
else:
|
||||||
|
context.website_specifications = self.website_specifications
|
||||||
|
|
||||||
|
def get_tabs(self):
|
||||||
|
tab_values = {}
|
||||||
|
tab_values["tab_1_title"] = "Product Details"
|
||||||
|
tab_values["tab_1_content"] = frappe.render_template(
|
||||||
|
"templates/generators/item/item_specifications.html",
|
||||||
|
{
|
||||||
|
"website_specifications": self.website_specifications,
|
||||||
|
"show_tabs": self.show_tabbed_section
|
||||||
|
})
|
||||||
|
|
||||||
|
for row in self.tabs:
|
||||||
|
tab_values[f"tab_{row.idx + 1}_title"] = _(row.label)
|
||||||
|
tab_values[f"tab_{row.idx + 1}_content"] = row.content
|
||||||
|
|
||||||
|
return tab_values
|
||||||
|
|
||||||
def invalidate_cache_for_web_item(doc):
|
def invalidate_cache_for_web_item(doc):
|
||||||
"""Invalidate Website Item Group cache and rebuild ItemVariantsCacheManager."""
|
"""Invalidate Website Item Group cache and rebuild ItemVariantsCacheManager."""
|
||||||
from erpnext.stock.doctype.item.item import invalidate_item_variants_cache_for_website
|
from erpnext.stock.doctype.item.item import invalidate_item_variants_cache_for_website
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"creation": "2021-03-18 20:32:15.321402",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"label",
|
||||||
|
"content"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "label",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "content",
|
||||||
|
"fieldtype": "HTML Editor",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Content"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2021-03-18 20:35:26.991192",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "E-commerce",
|
||||||
|
"name": "Website Item Tabbed Section",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class WebsiteItemTabbedSection(Document):
|
||||||
|
pass
|
@ -31,37 +31,32 @@
|
|||||||
"options": "Wishlist Items"
|
"options": "Wishlist Items"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"in_create": 1,
|
||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-10 19:05:52.373601",
|
"modified": "2021-03-18 16:10:29.534522",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "Wishlist",
|
"name": "Wishlist",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"share": 1,
|
"share": 1
|
||||||
"write": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"create": 1,
|
|
||||||
"delete": 1,
|
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "Stock Manager",
|
"role": "Stock Manager",
|
||||||
"share": 1,
|
"share": 1
|
||||||
"write": 1
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
|
@ -12,6 +12,10 @@ class Wishlist(Document):
|
|||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def add_to_wishlist(item_code, price, formatted_price=None):
|
def add_to_wishlist(item_code, price, formatted_price=None):
|
||||||
"""Insert Item into wishlist."""
|
"""Insert Item into wishlist."""
|
||||||
|
|
||||||
|
if frappe.db.exists("Wishlist Items", {"item_code": item_code, "parent": frappe.session.user}):
|
||||||
|
return
|
||||||
|
|
||||||
web_item_data = frappe.db.get_value("Website Item", {"item_code": item_code},
|
web_item_data = frappe.db.get_value("Website Item", {"item_code": item_code},
|
||||||
["image", "website_warehouse", "name", "item_name", "item_group", "route"]
|
["image", "website_warehouse", "name", "item_name", "item_group", "route"]
|
||||||
, as_dict=1)
|
, as_dict=1)
|
||||||
@ -44,7 +48,7 @@ def add_to_wishlist(item_code, price, formatted_price=None):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def remove_from_wishlist(item_code):
|
def remove_from_wishlist(item_code):
|
||||||
if frappe.db.exists("Wishlist Items", {"item_code": item_code}):
|
if frappe.db.exists("Wishlist Items", {"item_code": item_code, "parent": frappe.session.user}):
|
||||||
frappe.db.sql("""
|
frappe.db.sql("""
|
||||||
delete
|
delete
|
||||||
from `tabWishlist Items`
|
from `tabWishlist Items`
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
|
"fetch_from": "website_item.item_code",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "item_code",
|
"fieldname": "item_code",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
@ -106,12 +108,16 @@
|
|||||||
"label": "Price"
|
"label": "Price"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"fetch_from": "item_code.item_group",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "item_group",
|
"fieldname": "item_group",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Item Group",
|
"label": "Item Group",
|
||||||
"options": "Item Group"
|
"options": "Item Group"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"fetch_from": "website_item.route",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
"fieldname": "route",
|
"fieldname": "route",
|
||||||
"fieldtype": "Small Text",
|
"fieldtype": "Small Text",
|
||||||
"label": "Route"
|
"label": "Route"
|
||||||
@ -125,7 +131,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2021-03-15 16:37:40.405333",
|
"modified": "2021-03-18 16:04:52.965613",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "Wishlist Items",
|
"name": "Wishlist Items",
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
@import "frappe/public/scss/common/mixins";
|
@import "frappe/public/scss/common/mixins";
|
||||||
|
|
||||||
|
$wish-red: #F47A7A;
|
||||||
|
|
||||||
body.product-page {
|
body.product-page {
|
||||||
background: var(--gray-50);
|
background: var(--gray-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.item-breadcrumbs {
|
.item-breadcrumbs {
|
||||||
.breadcrumb-container {
|
.breadcrumb-container {
|
||||||
ol.breadcrumb {
|
|
||||||
background-color: var(--gray-50) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--gray-900);
|
color: var(--gray-900);
|
||||||
}
|
}
|
||||||
@ -140,6 +137,7 @@ body.product-page {
|
|||||||
|
|
||||||
.item-card {
|
.item-card {
|
||||||
padding: var(--padding-sm);
|
padding: var(--padding-sm);
|
||||||
|
min-width: 250px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,14 +187,40 @@ body.product-page {
|
|||||||
min-height: 70vh;
|
min-height: 70vh;
|
||||||
|
|
||||||
.product-details {
|
.product-details {
|
||||||
max-width: 40%;
|
max-width: 50%;
|
||||||
margin-left: -30px;
|
|
||||||
|
|
||||||
.btn-add-to-cart {
|
.btn-add-to-cart {
|
||||||
font-size: var(--text-base);
|
font-size: var(--text-base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expand {
|
||||||
|
max-width: 100% !important; // expand in absence of slideshow
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 789px) {
|
||||||
|
.product-details {
|
||||||
|
max-width: 90% !important;
|
||||||
|
|
||||||
|
.btn-add-to-cart {
|
||||||
|
font-size: var(--text-base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-add-to-wishlist {
|
||||||
|
svg use {
|
||||||
|
stroke: var(--wish-red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-view-in-wishlist {
|
||||||
|
svg use {
|
||||||
|
fill: var(--wish-red);
|
||||||
|
stroke: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.product-title {
|
.product-title {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -578,16 +602,16 @@ body.product-page {
|
|||||||
|
|
||||||
.not-wished {
|
.not-wished {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
stroke: #F47A7A !important;
|
stroke: var(--wish-red) !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
fill: #F47A7A;
|
fill: var(--wish-red);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wished {
|
.wished {
|
||||||
stroke: none;
|
stroke: none;
|
||||||
fill: #F47A7A !important;
|
fill: var(--wish-red) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-row-checkbox {
|
.list-row-checkbox {
|
||||||
@ -663,12 +687,23 @@ body.product-page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.remove-wish {
|
.remove-wish {
|
||||||
|
position: absolute;
|
||||||
|
top:10px;
|
||||||
|
right: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid var(--gray-100);
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--gray-100);
|
background-color: var(--gray-100);
|
||||||
border: 1px solid var(--icon-stroke);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.wish-removed {
|
.wish-removed {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-website-specification {
|
||||||
|
font-size: .875rem;
|
||||||
|
}
|
||||||
|
@ -126,7 +126,6 @@ class ItemGroup(NestedSet, WebsiteGenerator):
|
|||||||
|
|
||||||
context.no_breadcrumbs = False
|
context.no_breadcrumbs = False
|
||||||
context.title = self.website_title or self.name
|
context.title = self.website_title or self.name
|
||||||
context.body_class = "product-page"
|
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -9,17 +9,33 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_content %}
|
{% block page_content %}
|
||||||
<div class="product-container">
|
<div class="product-container col-md-12">
|
||||||
{% from "erpnext/templates/includes/macros.html" import product_image %}
|
{% from "erpnext/templates/includes/macros.html" import product_image %}
|
||||||
<div class="item-content">
|
<div class="item-content">
|
||||||
<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
|
<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
|
||||||
|
<!-- Image, Description, Add to Cart -->
|
||||||
<div class="row mb-5">
|
<div class="row mb-5">
|
||||||
{% include "templates/generators/item/item_image.html" %}
|
{% include "templates/generators/item/item_image.html" %}
|
||||||
{% include "templates/generators/item/item_details.html" %}
|
{% include "templates/generators/item/item_details.html" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 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"%}
|
{% include "templates/generators/item/item_specifications.html"%}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Advanced Custom Website Content -->
|
||||||
{{ doc.website_content or '' }}
|
{{ doc.website_content or '' }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
<div class="item-cart row mt-2" data-variant-item-code="{{ item_code }}">
|
<div class="item-cart row mt-2" data-variant-item-code="{{ item_code }}">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
|
<!-- Price and Availability -->
|
||||||
{% if cart_settings.show_price and product_info.price %}
|
{% if cart_settings.show_price and product_info.price %}
|
||||||
<div class="product-price">
|
<div class="product-price">
|
||||||
{{ product_info.price.formatted_price_sales_uom }}
|
{{ product_info.price.formatted_price_sales_uom }}
|
||||||
@ -30,17 +31,21 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Add to Cart / View in Cart, Contact Us -->
|
||||||
<div class="mt-5 mb-5">
|
<div class="mt-5 mb-5">
|
||||||
|
<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) %}
|
{% if product_info.price and (cart_settings.allow_items_not_in_stock or product_info.in_stock) %}
|
||||||
<a href="/cart"
|
<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"
|
role="button"
|
||||||
>
|
>
|
||||||
{{ _("View in Cart") }}
|
{{ _("View in Cart") }}
|
||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
data-item-code="{{item_code}}"
|
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">
|
<span class="mr-2">
|
||||||
<svg class="icon icon-md">
|
<svg class="icon icon-md">
|
||||||
@ -50,6 +55,36 @@
|
|||||||
{{ _("Add to Cart") }}
|
{{ _("Add to Cart") }}
|
||||||
</button>
|
</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 %}
|
{% if cart_settings.show_contact_us_button %}
|
||||||
{% include "templates/generators/item/item_inquiry.html" %}
|
{% include "templates/generators/item/item_inquiry.html" %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -60,6 +95,7 @@
|
|||||||
<script>
|
<script>
|
||||||
frappe.ready(() => {
|
frappe.ready(() => {
|
||||||
$('.page_content').on('click', '.btn-add-to-cart', (e) => {
|
$('.page_content').on('click', '.btn-add-to-cart', (e) => {
|
||||||
|
// Bind action on add to cart button
|
||||||
const $btn = $(e.currentTarget);
|
const $btn = $(e.currentTarget);
|
||||||
$btn.prop('disabled', true);
|
$btn.prop('disabled', true);
|
||||||
const item_code = $btn.data('item-code');
|
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>
|
</script>
|
||||||
|
|
||||||
|
@ -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 -->
|
<!-- title -->
|
||||||
<h1 class="product-title" itemprop="name">
|
<h1 class="product-title" itemprop="name">
|
||||||
{{ item_name }}
|
{{ item_name }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="product-code">
|
<p class="product-code">
|
||||||
<span>{{ _("Item Code") }}:</span>
|
<span>{{ _("Item Code") }}:</span>
|
||||||
<span itemprop="productID">{{ doc.name }}</span>
|
<span itemprop="productID">{{ doc.item_code }}</span>
|
||||||
</p>
|
</p>
|
||||||
{% if has_variants %}
|
{% if has_variants %}
|
||||||
<!-- configure template -->
|
<!-- configure template -->
|
||||||
|
@ -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 %}
|
{% if slides %}
|
||||||
<div class="item-slideshow d-flex flex-column mr-3">
|
<div class="item-slideshow d-flex flex-column mr-3">
|
||||||
{% for item in slides %}
|
{% for item in slides %}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
{% if doc.website_specifications -%}
|
{% if website_specifications -%}
|
||||||
<div class="row item-website-specification mt-5">
|
<div class="row mt-5 item-website-specification">
|
||||||
<div class="col-md-12">
|
<div class="col-md-11">
|
||||||
<table class="table table-bordered">
|
{% if not show_tabs %}
|
||||||
{% for d in doc.website_specifications -%}
|
<h2 class="product-title mb-5">Product Details</h2>
|
||||||
|
{% endif %}
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
{% for d in website_specifications -%}
|
||||||
<tr>
|
<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>
|
<td>{{ d.description }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
@ -172,9 +172,7 @@
|
|||||||
<a href="/{{ item.route or '#' }}" style="text-decoration: none;">
|
<a href="/{{ item.route or '#' }}" style="text-decoration: none;">
|
||||||
<img class="card-img" src="{{ item.image }}" alt="{{ title }}">
|
<img class="card-img" src="{{ item.image }}" alt="{{ title }}">
|
||||||
</a>
|
</a>
|
||||||
<div class="remove-wish"
|
<div class="remove-wish" data-item-code="{{ item.item_code }}">
|
||||||
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 }}">
|
|
||||||
<span style="padding-bottom: 2px;">
|
<span style="padding-bottom: 2px;">
|
||||||
<svg class="icon sm remove-wish-icon" style="margin-bottom: 4px; margin-left: 0.5px;">
|
<svg class="icon sm remove-wish-icon" style="margin-bottom: 4px; margin-left: 0.5px;">
|
||||||
<use class="close" href="#icon-close"></use>
|
<use class="close" href="#icon-close"></use>
|
||||||
@ -199,7 +197,7 @@
|
|||||||
{%- endmacro -%}
|
{%- endmacro -%}
|
||||||
|
|
||||||
{%- macro wishlist_card_body(item, settings) %}
|
{%- 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 style="margin-top: 16px;">
|
||||||
<div class="product-title">{{ item.item_name or item.item_code or ''}}</div>
|
<div class="product-title">{{ item.item_name or item.item_code or ''}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,7 +28,6 @@ def get_context(context):
|
|||||||
context.attribute_filters = filter_engine.get_attribute_filters()
|
context.attribute_filters = filter_engine.get_attribute_filters()
|
||||||
|
|
||||||
context.e_commerce_settings = engine.settings
|
context.e_commerce_settings = engine.settings
|
||||||
context.body_class = "product-page"
|
|
||||||
context.page_length = engine.settings.products_per_page or 20
|
context.page_length = engine.settings.products_per_page or 20
|
||||||
|
|
||||||
context.no_cache = 1
|
context.no_cache = 1
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
<!-- style defined at shop-by-category index -->
|
<!-- style defined at shop-by-category index -->
|
||||||
<div class="card category-card" data-type="{{ type }}" data-name="{{ title }}">
|
<div class="card category-card" data-type="{{ type }}" data-name="{{ title }}">
|
||||||
{% if image %}
|
{% if image %}
|
||||||
<img class="card-img-top" src="{{ image }}" alt="{{ title }}" style="height:80%">
|
<img class="card-img-top" src="{{ image }}" alt="{{ title }}" style="height: 80%;">
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="placeholder-div">
|
<div class="placeholder-div">
|
||||||
<span class="placeholder">AB</span>
|
<span class="placeholder">
|
||||||
|
{{ frappe.utils.get_abbr(title) }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="card-body text-center text-muted">
|
<div class="card-body text-center text-muted">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user