Adding Order Features (#47)

* Working on order model binding from checkout page - WIP

* Small layout tweaks (#43)

* Updating quantities implemented.

* Fixed basket widget count
This commit is contained in:
Steve Smith
2017-09-13 18:10:19 -04:00
committed by GitHub
parent ed5d17672d
commit db6ad75aee
9 changed files with 188 additions and 117 deletions

View File

@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Identity;
using Infrastructure.Identity;
using System;
using Web;
using System.Collections.Generic;
namespace Microsoft.eShopWeb.Controllers
{
@@ -17,14 +18,17 @@ namespace Microsoft.eShopWeb.Controllers
private const string _basketSessionKey = "basketId";
private readonly IUriComposer _uriComposer;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IAppLogger<BasketController> _logger;
public BasketController(IBasketService basketService,
IUriComposer uriComposer,
SignInManager<ApplicationUser> signInManager)
SignInManager<ApplicationUser> signInManager,
IAppLogger<BasketController> logger)
{
_basketService = basketService;
_uriComposer = uriComposer;
_signInManager = signInManager;
_logger = logger;
}
[HttpGet]
@@ -35,6 +39,16 @@ namespace Microsoft.eShopWeb.Controllers
return View(basketModel);
}
[HttpPost]
public async Task<IActionResult> Index(Dictionary<string, int> items)
{
var basketViewModel = await GetBasketViewModelAsync();
await _basketService.SetQuantities(basketViewModel.Id, items);
return View(await GetBasketViewModelAsync());
}
// POST: /Basket/AddToBasket
[HttpPost]
public async Task<IActionResult> AddToBasket(CatalogItemViewModel productDetails)
@@ -51,9 +65,17 @@ namespace Microsoft.eShopWeb.Controllers
}
[HttpPost]
public async Task<IActionResult> Checkout()
public async Task<IActionResult> Checkout(List<BasketItemViewModel> model)
{
// TODO: Get model binding working with collection of items
var basket = await GetBasketViewModelAsync();
//await _basketService.SetQuantities(basket.Id, quantities);
foreach (var item in basket.Items)
{
_logger.LogWarning($"Id: {item.Id}; Qty: {item.Quantity}");
}
// redirect to OrdersController
await _basketService.Checkout(basket.Id);

View File

@@ -1,4 +1,6 @@
using Microsoft.eShopWeb.ViewModels;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.ViewModels;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ApplicationCore.Interfaces
@@ -8,6 +10,7 @@ namespace ApplicationCore.Interfaces
Task<BasketViewModel> GetOrCreateBasketForUser(string userName);
Task TransferBasketAsync(string anonymousId, string userName);
Task AddItemToBasket(int basketId, int catalogItemId, decimal price, int quantity);
Task SetQuantities(int basketId, Dictionary<string, int> quantities);
Task Checkout(int basketId);
}
}

View File

@@ -12,14 +12,17 @@ namespace Web.Services
{
private readonly IAsyncRepository<Basket> _basketRepository;
private readonly IUriComposer _uriComposer;
private readonly IAppLogger<BasketService> _logger;
private readonly IRepository<CatalogItem> _itemRepository;
public BasketService(IAsyncRepository<Basket> basketRepository,
IRepository<CatalogItem> itemRepository,
IUriComposer uriComposer)
IUriComposer uriComposer,
IAppLogger<BasketService> logger)
{
_basketRepository = basketRepository;
_uriComposer = uriComposer;
this._logger = logger;
_itemRepository = itemRepository;
}
@@ -81,6 +84,20 @@ namespace Web.Services
await _basketRepository.UpdateAsync(basket);
}
public async Task SetQuantities(int basketId, Dictionary<string,int> quantities)
{
var basket = await _basketRepository.GetByIdAsync(basketId);
foreach (var item in basket.Items)
{
if (quantities.TryGetValue(item.Id.ToString(), out var quantity))
{
_logger.LogWarning($"Updating quantity of item ID:{item.Id} to {quantity}.");
item.Quantity = quantity;
}
}
await _basketRepository.UpdateAsync(basket);
}
public async Task Checkout(int basketId)
{
var basket = await _basketRepository.GetByIdAsync(basketId);

View File

@@ -1,27 +1,52 @@
using ApplicationCore.Interfaces;
using Infrastructure.Identity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopWeb.ViewModels;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Web.ViewComponents
{
public class Basket : ViewComponent
{
private readonly IBasketService _cartSvc;
private readonly IBasketService _basketService;
private readonly SignInManager<ApplicationUser> _signInManager;
public Basket(IBasketService cartSvc) => _cartSvc = cartSvc;
public Basket(IBasketService basketService,
SignInManager<ApplicationUser> signInManager)
{
_basketService = basketService;
_signInManager = signInManager;
}
public async Task<IViewComponentResult> InvokeAsync(string userName)
{
var vm = new BasketComponentViewModel();
var itemsInCart = await ItemsInBasketAsync(userName);
vm.ItemsCount = itemsInCart;
vm.ItemsCount = (await GetBasketViewModelAsync()).Items.Sum(i => i.Quantity);
return View(vm);
}
private async Task<int> ItemsInBasketAsync(string userName)
private async Task<BasketViewModel> GetBasketViewModelAsync()
{
var basket = await _cartSvc.GetOrCreateBasketForUser(userName);
return basket.Items.Count;
if (_signInManager.IsSignedIn(HttpContext.User))
{
return await _basketService.GetOrCreateBasketForUser(User.Identity.Name);
}
string anonymousId = GetBasketIdFromCookie();
if (anonymousId == null) return new BasketViewModel();
return await _basketService.GetOrCreateBasketForUser(anonymousId);
}
private string GetBasketIdFromCookie()
{
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
{
return Request.Cookies[Constants.BASKET_COOKIENAME];
}
return null;
}
}
}

View File

@@ -1,7 +1,7 @@
@using Microsoft.eShopWeb.ViewModels
@model BasketViewModel
@{
ViewData["Title"] = "Basket";
@model BasketViewModel
}
<section class="esh-catalog-hero">
<div class="container">
@@ -23,9 +23,10 @@
<section class="esh-basket-title col-xs-2">Cost</section>
</article>
<div class="esh-catalog-items row">
@foreach (var item in Model.Items)
@for (int i=0; i< Model.Items.Count; i++)
{
<article class="esh-basket-items row">
var item = Model.Items[i];
<article class="esh-basket-items row">
<div>
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
<img class="esh-basket-image" src="@item.PictureUrl" />
@@ -33,8 +34,8 @@
<section class="esh-basket-item esh-basket-item--middle col-xs-3">@item.ProductName</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">$ @item.UnitPrice.ToString("N2")</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">
<input type="hidden" name="@("quantities[" + item.Id +"].Key")" value="@item.Id" />
<input type="number" class="esh-basket-input" min="1" name="@("quantities[" + item.Id +"].Value")" value="@item.Quantity" />
<input type="hidden" name="@("Items[" + i + "].Key")" value="@item.Id" />
<input type="number" class="esh-basket-input" min="1" name="@("Items[" + i + "].Value")" value="@item.Quantity" />
</section>
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")</section>
</div>
@@ -65,7 +66,9 @@
</article>
</div>
}
<section class="esh-basket-item col-xs-push-9 col-xs-3">
<section class="esh-basket-item col-xs-push-8 col-xs-4">
<button class="btn esh-basket-checkout" name="updatebutton" value="" type="submit"
asp-action="Update">[ Update ]</button>
<input type="submit" asp-action="Checkout"
class="btn esh-basket-checkout"
value="[ Checkout ]" name="action" />

View File

@@ -1,32 +1,38 @@
@model PaginationInfoViewModel
<div class="esh-pager">
<div class="container">
<article class="esh-pager-wrapper row">
<nav>
<a class="esh-pager-item esh-pager-item--navigable @Model.Previous"
id="Previous"
asp-controller="Catalog"
asp-action="Index"
asp-route-page="@(Model.ActualPage -1)"
aria-label="Previous">
Previous
</a>
<span class="esh-pager-item">
Showing @Model.ItemsPerPage of @Model.TotalItems products - Page @(Model.ActualPage + 1) - @Model.TotalPages
</span>
<a class="esh-pager-item esh-pager-item--navigable @Model.Next"
id="Next"
asp-controller="Catalog"
asp-action="Index"
asp-route-page="@(Model.ActualPage + 1)"
aria-label="Next">
Next
</a>
</nav>
</article>
</div>
<div class="container-fluid">
<article class="esh-pager-wrapper row">
<nav>
<div class="col-md-2 col-xs-12">
<a class="esh-pager-item-left esh-pager-item--navigable @Model.Previous"
id="Previous"
asp-controller="Catalog"
asp-action="Index"
asp-route-page="@(Model.ActualPage - 1)"
aria-label="Previous">
Previous
</a>
</div>
<div class="col-md-8 col-xs-12">
<span class="esh-pager-item">
Showing @Model.ItemsPerPage of @Model.TotalItems products - Page @(Model.ActualPage + 1) - @Model.TotalPages
</span>
</div>
<div class="col-md-2 col-xs-12">
<a class="esh-pager-item-right esh-pager-item--navigable @Model.Next"
id="Next"
asp-controller="Catalog"
asp-action="Index"
asp-route-page="@(Model.ActualPage + 1)"
aria-label="Next">
Next
</a>
</div>
</nav>
</article>
</div>
</div>

View File

@@ -1,89 +1,79 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Microsoft.eShopOnWeb</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Microsoft.eShopOnWeb</title>
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/app.css" />
<link rel="stylesheet" href="~/css/app.component.css" />
@*<link rel="stylesheet" href="~/css/shared/components/header/header.css" />
<link rel="stylesheet" href="~/css/shared/components/identity/identity.css" />
<link rel="stylesheet" href="~/css/campaigns/campaigns.component.css" />
<link rel="stylesheet" href="~/css/shared/components/pager/pager.css" />*@
<link rel="stylesheet" href="~/css/basket/basket.component.css" />
<link rel="stylesheet" href="~/css/basket/basket-status/basket-status.component.css" />
<link rel="stylesheet" href="~/css/catalog/catalog.component.css" />
@*<link rel="stylesheet" href="~/css/orders/orders.component.css" />
<link rel="stylesheet" href="~/css/orders/orders-detail/orders-detail.component.css" />
<link rel="stylesheet" href="~/css/orders/orders-new/orders-new.component.css" />
<link rel="stylesheet" href="~/css/override.css" type="text/css" />*@
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/app.min.css" asp-append-version="true" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/app.min.css" asp-append-version="true" />
</environment>
<link rel="stylesheet" href="~/css/app.component.css" />
<link rel="stylesheet" href="~/css/basket/basket.component.css" />
<link rel="stylesheet" href="~/css/catalog/pager.css" />
<link rel="stylesheet" href="~/css/catalog/catalog.component.css" />
<link rel="stylesheet" href="~/css/catalog/catalog.component.css" />
<link rel="stylesheet" href="~/css/basket/basket-status/basket-status.component.css" />
</head>
<body>
<header class="navbar navbar-light navbar-static-top">
<div class="container">
<article class="row">
<header class="navbar navbar-light navbar-static-top">
<div class="container">
<article class="row">
<section class="col-lg-7 col-md-6 col-xs-12">
<a class="navbar-brand" routerLink="catalog">
<a asp-area="" asp-controller="Catalog" asp-action="Index">
<img src="../images/brand.png" />
</a>
</section>
@await Html.PartialAsync("_LoginPartial")
<section class="col-lg-1 col-xs-12"><a asp-controller="Basket" asp-action="Index">Basket</a></section>
<section class="col-lg-7 col-md-6 col-xs-12">
<a asp-area="" asp-controller="Catalog" asp-action="Index" class="navbar-brand">
<img src="../images/brand.png" alt="eShop On Web"/>
</a>
</section>
@await Html.PartialAsync("_LoginPartial")
<section class="col-lg-1 col-md-3 col-xs-6"><a asp-controller="Basket" asp-action="Index">Basket</a></section>
</article>
</div>
</header>
</article>
</div>
</header>
@RenderBody()
@RenderBody()
<footer class="esh-app-footer">
<div class="container">
<article class="row">
<footer class="esh-app-footer">
<div class="container">
<article class="row">
<section class="col-sm-6">
<img class="esh-app-footer-brand" src="../images/brand_dark.png" />
</section>
<section class="col-sm-6">
<img class="esh-app-footer-brand" src="../images/brand_dark.png" />
</section>
<section class="col-sm-6">
<div class="esh-app-footer-text hidden-xs"> e-ShopOnWeb. All right reserved </div>
</section>
<section class="col-sm-6">
<div class="esh-app-footer-text hidden-xs"> e-ShopOnWeb. All right reserved </div>
</section>
</article>
</div>
</footer>
</article>
</div>
</footer>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("scripts", required: false)
@RenderSection("scripts", required: false)
</body>
</html>

View File

@@ -39,7 +39,7 @@
}
else
{
<section class="col-lg-4 col-md-5 col-xs-12">
<section class="col-lg-1 col-lg-offset-3 col-md-3 col-xs-6">
<div class="esh-identity">
<section class="esh-identity-section">
<div class="esh-identity-item">
@@ -52,6 +52,7 @@ else
</div>
</section>
<section class="col-lg-1 col-xs-12">@await Component.InvokeAsync("Basket")
</section>
<section class="col-lg-1 col-xs-12">
@await Component.InvokeAsync("Basket")
</section>
}

View File

@@ -3,8 +3,12 @@
text-align: center;
}
.esh-pager-item {
margin: 0 5vw;
.esh-pager-item-left {
float: left;
}
.esh-pager-item-right {
float: right;
}
.esh-pager-item--navigable {