feat: Cart minor UI/UX Refresh

- Added Setting to show or hide price if checkout is disabled
- Show Web Item name in cart instead of Desk Item name
- Cart minor UI Refresh: added images in cart
- Cart minor UI Refresh: repositioned remove button and redesigned
- Cart minor UI Refresh: Payment Summary section
- Cart minor UI Refresh: Disable input on free item
- Cart minor UI Refresh: Add address button in cards
- New file for cart payment summary UI with coupon code (old)
This commit is contained in:
marination 2021-07-15 20:09:02 +05:30
parent ef4579e4eb
commit 929a24ea5c
9 changed files with 347 additions and 127 deletions

View File

@ -39,8 +39,9 @@
"quotation_series",
"checkout_settings_section",
"enable_checkout",
"save_quotations_as_draft",
"show_price_in_quotation",
"column_break_27",
"save_quotations_as_draft",
"payment_gateway_account",
"payment_success_url",
"filter_categories_section",
@ -379,12 +380,19 @@
"fieldname": "enable_recommendations",
"fieldtype": "Check",
"label": "Enable Recommendations"
},
{
"default": "0",
"depends_on": "eval: doc.enable_checkout == 0",
"fieldname": "show_price_in_quotation",
"fieldtype": "Check",
"label": "Show Price in Quotation"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2021-07-13 16:30:14.715949",
"modified": "2021-07-15 16:50:50.087281",
"modified_by": "Administrator",
"module": "E-commerce",
"name": "E Commerce Settings",

View File

@ -271,8 +271,12 @@ def guess_territory():
def decorate_quotation_doc(doc):
for d in doc.get("items", []):
d.update(frappe.db.get_value("Website Item", {"item_code": d.item_code},
["thumbnail", "website_image", "description", "route"], as_dict=True))
d.update(frappe.db.get_value(
"Website Item",
{"item_code": d.item_code},
["web_item_name", "thumbnail", "website_image", "description", "route"],
as_dict=True)
)
return doc

View File

@ -121,7 +121,7 @@ $.extend(shopping_cart, {
$(".cart-items").html('Cart is Empty');
$(".cart-tax-items").hide();
$(".btn-place-order").hide();
$(".cart-addresses").hide();
$(".cart-payment-addresses").hide();
}
else {
$cart.css("display", "inline");

View File

@ -628,6 +628,7 @@ body.product-page {
display: flex;
flex-direction: column;
justify-content: space-between;
height: fit-content;
}
.cart-items-header {
@ -656,8 +657,29 @@ body.product-page {
color: var(--text-color);
}
.cart-item-image {
width: 20%;
min-width: 100px;
img {
max-height: 112px;
}
.no-image-cart-item {
max-height: 112px;
display: flex; justify-content: center;
background-color: var(--gray-200);
align-items: center;
color: var(--gray-400);
margin-top: .15rem;
border-radius: 6px;
height: 100%;
font-size: 24px;
}
}
.cart-items {
.item-title {
width: 80%;
font-size: 14px;
font-weight: 500;
color: var(--text-color);
@ -688,9 +710,18 @@ body.product-page {
color: var(--text-muted);
}
textarea {
width: 40%;
.free-tag {
padding: 4px 8px;
border-radius: 4px;
background-color: var(--dark-green-50);
}
textarea {
width: 80%;
height: 60px;
font-size: 14px;
}
}
.cart-tax-items {
@ -715,52 +746,95 @@ body.product-page {
}
.remove-cart-item {
border-radius: 50%;
border-radius: 6px;
border: 1px solid var(--gray-100);
width: 22px;
height: 22px;
background-color: var(--gray-200);
width: 28px;
height: 28px;
font-weight: 300;
color: var(--gray-700);
background-color: var(--gray-100);
float: right;
cursor: pointer;
margin-top: .25rem;
justify-content: center;
}
.remove-cart-item-logo {
margin-bottom: 6px;
margin-left: 1px;
}
.totals {
padding-right: 4rem;
@media (max-width: 992px) {
padding-right: 1rem;
}
margin-top: 2px;
margin-left: 2.2px;
fill: var(--gray-700) !important;
}
}
.cart-addresses {
.cart-payment-addresses {
hr {
border-color: var(--border-color);
}
}
.payment-summary {
h6 {
padding-bottom: 1rem;
border-bottom: solid 1px var(--gray-200);
}
table {
font-size: 14px;
td {
padding: 0;
padding-top: 0.35rem !important;
border: none !important;
}
&.grand-total {
border-top: solid 1px var(--gray-200);
}
}
.bill-label {
color: var(--gray-600);
}
.bill-content {
font-weight: 500;
&.net-total {
font-size: 16px;
font-weight: 600;
}
}
.btn-coupon-code {
font-size: 14px;
border: dashed 1px var(--gray-400);
box-shadow: none;
}
}
.number-spinner {
width: 75%;
min-width: 105px;
.cart-btn {
border: none;
background: var(--primary-color);
color: white;
background: var(--gray-100);
color: var(--gray-500);
box-shadow: none;
width: 24px;
height: 28px;
align-items: center;
justify-content: center;
display: flex;
font-size: 20px;
font-weight: 300;
color: var(--gray-700);
}
.cart-qty {
height: 28px;
font-size: 13px;
&:disabled {
background: var(--gray-100);
opacity: 0.65;
}
}
}
@ -802,19 +876,29 @@ body.product-page {
font-size: 13px;
svg use {
stroke: var(--blue-500);
stroke: var(--primary-color);
}
}
.btn-change-address {
color: var(--blue-500);
border: 1px solid var(--primary-color);
color: var(--primary-color);
box-shadow: none;
}
}
.address-header {
margin-top: .15rem;padding: 0;
}
.btn-new-address {
float: right;
font-size: 15px !important;
color: var(--primary-color) !important;
}
.btn-new-address:hover, .btn-change-address:hover {
box-shadow: none;
color: var(--blue-500) !important;
border: 1px solid var(--blue-500);
color: var(--primary-color) !important;
}
.modal .address-card {

View File

@ -649,7 +649,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2021-02-23 01:13:54.670763",
"modified": "2021-07-15 12:40:51.074820",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",

View File

@ -4,18 +4,14 @@
{% set select_address = True %}
{% endif %}
{% set show_coupon_code = frappe.db.get_single_value('E Commerce Settings', 'show_apply_coupon_code_in_website') %}
{% if show_coupon_code == 1%}
<div class="mb-3">
<div class="row no-gutters">
<input type="text" class="txtcoupon form-control mr-3 w-50 font-md" placeholder="Enter Coupon Code" name="txtcouponcode" ></input>
<button class="btn btn-primary btn-sm bt-coupon font-md">{{ _("Apply Coupon Code") }}</button>
<input type="hidden" class="txtreferral_sales_partner font-md" placeholder="Enter Sales Partner" name="txtreferral_sales_partner" type="text"></input>
</div>
</div>
{% endif %}
<div class="mb-3 frappe-card p-5" data-section="shipping-address">
<h6>{{ _("Shipping Address") }}</h6>
<div class="d-flex">
<div class="col-6 address-header"><h6>{{ _("Shipping Address") }}</h6></div>
<div class="col-6" style="padding: 0;">
<a class="ml-4 btn-new-address" role="button">{{ _("Add a new address") }}</a>
</div>
</div>
<hr>
{% for address in shipping_addresses %}
{% if doc.shipping_address_name == address.name %}
@ -27,28 +23,36 @@
{% endif %}
{% endfor %}
</div>
<!-- Billing Address -->
<div class="checkbox ml-1 mb-2">
<label for="input_same_billing">
<input type="checkbox" class="product-filter" id="input_same_billing" checked style="width: 14px !important">
<span class="label-area font-md">{{ _('Billing Address is same as Shipping Address') }}</span>
</label>
</div>
<div class="mb-3 frappe-card p-5" data-section="billing-address">
<h6>{{ _("Billing Address") }}</h6>
<hr>
{% for address in billing_addresses %}
{% if doc.customer_address == address.name %}
<div class="row no-gutters" data-fieldname="customer_address">
<div class="w-100 address-container" data-address-name="{{address.name}}" data-address-type="billing" data-active>
{% include "templates/includes/cart/address_card.html" %}
</div>
{% if billing_addresses %}
<div class="mb-3 frappe-card p-5" data-section="billing-address">
<div class="d-flex">
<div class="col-6 address-header"><h6>{{ _("Billing Address") }}</h6></div>
<div class="col-6" style="padding: 0;">
<a class="ml-4 btn-new-address" role="button">{{ _("Add a new address") }}</a>
</div>
</div>
{% endif %}
{% endfor %}
</div>
<button class="btn btn-outline-primary btn-sm mt-1 btn-new-address bg-white font-md">
{{ _("Add a new address") }}
</button>
<hr>
{% for address in billing_addresses %}
{% if doc.customer_address == address.name %}
<div class="row no-gutters" data-fieldname="customer_address">
<div class="w-100 address-container" data-address-name="{{address.name}}" data-address-type="billing" data-active>
{% include "templates/includes/cart/address_card.html" %}
</div>
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
<script>
frappe.ready(() => {

View File

@ -1,3 +1,5 @@
{% from "erpnext/templates/includes/macros.html" import product_image %}
{% macro item_subtotal(item) %}
<div>
{{ item.get_formatted('amount') }}
@ -5,10 +7,7 @@
{% if item.is_free_item %}
<div class="text-success mt-4">
<span style="
padding: 4px 8px;
border-radius: 4px;
border: 1px dashed">
<span class="free-tag">
{{ _('FREE') }}
</span>
</div>
@ -21,43 +20,83 @@
{% for d in doc.items %}
<tr data-name="{{ d.name }}">
<td>
<div class="item-title mb-1 mr-3">
{{ d.item_name }}
</div>
<div class="item-subtitle mr-2">
{{ d.item_code }}
</div>
{%- set variant_of = frappe.db.get_value('Item', d.item_code, 'variant_of') %}
{% if variant_of %}
<span class="item-subtitle mr-2">
{{ _('Variant of') }}
<a href="{{frappe.db.get_value('Website Item', {'item_code': variant_of}, 'route') or '#'}}">
{{ variant_of }}
</a>
</span>
{% endif %}
<div class="mt-2 notes">
<textarea data-item-code="{{d.item_code}}" class="form-control" rows="2" placeholder="{{ _('Add notes') }}">
{{d.additional_notes or ''}}
</textarea>
<td style="width: 60%;">
<div class="d-flex">
<div class="cart-item-image mr-4">
{% if d.thumbnail %}
{{ product_image(d.thumbnail, alt="d.web_item_name", no_border=True) }}
{% else %}
<div class = "no-image-cart-item">
{{ frappe.utils.get_abbr(d.web_item_name) or "NA" }}
</div>
{% endif %}
</div>
<div class="d-flex w-100" style="flex-direction: column;">
<div class="item-title mb-1 mr-3">
{{ d.get("web_item_name") or d.item_name }}
</div>
<div class="item-subtitle mr-2">
{{ d.item_code }}
</div>
{%- set variant_of = frappe.db.get_value('Item', d.item_code, 'variant_of') %}
{% if variant_of %}
<span class="item-subtitle mr-2">
{{ _('Variant of') }}
<a href="{{frappe.db.get_value('Website Item', {'item_code': variant_of}, 'route') or '#'}}">
{{ variant_of }}
</a>
</span>
{% endif %}
<div class="mt-2 notes">
<textarea data-item-code="{{d.item_code}}" class="form-control" rows="2" placeholder="{{ _('Add notes') }}">
{{d.additional_notes or ''}}
</textarea>
</div>
</div>
</div>
</td>
<!-- Qty column -->
<td class="text-right">
<div class="input-group number-spinner mt-1 mb-4">
<span class="input-group-prepend d-sm-inline-block">
<button class="btn cart-btn" data-dir="dwn"></button>
</span>
<input class="form-control text-center cart-qty" value="{{ d.get_formatted('qty') }}" data-item-code="{{ d.item_code }}">
<span class="input-group-append d-sm-inline-block">
<button class="btn cart-btn" data-dir="up">+</button>
</span>
<td class="text-right" style="width: 25%;">
<div class="d-flex">
{% set disabled = 'disabled' if d.is_free_item else '' %}
<div class="input-group number-spinner mt-1 mb-4">
<span class="input-group-prepend d-sm-inline-block">
<button class="btn cart-btn" data-dir="dwn" {{ disabled }}>
{{ '' if not d.is_free_item else ''}}
</button>
</span>
<input class="form-control text-center cart-qty" value="{{ d.get_formatted('qty') }}" data-item-code="{{ d.item_code }}"
style="max-width: 70px;" {{ disabled }}>
<span class="input-group-append d-sm-inline-block">
<button class="btn cart-btn" data-dir="up" {{ disabled }}>
{{ '+' if not d.is_free_item else ''}}
</button>
</span>
</div>
<div>
{% if not d.is_free_item %}
<div class="remove-cart-item column-sm-view d-flex" data-item-code="{{ d.item_code }}">
<span>
<svg class="icon sm remove-cart-item-logo"
width="18" height="18" viewBox="0 0 18 18"
xmlns="http://www.w3.org/2000/svg" id="icon-close">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.146 11.217a.5.5 0 1 0 .708.708l3.182-3.182 3.181 3.182a.5.5 0 1 0 .708-.708l-3.182-3.18 3.182-3.182a.5.5 0 1 0-.708-.708l-3.18 3.181-3.183-3.182a.5.5 0 0 0-.708.708l3.182 3.182-3.182 3.181z" stroke-width="0"></path>
</svg>
</span>
</div>
{% endif %}
</div>
</div>
<!-- Shown on mobile view, else hidden -->
{% if cart_settings.enable_checkout %}
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
<div class="text-right sm-item-subtotal">
{{ item_subtotal(d) }}
</div>
@ -65,25 +104,10 @@
</td>
<!-- Subtotal column -->
{% if cart_settings.enable_checkout %}
<td class="text-right item-subtotal column-sm-view">
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
<td class="text-right item-subtotal column-sm-view w-100">
{{ item_subtotal(d) }}
</td>
{% endif %}
<!-- Show close button irrespective except on free items -->
<td class="text-right">
{% if not d.is_free_item %}
<div class="ml-1 remove-cart-item column-sm-view" data-item-code="{{ d.item_code }}">
<span>
<svg class="icon sm remove-cart-item-logo"
width="18" height="18" viewBox="0 0 18 18"
xmlns="http://www.w3.org/2000/svg" id="icon-close">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.146 11.217a.5.5 0 1 0 .708.708l3.182-3.182 3.181 3.182a.5.5 0 1 0 .708-.708l-3.182-3.18 3.182-3.182a.5.5 0 1 0-.708-.708l-3.18 3.181-3.183-3.182a.5.5 0 0 0-.708.708l3.182 3.182-3.182 3.181z" stroke-width="0"></path>
</svg>
</span>
</div>
{% endif %}
</td>
</tr>
{% endfor %}

View File

@ -0,0 +1,80 @@
<!-- Payment -->
<div class="mb-3 frappe-card p-5 payment-summary">
<h6>
{{ _("Payment Summary") }}
</h6>
<div class="card h-100">
<div class="card-body p-0">
<table class="table w-100">
<tr>
<td class="bill-label">{{ _("Net Total (") + frappe.utils.cstr(doc.items|len) + _(" Items)") }}</td>
<td class="bill-content net-total text-right">{{ doc.get_formatted("net_total") }}</td>
</tr>
<!-- taxes -->
{% for d in doc.taxes %}
{% if d.base_tax_amount %}
<tr>
<td class="bill-label">
{{ d.description }}
</td>
<td class="bill-content text-right">
{{ d.get_formatted("base_tax_amount") }}
</td>
</tr>
{% endif %}
{% endfor %}
</table>
<!-- TODO: Apply Coupon Dialog-->
<!-- {% set show_coupon_code = cart_settings.show_apply_coupon_code_in_website and cart_settings.enable_checkout %}
{% if show_coupon_code %}
<button class="btn btn-coupon-code w-100 text-left">
<svg width="24" height="24" viewBox="0 0 24 24" stroke="var(--gray-600)" 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"/>
<path d="M15 9L9 15" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10.5 9.5C10.5 10.0523 10.0523 10.5 9.5 10.5C8.94772 10.5 8.5 10.0523 8.5 9.5C8.5 8.94772 8.94772 8.5 9.5 8.5C10.0523 8.5 10.5 8.94772 10.5 9.5Z" fill="white" stroke-linecap="round" stroke-linejoin="round"/>
<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>
<span class="ml-2">Apply Coupon</span>
</button>
{% endif %} -->
<table class="table w-100 grand-total mt-6">
<tr>
<td class="bill-content net-total">{{ _("Grand Total") }}</td>
<td class="bill-content net-total text-right">{{ doc.get_formatted("grand_total") }}</td>
</tr>
</table>
{% if cart_settings.enable_checkout %}
<button class="btn btn-primary btn-place-order font-md w-100" type="button">
{{ _('Place Order') }}
</button>
{% else %}
<button class="btn btn-primary btn-request-for-quotation font-md w-100" type="button">
{{ _('Request for Quote') }}
</button>
{% endif %}
</div>
</div>
</div>
<!-- TODO: Apply Coupon Dialog-->
<!-- <script>
frappe.ready(() => {
$('.btn-coupon-code').click((e) => {
const $btn = $(e.currentTarget);
const d = new frappe.ui.Dialog({
title: __('Coupons'),
fields: [
{
fieldname: 'coupons_area',
fieldtype: 'HTML'
}
]
});
d.show();
});
});
</script> -->

View File

@ -32,8 +32,8 @@
<tr>
<th class="item-column">{{ _('Item') }}</th>
<th width="20%">{{ _('Quantity') }}</th>
{% if cart_settings.enable_checkout %}
<th width="20" class="text-right column-sm-view">{{ _('Subtotal') }}</th>
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
<th width="20" class="text-right column-sm-view">{{ _('Subtotal') }}</th>
{% endif %}
<th width="10%" class="column-sm-view"></th>
</tr>
@ -41,10 +41,19 @@
<tbody class="cart-items">
{% include "templates/includes/cart/cart_items.html" %}
</tbody>
{% if cart_settings.enable_checkout %}
<tfoot class="cart-tax-items">
{% include "templates/includes/order/order_taxes.html" %}
</tfoot>
{% if cart_settings.enable_checkout or cart_settings.show_price_in_quotation %}
<tfoot class="cart-tax-items">
<tr>
<th></th>
<th class="text-left item-grand-total" colspan="1">
{{ _("Total") }}
</th>
<th class="text-left item-grand-total totals" colspan="3">
{{ doc.get_formatted("total") }}
</th>
</tr>
</tfoot>
{% endif %}
</table>
</div>
@ -52,12 +61,12 @@
<div class="row mt-2">
<div class="col-3">
{% if cart_settings.enable_checkout %}
<a class="btn btn-outline-primary font-md" href="/orders">
<a class="btn btn-primary-light font-md" href="/orders">
{{ _('Past Orders') }}
</a>
{% else %}
<a class="btn btn-outline-primary font-md" href="/quotations">
{{ _('See past quotations') }}
<a class="btn btn-primary-light font-md" href="/quotations">
{{ _('Past Quotes') }}
</a>
{% endif %}
</div>
@ -65,17 +74,8 @@
{% if doc.items %}
<div class="place-order-container">
<a class="btn btn-primary-light mr-2 font-md" href="/all-products">
{{ _('Back to Shop') }}
{{ _('Continue Shopping') }}
</a>
{% if cart_settings.enable_checkout %}
<button class="btn btn-primary btn-place-order font-md" type="button">
{{ _('Place Order') }}
</button>
{% else %}
<button class="btn btn-primary btn-request-for-quotation font-md" type="button">
{{ _('Request for Quotation') }}
</button>
{% endif %}
</div>
{% endif %}
</div>
@ -112,9 +112,25 @@
</div>
<div class="col-md-4">
<div class="cart-addresses">
<div class="cart-payment-addresses">
<!-- Apply Coupon Code -->
{% set show_coupon_code = cart_settings.show_apply_coupon_code_in_website and cart_settings.enable_checkout %}
{% if show_coupon_code == 1%}
<div class="mb-3">
<div class="row no-gutters">
<input type="text" class="txtcoupon form-control mr-3 w-50 font-md" placeholder="Enter Coupon Code" name="txtcouponcode" ></input>
<button class="btn btn-primary btn-sm bt-coupon font-md">{{ _("Apply Coupon Code") }}</button>
<input type="hidden" class="txtreferral_sales_partner font-md" placeholder="Enter Sales Partner" name="txtreferral_sales_partner" type="text"></input>
</div>
</div>
{% endif %}
{% if cart_settings.enable_checkout %}
{% include "templates/includes/cart/cart_payment_summary.html" %}
{% endif %}
{% include "templates/includes/cart/cart_address.html" %}
</div>
</div>
</div>
{% endif %}
</div>