Browse Source

Merge pull request #55 from abpframework/gterdem/basket_ui_enhancements

eShopOnAbp: Design Basket UI
pull/58/head
Galip Tolga Erdem 5 years ago
committed by GitHub
parent
commit
4369ae71f3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 86
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/Default.cshtml
  2. 67
      apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml
  3. 1
      apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Basket.cshtml
  4. 130
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.css
  5. 44
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.js
  6. 12
      apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/purchase/purchase-widget.css
  7. 11
      shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json
  8. 11
      shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json

86
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Basket/Default.cshtml

@ -8,47 +8,75 @@
@if (!Model.Items.Any())
{
<div class="basket-list">
<p class="text-center">
<strong>
<em>Your basket is empty. Click to a product to add it!</em>
</strong>
</p>
<abp-row>
<abp-card>
<abp-card-body>
<h3 style="text-align: center">@L["EmptyBasket"]</h3>
<br/>
<div style="text-align: center">
<span>
@L["CheckOtherProducts"] <a href="/">@L["ContinueShopping"]</a>
</span>
</div>
</abp-card-body>
</abp-card>
</abp-row>
</div>
}
else
{
<div class="row">
<div class="col-lg-9">
<div class="basket-list">
<div class="basket-list flex-container vertical">
@foreach (var item in Model.Items)
{
<div class="basket-list-item" data-product-id="@item.ProductId">
@if (!item.ImageName.IsNullOrEmpty())
{
<img src="/product-images/@item.ImageName"/>
}
else
{
<img src="/product-images/noimage.jpg"/>
}
@item.ProductName
@if (item.Count > 1)
{
<text> (@("x" + item.Count))</text>
}
- $@item.TotalPrice.ToString("0.00")
<i class="fa fa-remove basket-item-remove" title="@L["RemoveFromBasket"]"></i>
string imageName = item.ImageName.IsNullOrEmpty() ? "/product-images/noimage.jpg" : $"/product-images/{item.ImageName}";
var price = (item.TotalPrice * item.Count).ToString("0.00");
<div class="card basket-list-item" data-product-id="@item.ProductId">
<div class="card-body">
<div class="flex-container horizontal">
<div class="image-container flex-item">
<img class="basket-item-image" src="@imageName"/>
</div>
<div class="flex-item">
<div class="flex-container vertical description-container">
<div class="flex-item description-header">
<span>@item.ProductName</span>
</div>
<div class="flex-item description-price">
<span>$@price</span>
</div>
<div class="flex-item description-cargo">
<span><i class="fa fa-truck"></i> @L["FreeCargo"]</span>
</div>
</div>
</div>
<div class="remove-container hide flex-item">
<i class="fa fa-trash basket-item-remove" title="@L["RemoveFromBasket"]"></i>
</div>
<div class="actions-container flex-item">
<a href="" class="basket-item-increase">
<i class="fa fa-plus-circle"></i>
</a>
<span class="basket-item-count">@item.Count</span>
<a href="" class="basket-item-decrease">
@{
string removeIcon = item.Count <= 1 ? "fa-trash" : "fa-minus-circle";
}
<i class="fa @removeIcon"></i>
</a>
</div>
</div>
</div>
</div>
<hr/>
}
<hr/>
<div class="basket-total-area">
@L["Total"]: $@Model.TotalPrice.ToString("0.00")
</div>
</div>
</div>
<div class="col-lg-3">
@await Component.InvokeAsync(typeof(PurchaseWidgetViewComponent),
new { Basket = Model, ButtonDescription = "CompletePurchase"})
<div class="col-lg-3 sticky">
@await Component.InvokeAsync(typeof(PurchaseWidgetViewComponent),
new {Basket = Model, ButtonDescription = "CompletePurchase"})
</div>
</div>
}

67
apps/public-web/src/EShopOnAbp.PublicWeb/Components/Purchase/Default.cshtml

@ -4,18 +4,59 @@
@model PurchaseWidgetViewComponent.PurchaseViewModel
@inject IStringLocalizer<EShopOnAbpResource> L
<div>
<div class="row">
<h4>Total Selected (@Model.Basket.Items.Count)</h4>
</div>
<div class="row">
<h3>$@Model.Basket.TotalPrice.ToString("0.00")</h3>
</div>
<div class="row">
<form method="post">
@Html.AntiForgeryToken()
<abp-button type="submit" size="Large" class="basket-purchase-button" text="@L[Model.ButtonDescription]" button-type="Primary"/>
</form>
@{
var totalCount = Model?.Basket.Items.Count ?? 0;
var totalPrice = Model.Basket.TotalPrice;
var demoDiscountPercentage = 10;
var discountTotal = totalPrice * demoDiscountPercentage / 100;
var grandTotal = totalPrice - discountTotal;
}
<div class="card">
<div class="card-body">
<div style="text-align: center; padding-top: 25px" >
<div class="row">
<h5>@L["TotalSelected", totalCount]</h5>
</div>
<div class="row">
<h3>$@totalPrice.ToString("0.00")</h3>
</div>
</div>
<hr/>
<div class="row">
<h3>@L["Purchase:OrderSummary"]</h3>
</div>
<div class="summary">
<div class="row">
<div class="col-md-7">@L["Purchase:Products"]:</div>
<div class="col-md-5 m-result">@totalPrice.ToString("0.00") $</div>
</div>
<div class="row">
<div class="col-md-7">@L["Purchase:CargoAndPackaging"]:</div>
<div class="col-md-5 m-result">0.00 $</div>
</div>
<div class="row">
<div class="col-md-7">@L["Purchase:Total"]:</div>
<div class="col-md-5 m-result">@totalPrice.ToString("0.00") $</div>
</div>
<div class="row">
<div class="col-md-7">@L["Purchase:GiftCards"]:</div>
<div class="col-md-5 m-result">@discountTotal.ToString("0.00") $</div>
</div>
</div>
<hr/>
<div class="row">
<div class="col-md-7">
<h5>@L["Purchase:OrderTotal"]:</h5>
</div>
<div class="col-md-5 m-result order-total">
<h5>@grandTotal.ToString("0.00") $</h5>
</div>
</div>
<div class="row" style="padding: 25px; text-align: center">
<form method="post">
@Html.AntiForgeryToken()
<abp-button type="submit" size="Large" class="basket-purchase-button" text="@L[Model.ButtonDescription]" button-type="Warning"/>
</form>
</div>
</div>
</div>

1
apps/public-web/src/EShopOnAbp.PublicWeb/Pages/Basket.cshtml

@ -11,7 +11,6 @@
@inject IStringLocalizer<EShopOnAbpResource> L
<div class="row">
@* <h3 class="pt-5 pb-4 text-center">@L["YourBasket"]</h3> *@
<div id="BasketArea" class="pt-5">
@await Component.InvokeAsync(typeof(BasketWidgetViewComponent))
</div>

130
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.css

@ -1,42 +1,132 @@
.basket-list
{
.basket-list {
}
.basket-list-item {
width:-webkit-fill-available;
background-color: #fff;
padding: 1em;
border: 1px solid #666;
border: 1px solid #eee;
border-radius: 3px;
box-shadow: 0 0 10px rgba(0, 0, 0, .05);
margin-bottom: 0.5em;
transition: all .2s;
cursor: default;
}
.basket-list:hover {
.basket-list-item:hover {
box-shadow: 0 0 20px rgba(0, 0, 0, .1);
}
.basket-list-item {
margin-top: 1em;
.flex-container {
display: flex;
justify-content: space-between;
align-items: center;
}
.horizontal {
flex-direction: row;
width: 100%;
}
.basket-list-item:first-child{
margin-top: 0;
.horizontal .flex-item {
flex: 1;
}
.basket-list-item img {
height: 1em;
.vertical {
flex-direction: column;
}
.basket-total-area
{
margin-bottom: 1em;
.flex-item {
/*background: tomato;*/
padding: 5px;
max-width: 100vh;
margin: 5px;
font-size: 3em;
text-align: center;
}
.image-container {
border: 2px solid #ccc !important;
border-radius: 10px;
background-color: white;
max-width: 3em;
}
.basket-item-image {
min-width: 1em;
width: 2em;
max-width: 80%;
}
.description-container {
align-items: baseline;
}
.description-header {
line-height: 50px;
text-align: left;
font-weight: 500;
font-size: 1.2rem;
margin-bottom: 0.5rem;
overflow: hidden;
}
.description-header > span {
line-height: 20px;
vertical-align: top;
}
.description-price {
text-align: center;
font-size: 1.1rem;
font-weight: bold;
line-height: 30px;
color: rgb(72, 72, 72);
}
.basket-item-remove {
cursor: pointer;
color: red;
opacity: 0.25;
.description-price > span {
line-height: 20px;
vertical-align: top;
}
.description-cargo{
color: #189c38;
text-align: center;
font-size: 1rem;
}
.description-cargo> span {
line-height: 20px;
vertical-align: top;
}
.basket-list-item:hover .basket-item-remove {
.remove-container {
color: #bb2d3b;
max-width: 2em;
font-size: 1.5rem;
line-height: initial;
}
.actions-container {
font-weight: 600;
color: #523e02;
max-width: 2em;
font-size: 1.25rem;
line-height: 40px;
}
.hide {
opacity: 0;
-webkit-transition: all 500ms ease-in-out;
-moz-transition: all 500ms ease-in-out;
-ms-transition: all 500ms ease-in-out;
-o-transition: all 500ms ease-in-out;
transition: all 500ms ease-in-out;
}
.basket-list-item:hover .hide {
opacity: 1.0;
}
.sticky {
position: -webkit-sticky; /* for Safari */
position: sticky;
top: 1rem;
align-self: flex-start; /* <-- this is the fix */
}

44
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/basket/basket-widget.js

@ -1,8 +1,6 @@
(function () {
let anonymousId = abp.utils.getCookieValue("anonymous_id");
abp.widgets.BasketWidget = function ($wrapper) {
var widgetManager = $wrapper.data('abp-widget-manager');
@ -10,23 +8,55 @@
$wrapper
.find('.basket-item-remove')
.click(function () {
var $this = $(this);
var productId = $this.parent('.basket-list-item').attr('data-product-id');
let $this = $(this);
let productId = $this.parents('.basket-list-item').attr('data-product-id');
eShopOnAbp.basketService.basket.removeProduct({
productId: productId,
anonymousId: anonymousId
}).then(function () {
widgetManager.refresh();
$('.abp-widget-wrapper[data-widget-name="CartWidget"]')
.data('abp-widget-manager')
.refresh();
abp.notify.info("Removed the product from your basket.", "Removed basket item");
});
});
$wrapper
.find('.basket-item-increase')
.click(function (e) {
e.preventDefault();
let $this = $(this);
let productId = $this.parents('.basket-list-item').attr('data-product-id');
eShopOnAbp.basketService.basket.addProduct({
productId: productId,
count: 1,
anonymousId: anonymousId
}).then(function () {
widgetManager.refresh();
$('.abp-widget-wrapper[data-widget-name="CartWidget"]')
.data('abp-widget-manager')
.refresh();
});
});
$wrapper
.find('.basket-item-decrease')
.click(function (e) {
e.preventDefault();
let $this = $(this);
let productId = $this.parents('.basket-list-item').attr('data-product-id');
eShopOnAbp.basketService.basket.removeProduct({
productId: productId,
count: 1,
anonymousId: anonymousId
}).then(function () {
widgetManager.refresh();
$('.abp-widget-wrapper[data-widget-name="CartWidget"]')
.data('abp-widget-manager')
.refresh();
});
});
};
return {

12
apps/public-web/src/EShopOnAbp.PublicWeb/wwwroot/components/purchase/purchase-widget.css

@ -0,0 +1,12 @@
.m-result {
text-align: end;
}
.summary {
color: #0F1111;
font-size: 1rem;
}
.order-total {
font-size: 1.2rem;
}

11
shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/en.json

@ -4,8 +4,19 @@
"Menu:Home": "Home",
"Login": "Login",
"YourBasket": "Your Basket",
"EmptyBasket": "Empyt basket",
"CheckOtherProducts": "You can check the recommended products below or",
"ContinueShopping": "continue shopping.",
"Total": "Total",
"TotalSelected": "Total Selected ({0})",
"OurProducts": "Our Products",
"FreeCargo": "Free Cargo",
"Purchase:GiftCards":"Gift Cards",
"Purchase:CargoAndPackaging": "Cargo & Packaging",
"Purchase:Total": "Total",
"Purchase:OrderSummary": "Order Summary",
"Purchase:Products": "Products",
"Purchase:OrderTotal": "Order Total",
"CatalogServiceNotAvailable": "Catalog Service is unavailable right now! Try again later...",
"StockCount": "Stock Count",
"RemoveFromBasket": "Remove from basket",

11
shared/EShopOnAbp.Shared.Localization/Localization/EShopOnAbp/tr.json

@ -4,8 +4,19 @@
"Menu:Home": "Ana Sayfa",
"Login": "Giriş",
"YourBasket": "Sepetiniz",
"EmptyBasket": "Sepetiniz boş",
"CheckOtherProducts": "Aşağıdaki önerilen öğeleri takip edebilirsiniz veya",
"ContinueShopping": "alışverişe devam edin.",
"Total": "Toplam",
"TotalSelected": "Seçilen Ürünler ({0})",
"OurProducts": "Ürünlerimiz",
"FreeCargo": "Ücretsiz Kargo",
"Purchase:GiftCards":"Hediye Çekleri",
"Purchase:CargoAndPackaging": "Kargo ve Paketleme",
"Purchase:Total": "Toplam",
"Purchase:OrderSummary": "Sipariş Özeti",
"Purchase:Products": "Ürünler",
"Purchase:OrderTotal": "Sipariş Toplamı",
"CatalogServiceNotAvailable": "Ürün servisine şu anda ulaşılamıyor! Lütfen sonra tekrar deneyiniz...",
"StockCount": "Stokta",
"RemoveFromBasket": "Sepetten kaldır",

Loading…
Cancel
Save