mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-12 17:51:20 +00:00
feat: Recommended Items and Item full page refresh
- Added Optional Recommended Items - Item Full Page minor UI Refresh - Floating wishlist button in item full page - Reviews section UI Refresh
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
{% extends "templates/web.html" %}
|
||||
{% from "erpnext/templates/includes/macros.html" import recommended_item_row %}
|
||||
|
||||
{% block title %} {{ title }} {% endblock %}
|
||||
|
||||
@@ -9,7 +10,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="product-container col-md-12">
|
||||
<div class="product-container item-main">
|
||||
{% from "erpnext/templates/includes/macros.html" import product_image %}
|
||||
<div class="item-content">
|
||||
<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
|
||||
@@ -18,33 +19,56 @@
|
||||
{% include "templates/generators/item/item_image.html" %}
|
||||
{% include "templates/generators/item/item_details.html" %}
|
||||
</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"%}
|
||||
{% endif %}
|
||||
|
||||
<!-- Advanced Custom Website Content -->
|
||||
{{ doc.website_content or '' }}
|
||||
|
||||
<!-- Reviews and Comments -->
|
||||
{% if shopping_cart.cart_settings.enable_reviews and not doc.has_variants %}
|
||||
{% include "templates/generators/item/item_reviews.html"%}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Info/Reviews, Recommendations -->
|
||||
<div class="d-flex">
|
||||
{% set show_recommended_items = recommended_items and shopping_cart.cart_settings.enable_recommendations %}
|
||||
{% set info_col = 'col-9' if show_recommended_items else 'col-12' %}
|
||||
|
||||
{% set padding_top = 'pt-0' if (show_tabs and tabs) else '' %}
|
||||
|
||||
<div class="product-container mt-4 {{ padding_top }} {{ info_col }}">
|
||||
<div class="item-content {{ 'mt-minus-2' if (show_tabs and tabs) else '' }}">
|
||||
<div class="product-page-content" itemscope itemtype="http://schema.org/Product">
|
||||
<!-- 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 '' }}
|
||||
|
||||
<!-- Reviews and Comments -->
|
||||
{% if shopping_cart.cart_settings.enable_reviews and not doc.has_variants %}
|
||||
{% include "templates/generators/item/item_reviews.html"%}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recommended Items -->
|
||||
{% if show_recommended_items %}
|
||||
<div class="mt-4 col-3 recommended-item-section">
|
||||
<span class="recommendation-header">Recommended</span>
|
||||
<div class="product-container mt-2 recommendation-container">
|
||||
{% for item in recommended_items %}
|
||||
{{ recommended_item_row(item) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block base_scripts %}
|
||||
|
||||
@@ -7,34 +7,39 @@
|
||||
<div class="col-md-12">
|
||||
<!-- Price and Availability -->
|
||||
{% if cart_settings.show_price and product_info.price %}
|
||||
{% set price_info = product_info.price %}
|
||||
{% set price_info = product_info.price %}
|
||||
|
||||
{% if price_info.formatted_mrp %}
|
||||
<small class="formatted-price">
|
||||
M.R.P.:
|
||||
<s>{{ price_info.formatted_mrp }}</s>
|
||||
</small>
|
||||
<small class="ml-2 formatted-price" style="color: #F47A7A; font-weight: 500;">
|
||||
{{ price_info.get("formatted_discount_percent") or price_info.get("formatted_discount_rate")}} OFF
|
||||
</small>
|
||||
{% endif %}
|
||||
<div class="product-price">
|
||||
<!-- Final Price -->
|
||||
{{ price_info.formatted_price_sales_uom }}
|
||||
|
||||
<div class="product-price">
|
||||
{{ price_info.formatted_price_sales_uom }}
|
||||
<small class="formatted-price">({{ price_info.formatted_price }} / {{ product_info.uom }})</small>
|
||||
</div>
|
||||
<!-- Striked Price and Discount -->
|
||||
{% if price_info.formatted_mrp %}
|
||||
<small class="formatted-price">
|
||||
<s>MRP {{ price_info.formatted_mrp }}</s>
|
||||
</small>
|
||||
<small class="ml-1 formatted-price in-green">
|
||||
-{{ price_info.get("formatted_discount_percent") or price_info.get("formatted_discount_rate")}}
|
||||
</small>
|
||||
{% endif %}
|
||||
|
||||
<!-- Price per UOM -->
|
||||
<small class="formatted-price ml-2">
|
||||
({{ price_info.formatted_price }} / {{ product_info.uom }})
|
||||
</small>
|
||||
</div>
|
||||
{% else %}
|
||||
{{ _("UOM") }} : {{ product_info.uom }}
|
||||
{% endif %}
|
||||
|
||||
{% if cart_settings.show_stock_availability %}
|
||||
<div>
|
||||
<div class="mt-2">
|
||||
{% if product_info.in_stock == 0 %}
|
||||
<span class="text-danger no-stock">
|
||||
{{ _('Not in stock') }}
|
||||
</span>
|
||||
{% elif product_info.in_stock == 1 %}
|
||||
<span class="text-success has-stock">
|
||||
<span class="in-green has-stock">
|
||||
{{ _('In stock') }}
|
||||
{% if product_info.show_stock_qty and product_info.stock_qty %}
|
||||
({{ product_info.stock_qty[0][0] }})
|
||||
@@ -47,10 +52,15 @@
|
||||
<!-- Offers -->
|
||||
{% if doc.offers %}
|
||||
<br>
|
||||
<h3>Offers</h3>
|
||||
<div class="offers-heading mb-4">
|
||||
<span class="mr-1 tag-icon">
|
||||
<svg class="icon icon-lg"><use href="#icon-tag"></use></svg>
|
||||
</span>
|
||||
<b>Available Offers</b>
|
||||
</div>
|
||||
<div class="offer-container">
|
||||
{% for offer in doc.offers %}
|
||||
<div class="mt-2" style="display: flex;">
|
||||
<div class="mt-2 d-flex">
|
||||
<div class="mr-2" >
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" stroke="var(--yellow-500)" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 15.6213C19 15.2235 19.158 14.842 19.4393 14.5607L20.9393 13.0607C21.5251 12.4749 21.5251 11.5251 20.9393 10.9393L19.4393 9.43934C19.158 9.15804 19 8.7765 19 8.37868V6.5C19 5.67157 18.3284 5 17.5 5H15.6213C15.2235 5 14.842 4.84196 14.5607 4.56066L13.0607 3.06066C12.4749 2.47487 11.5251 2.47487 10.9393 3.06066L9.43934 4.56066C9.15804 4.84196 8.7765 5 8.37868 5H6.5C5.67157 5 5 5.67157 5 6.5V8.37868C5 8.7765 4.84196 9.15804 4.56066 9.43934L3.06066 10.9393C2.47487 11.5251 2.47487 12.4749 3.06066 13.0607L4.56066 14.5607C4.84196 14.842 5 15.2235 5 15.6213V17.5C5 18.3284 5.67157 19 6.5 19H8.37868C8.7765 19 9.15804 19.158 9.43934 19.4393L10.9393 20.9393C11.5251 21.5251 12.4749 21.5251 13.0607 20.9393L14.5607 19.4393C14.842 19.158 15.2235 19 15.6213 19H17.5C18.3284 19 19 18.3284 19 17.5V15.6213Z" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
@@ -59,8 +69,8 @@
|
||||
<path d="M15.5 14.5C15.5 15.0523 15.0523 15.5 14.5 15.5C13.9477 15.5 13.5 15.0523 13.5 14.5C13.5 13.9477 13.9477 13.5 14.5 13.5C15.0523 13.5 15.5 13.9477 15.5 14.5Z" fill="white" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="mr-1">
|
||||
<strong>{{ _(offer.offer_title) }}:</strong>
|
||||
<p class="mr-1 mb-1">
|
||||
{{ _(offer.offer_title) }}:
|
||||
{{ _(offer.offer_subtitle) }}
|
||||
<a class="offer-details" href="#"
|
||||
data-offer-title="{{ offer.offer_title }}" data-offer-id="{{ offer.name }}"
|
||||
@@ -74,20 +84,14 @@
|
||||
{% endif %}
|
||||
|
||||
<!-- Add to Cart / View in Cart, Contact Us -->
|
||||
<div class="mt-5 mb-5">
|
||||
<div style="display: flex;" class="mb-4">
|
||||
<div class="mt-6 mb-5">
|
||||
<div class="mb-4 d-flex">
|
||||
<!-- 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 hidden mr-2 font-md"
|
||||
role="button"
|
||||
>
|
||||
<a href="/cart" class="btn btn-light btn-view-in-cart hidden mr-2 font-md" role="button">
|
||||
{{ _("View in Cart") }}
|
||||
</a>
|
||||
<button
|
||||
data-item-code="{{item_code}}"
|
||||
class="btn btn-primary btn-add-to-cart w-50 mr-2"
|
||||
>
|
||||
<button data-item-code="{{item_code}}" class="btn btn-primary btn-add-to-cart mr-2 w-30-40">
|
||||
<span class="mr-2">
|
||||
<svg class="icon icon-md">
|
||||
<use href="#icon-assets"></use>
|
||||
@@ -97,41 +101,11 @@
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
<!-- Add to Wishlist -->
|
||||
{% if cart_settings.enable_wishlist %}
|
||||
<a href="/wishlist"
|
||||
class="btn btn-view-in-wishlist font-md 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 font-md"
|
||||
>
|
||||
<span class="mr-2">
|
||||
<svg class="icon icon-md">
|
||||
<use href="#icon-heart"></use>
|
||||
</svg>
|
||||
</span>
|
||||
{{ _("Add to Wishlist") }}
|
||||
</button>
|
||||
<!-- Contact Us -->
|
||||
{% if cart_settings.show_contact_us_button %}
|
||||
{% include "templates/generators/item/item_inquiry.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Contact Us -->
|
||||
{% if cart_settings.show_contact_us_button %}
|
||||
{% include "templates/generators/item/item_inquiry.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -155,28 +129,6 @@
|
||||
});
|
||||
});
|
||||
|
||||
$('.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);
|
||||
e_commerce.wishlist.set_wishlist_count();
|
||||
$('.btn-add-to-wishlist, .btn-view-in-wishlist').toggleClass('hidden');
|
||||
|
||||
};
|
||||
e_commerce.wishlist.add_remove_from_wishlist("add", args, success_action, failure_action);
|
||||
});
|
||||
|
||||
$('.page_content').on('click', '.offer-details', (e) => {
|
||||
// Bind action on More link in Offers
|
||||
const $btn = $(e.currentTarget);
|
||||
|
||||
@@ -1,28 +1,65 @@
|
||||
{% set width_class = "expand" if not slides else "" %}
|
||||
{% set cart_settings = shopping_cart.cart_settings %}
|
||||
{% set product_info = shopping_cart.product_info %}
|
||||
{% set price_info = product_info.get('price') or {} %}
|
||||
|
||||
<div class="col-md-7 product-details {{ width_class }}">
|
||||
<!-- title -->
|
||||
<h1 class="product-title" itemprop="name">
|
||||
{{ doc.web_item_name }}
|
||||
</h1>
|
||||
<p class="product-code">
|
||||
<span>{{ _("Item Code") }}:</span>
|
||||
<span itemprop="productID">{{ doc.item_code }}</span>
|
||||
</p>
|
||||
{% if has_variants %}
|
||||
<!-- configure template -->
|
||||
{% include "templates/generators/item/item_configure.html" %}
|
||||
{% else %}
|
||||
<!-- add variant to cart -->
|
||||
{% include "templates/generators/item/item_add_to_cart.html" %}
|
||||
{% endif %}
|
||||
<!-- description -->
|
||||
<div class="product-description" itemprop="description">
|
||||
{% if frappe.utils.strip_html(doc.web_long_description or '') %}
|
||||
{{ doc.web_long_description | safe }}
|
||||
{% elif frappe.utils.strip_html(doc.description or '') %}
|
||||
{{ doc.description | safe }}
|
||||
{% else %}
|
||||
{{ _("No description given") }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<!-- title -->
|
||||
<div class="product-title col-11" itemprop="name">
|
||||
{{ doc.web_item_name }}
|
||||
</div>
|
||||
|
||||
<!-- Wishlist -->
|
||||
{% if cart_settings.enable_wishlist %}
|
||||
<div class="like-action-item-fp like-action {{ 'like-action-wished' if wished else ''}} ml-2"
|
||||
data-item-code="{{ doc.item_code }}"
|
||||
data-price="{{ price_info.get('price_list_rate') if price_info else 0 }}"
|
||||
data-formatted-price="{{ price_info.get('formatted_price') if price_info else 0 }}">
|
||||
<svg class="icon sm">
|
||||
<use class="{{ 'wished' if wished else 'not-wished' }} wish-icon" href="#icon-heart"></use>
|
||||
</svg>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<p class="product-code">
|
||||
<span class="product-item-group">
|
||||
{{ _(doc.item_group) }}
|
||||
</span>
|
||||
<span class="product-item-code">
|
||||
{{ _("Item Code") }}:
|
||||
</span>
|
||||
<span itemprop="productID">{{ doc.item_code }}</span>
|
||||
</p>
|
||||
{% if has_variants %}
|
||||
<!-- configure template -->
|
||||
{% include "templates/generators/item/item_configure.html" %}
|
||||
{% else %}
|
||||
<!-- add variant to cart -->
|
||||
{% include "templates/generators/item/item_add_to_cart.html" %}
|
||||
{% endif %}
|
||||
<!-- description -->
|
||||
<div class="product-description" itemprop="description">
|
||||
{% if frappe.utils.strip_html(doc.web_long_description or '') %}
|
||||
{{ doc.web_long_description | safe }}
|
||||
{% elif frappe.utils.strip_html(doc.description or '') %}
|
||||
{{ doc.description | safe }}
|
||||
{% else %}
|
||||
{{ "" }}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block base_scripts %}
|
||||
<!-- js should be loaded in body! -->
|
||||
<script type="text/javascript" src="/assets/frappe/js/lib/jquery/jquery.min.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
<script>
|
||||
$('.page_content').on('click', '.like-action-item-fp', (e) => {
|
||||
// Bind action on wishlist button
|
||||
const $btn = $(e.currentTarget);
|
||||
e_commerce.wishlist.wishlist_action($btn);
|
||||
});
|
||||
</script>
|
||||
@@ -1,7 +1,7 @@
|
||||
{% if shopping_cart and shopping_cart.cart_settings.enabled %}
|
||||
{% set cart_settings = shopping_cart.cart_settings %}
|
||||
{% if cart_settings.show_contact_us_button | int %}
|
||||
<button class="btn btn-inquiry btn-primary-light font-md" data-item-code="{{ doc.name }}">
|
||||
<button class="btn btn-inquiry font-md w-30-40" data-item-code="{{ doc.name }}">
|
||||
{{ _('Contact Us') }}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,23 +1,29 @@
|
||||
{% from "erpnext/templates/includes/macros.html" import user_review, ratings_summary %}
|
||||
|
||||
<div class="mt-12 ratings-reviews-section" style="display: flex;">
|
||||
<div class="col-md-4 order-md-1 mt-8" style="max-width: 300px;">
|
||||
{{ ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating) }}
|
||||
<div class="mt-4 ratings-reviews-section">
|
||||
<!-- Title and Action -->
|
||||
<div class="w-100 mt-4 mb-2 d-flex">
|
||||
<div class="reviews-header col-9">
|
||||
{{ _("Customer Reviews") }}
|
||||
</div>
|
||||
|
||||
<div class="write-a-review-btn col-3">
|
||||
<!-- Write a Review for legitimate users -->
|
||||
{% if frappe.session.user != "Guest" and user_is_customer %}
|
||||
<button class="btn btn-write-review"
|
||||
data-web-item="{{ doc.name }}">
|
||||
{{ _("Write a Review") }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary -->
|
||||
{{ ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating, for_summary=True, total_reviews=total_reviews) }}
|
||||
|
||||
<!-- Write a Review for legitimate users -->
|
||||
{% if frappe.session.user != "Guest" and user_is_customer %}
|
||||
<button class="btn btn-light btn-write-review mr-2 mt-4 mb-4 w-100"
|
||||
data-web-item="{{ doc.name }}">
|
||||
{{ _("Write a Review") }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Reviews and Comments -->
|
||||
<div class="col-12 order-2 col-md-9 order-md-2 mt-8 ml-16">
|
||||
<h2 class="reviews-header">
|
||||
{{ _("Reviews") }}
|
||||
</h2>
|
||||
<div class="mt-8">
|
||||
{% if reviews %}
|
||||
{{ user_review(reviews) }}
|
||||
|
||||
@@ -64,7 +70,7 @@
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
frappe.msgprint({
|
||||
message: __("Thank you for submitting your review"),
|
||||
message: __("Thank you for the review"),
|
||||
title: __("Review Submitted"),
|
||||
indicator: "green"
|
||||
});
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
<div class="mt-5 item-website-specification">
|
||||
<div class="col-md-11">
|
||||
{% if not show_tabs %}
|
||||
<h3 class="product-title mb-5 mt-8">Product Details</h3>
|
||||
<div class="product-title mb-5 mt-8">
|
||||
Product Details
|
||||
</div>
|
||||
{% endif %}
|
||||
<table class="table table-bordered table-hover">
|
||||
<table class="table">
|
||||
{% for d in website_specifications -%}
|
||||
<tr>
|
||||
<td class="text-muted" style="width: 30%; font-weight: bold;">{{ d.label }}</td>
|
||||
<td>{{ d.description }}</td>
|
||||
<td class="spec-label">{{ d.label }}</td>
|
||||
<td class="spec-content">{{ d.description }}</td>
|
||||
</tr>
|
||||
{%- endfor %}
|
||||
</table>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro product_image(website_image, css_class="product-image", alt="") %}
|
||||
<div class="border text-center rounded {{ css_class }}" style="overflow: hidden;">
|
||||
{% macro product_image(website_image, css_class="product-image", alt="", no_border=False) %}
|
||||
<div class="{{ 'border' if not no_border else ''}} text-center rounded {{ css_class }}" style="overflow: hidden;">
|
||||
{% if website_image %}
|
||||
<img itemprop="image" class="website-image h-100 w-100" alt="{{ alt }}" src="{{ frappe.utils.quoted(website_image) | abs_url }}">
|
||||
{% else %}
|
||||
@@ -208,9 +208,12 @@
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro ratings_with_title(avg_rating, title, size, rating_header_class) -%}
|
||||
<div style="display: flex;">
|
||||
<div class="rating">
|
||||
{%- macro ratings_with_title(avg_rating, title, size, rating_header_class, for_summary=False) -%}
|
||||
<div class="{{ 'd-flex' if not for_summary else '' }}">
|
||||
<p class="mr-4 {{ rating_header_class }}">
|
||||
<span>{{ title }}</span>
|
||||
</p>
|
||||
<div class="rating {{ 'ratings-pill' if for_summary else ''}}">
|
||||
{% for i in range(1,6) %}
|
||||
{% set fill_class = 'star-click' if i <= avg_rating else '' %}
|
||||
<svg class="icon icon-{{ size }} {{ fill_class }}">
|
||||
@@ -218,44 +221,50 @@
|
||||
</svg>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<p class="ml-4 {{ rating_header_class }}">
|
||||
<span>{{ title }}</span>
|
||||
</p>
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating)-%}
|
||||
<!-- Ratings Summary -->
|
||||
<h2 class="reviews-header">
|
||||
{{ _("Customer Ratings") }}
|
||||
</h2>
|
||||
|
||||
{% if reviews %}
|
||||
{% set rating_title = frappe.utils.cstr(average_rating) + " " + _("out of 5") %}
|
||||
{{ ratings_with_title(average_whole_rating, rating_title, "lg", "rating-summary-title") }}
|
||||
{% endif %}
|
||||
|
||||
<!-- Rating Progress Bars -->
|
||||
<div class="rating-progress-bar-section">
|
||||
{% for percent in reviews_per_rating %}
|
||||
<div class="mt-4 col-sm-4 small rating-bar-title">
|
||||
{{ loop.index }} star
|
||||
{%- macro ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating, for_summary=False, total_reviews=None)-%}
|
||||
<div class="rating-summary-section mt-4">
|
||||
<div class="rating-summary-numbers col-3">
|
||||
<h2 style="font-size: 2rem;">
|
||||
{{ average_rating or 0 }}
|
||||
</h2>
|
||||
<div class="mb-2" style="margin-top: -.5rem;">
|
||||
{{ frappe.utils.cstr(total_reviews) + " " + _("ratings") }}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-7">
|
||||
<div class="progress rating-progress-bar" title="{{ percent }} % of reviews are {{ loop.index }} star">
|
||||
<div class="progress-bar" role="progressbar"
|
||||
aria-valuenow="{{ percent }}"
|
||||
aria-valuemin="0" aria-valuemax="100"
|
||||
style="width: {{ percent }}%; background-color: var(--text-on-green);">
|
||||
|
||||
<!-- Ratings Summary -->
|
||||
{% if reviews %}
|
||||
{% set rating_title = frappe.utils.cstr(average_rating) + " " + _("out of 5") if not for_summary else ''%}
|
||||
{{ ratings_with_title(average_whole_rating, rating_title, "md", "rating-summary-title", for_summary) }}
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-2">{{ frappe.utils.cstr(average_rating or 0) + " " + _("out of 5") }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Rating Progress Bars -->
|
||||
<div class="rating-progress-bar-section col-4 ml-4">
|
||||
{% for percent in reviews_per_rating %}
|
||||
<div class="col-sm-4 small rating-bar-title">
|
||||
{{ loop.index }} star
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-7">
|
||||
<div class="progress rating-progress-bar" title="{{ percent }} % of reviews are {{ loop.index }} star">
|
||||
<div class="progress-bar progress-bar-cosmetic" role="progressbar"
|
||||
aria-valuenow="{{ percent }}"
|
||||
aria-valuemin="0" aria-valuemax="100"
|
||||
style="width: {{ percent }}%;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1 small">
|
||||
{{ percent }}%
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1 small">
|
||||
{{ percent }}%
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
|
||||
@@ -264,17 +273,19 @@
|
||||
<div class="user-reviews">
|
||||
{% for review in reviews %}
|
||||
<div class="mb-3 review">
|
||||
{{ ratings_with_title(review.rating, _(review.review_title), "md", "user-review-title") }}
|
||||
{{ ratings_with_title(review.rating, _(review.review_title), "sm", "user-review-title") }}
|
||||
|
||||
<div class="review-signature">
|
||||
<span class="reviewer">{{ _(review.customer) }}</span>
|
||||
<span>{{ review.published_on }}</span>
|
||||
</div>
|
||||
<div class="product-description mb-4 mt-4">
|
||||
<div class="product-description mb-4">
|
||||
<p>
|
||||
{{ _(review.comment) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="review-signature mb-2">
|
||||
<span class="reviewer">{{ _(review.customer) }}</span>
|
||||
<span class="indicator grey" style="--text-on-gray: var(--gray-300);"></span>
|
||||
<span class="reviewer">{{ review.published_on }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@@ -346,4 +357,43 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{%- endmacro -%}
|
||||
|
||||
{%- macro recommended_item_row(item)-%}
|
||||
<div class="recommended-item mb-6 d-flex">
|
||||
<div class="r-item-image">
|
||||
{% if item.website_item_thumbnail %}
|
||||
{{ product_image(item.website_item_thumbnail, alt="item.website_item_name", no_border=True) }}
|
||||
{% else %}
|
||||
<div class = "no-image-r-item">
|
||||
{{ frappe.utils.get_abbr(item.website_item_name) or "NA" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="r-item-info">
|
||||
<a href="/{{ item.route or '#'}}" target="_blank">
|
||||
{% set title = item.website_item_name %}
|
||||
{{ title[:70] + "..." if title|len > 70 else title }}
|
||||
</a>
|
||||
|
||||
{% if item.get('price_info') %}
|
||||
{% set price = item.get('price_info') %}
|
||||
<div class="mt-2">
|
||||
<span class="item-price">
|
||||
{{ price.get('formatted_price') or '' }}
|
||||
</span>
|
||||
|
||||
{% if price.get('formatted_mrp') %}
|
||||
<br>
|
||||
<span class="striked-item-price">
|
||||
<s>MRP {{ price.formatted_mrp }}</s>
|
||||
</span>
|
||||
<span class="in-green">
|
||||
- {{ price.get('formatted_discount_percent') or price.get('formatted_discount_rate')}}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro -%}
|
||||
@@ -4,25 +4,30 @@
|
||||
{% block title %} {{ _("Customer Reviews") }} {% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="product-container col-md-12">
|
||||
<div style="display: flex;">
|
||||
<div class="col-md-4 order-md-1 mt-8" style="max-width: 300px;">
|
||||
{{ ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating) }}
|
||||
<div class="product-container reviews-full-page col-md-12">
|
||||
<!-- Title and Action -->
|
||||
<div class="w-100 mb-6 d-flex">
|
||||
<div class="reviews-header col-9">
|
||||
{{ _("Customer Reviews") }}
|
||||
</div>
|
||||
|
||||
<!-- Write a Review for legitimate users -->
|
||||
{% if frappe.session.user != "Guest" %}
|
||||
<button class="btn btn-light btn-write-review mr-2 mt-4 mb-4 w-100"
|
||||
data-web-item="{{ web_item }}">
|
||||
{{ _("Write a Review") }}
|
||||
</button>
|
||||
{% endif %}
|
||||
<div class="write-a-review-btn col-3">
|
||||
<!-- Write a Review for legitimate users -->
|
||||
{% if frappe.session.user != "Guest" and user_is_customer %}
|
||||
<button class="btn btn-write-review"
|
||||
data-web-item="{{ web_item }}">
|
||||
{{ _("Write a Review") }}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary -->
|
||||
{{ ratings_summary(reviews, reviews_per_rating, average_rating, average_whole_rating, for_summary=True, total_reviews=total_reviews) }}
|
||||
|
||||
|
||||
<!-- Reviews and Comments -->
|
||||
<div class="col-12 order-2 col-md-9 order-md-2 mt-8 ml-16">
|
||||
<h2 class="reviews-header">
|
||||
{{ _("Reviews") }}
|
||||
</h2>
|
||||
<div class="mt-8">
|
||||
{% if reviews %}
|
||||
{{ user_review(reviews) }}
|
||||
|
||||
@@ -40,7 +45,6 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
import frappe
|
||||
from erpnext.e_commerce.doctype.item_review.item_review import get_item_reviews
|
||||
from erpnext.e_commerce.doctype.website_item.website_item import check_if_user_is_customer
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
@@ -11,4 +12,5 @@ def get_context(context):
|
||||
if frappe.form_dict and frappe.form_dict.get("item_code"):
|
||||
context.item_code = frappe.form_dict.get("item_code")
|
||||
context.web_item = frappe.db.get_value("Website Item", {"item_code": context.item_code}, "name")
|
||||
context.user_is_customer = check_if_user_is_customer()
|
||||
get_item_reviews(context.web_item, 0, 10, context)
|
||||
|
||||
Reference in New Issue
Block a user