Cart Updates (#26)
* ardalis/cart-updates Updating how items are added to cart and displayed in cart. * Cleaning up UI
This commit is contained in:
@@ -8,19 +8,20 @@ namespace Microsoft.eShopWeb.ApplicationCore.Entities
|
||||
public string BuyerId { get; set; }
|
||||
public List<BasketItem> Items { get; set; } = new List<BasketItem>();
|
||||
|
||||
public void AddItem(int productId, decimal unitPrice, int quantity = 1)
|
||||
public void AddItem(CatalogItem item, decimal unitPrice, int quantity = 1)
|
||||
{
|
||||
if(!Items.Any(i => i.ProductId == productId))
|
||||
if(!Items.Any(i => i.Item.Id == item.Id))
|
||||
{
|
||||
Items.Add(new BasketItem()
|
||||
{
|
||||
ProductId = productId,
|
||||
Item = item,
|
||||
//ProductId = productId,
|
||||
Quantity = quantity,
|
||||
UnitPrice = unitPrice
|
||||
});
|
||||
return;
|
||||
}
|
||||
var existingItem = Items.FirstOrDefault(i => i.ProductId == productId);
|
||||
var existingItem = Items.FirstOrDefault(i => i.Item.Id == item.Id);
|
||||
existingItem.Quantity += quantity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
{
|
||||
public class BasketItem : BaseEntity<string>
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
//public int ProductId { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public CatalogItem Item { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,5 @@
|
||||
public CatalogType CatalogType { get; set; }
|
||||
public int CatalogBrandId { get; set; }
|
||||
public CatalogBrand CatalogBrand { get; set; }
|
||||
public CatalogItem() { }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ namespace ApplicationCore.Interfaces
|
||||
Task<Basket> GetBasket(string basketId);
|
||||
Task<Basket> CreateBasket();
|
||||
Task<Basket> CreateBasketForUser(string userId);
|
||||
Task UpdateBasket(Basket basket);
|
||||
|
||||
Task AddItemToBasket(Basket basket, int productId, int quantity);
|
||||
//Task UpdateBasket(Basket basket);
|
||||
}
|
||||
}
|
||||
|
||||
8
src/ApplicationCore/Interfaces/IUriComposer.cs
Normal file
8
src/ApplicationCore/Interfaces/IUriComposer.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace ApplicationCore.Interfaces
|
||||
{
|
||||
|
||||
public interface IUriComposer
|
||||
{
|
||||
string ComposePicUri(string uriTemplate);
|
||||
}
|
||||
}
|
||||
20
src/ApplicationCore/Services/UriComposer.cs
Normal file
20
src/ApplicationCore/Services/UriComposer.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb;
|
||||
|
||||
namespace ApplicationCore.Services
|
||||
{
|
||||
public class UriComposer : IUriComposer
|
||||
{
|
||||
private readonly CatalogSettings _catalogSettings;
|
||||
|
||||
public UriComposer(CatalogSettings catalogSettings)
|
||||
{
|
||||
_catalogSettings = catalogSettings;
|
||||
}
|
||||
public string ComposePicUri(string uriTemplate)
|
||||
{
|
||||
return uriTemplate.Replace("http://catalogbaseurltobereplaced", _catalogSettings.CatalogBaseUrl);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
||||
using ApplicationCore.Interfaces;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.eShopWeb.ViewModels;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.eShopWeb.Controllers
|
||||
{
|
||||
@@ -11,12 +13,15 @@ namespace Microsoft.eShopWeb.Controllers
|
||||
private readonly IBasketService _basketService;
|
||||
//private readonly IIdentityParser<ApplicationUser> _appUserParser;
|
||||
private const string _basketSessionKey = "basketId";
|
||||
private readonly IUriComposer _uriComposer;
|
||||
|
||||
public CartController(IBasketService basketService)
|
||||
public CartController(IBasketService basketService,
|
||||
IUriComposer uriComposer)
|
||||
// IIdentityParser<ApplicationUser> appUserParser)
|
||||
{
|
||||
_basketService = basketService;
|
||||
// _appUserParser = appUserParser;
|
||||
_uriComposer = uriComposer;
|
||||
// _appUserParser = appUserParser;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +31,21 @@ namespace Microsoft.eShopWeb.Controllers
|
||||
//var user = _appUserParser.Parse(HttpContext.User);
|
||||
var basket = await GetBasketFromSessionAsync();
|
||||
|
||||
return View(basket);
|
||||
var viewModel = new BasketViewModel()
|
||||
{
|
||||
BuyerId = basket.BuyerId,
|
||||
Items = basket.Items.Select(i => new BasketItemViewModel()
|
||||
{
|
||||
Id = i.Id,
|
||||
UnitPrice = i.UnitPrice,
|
||||
PictureUrl = _uriComposer.ComposePicUri(i.Item.PictureUri),
|
||||
ProductId = i.Item.Id.ToString(),
|
||||
ProductName = i.Item.Name,
|
||||
Quantity = i.Quantity
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: /Cart/AddToCart
|
||||
@@ -39,9 +58,7 @@ namespace Microsoft.eShopWeb.Controllers
|
||||
}
|
||||
var basket = await GetBasketFromSessionAsync();
|
||||
|
||||
basket.AddItem(productDetails.Id, productDetails.Price, 1);
|
||||
|
||||
await _basketService.UpdateBasket(basket);
|
||||
await _basketService.AddItemToBasket(basket, productDetails.Id, 1);
|
||||
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Microsoft.eShopWeb.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
|
||||
namespace Web.Services
|
||||
{
|
||||
@@ -18,6 +19,7 @@ namespace Web.Services
|
||||
{
|
||||
var basket = await _context.Baskets
|
||||
.Include(b => b.Items)
|
||||
.ThenInclude(i => i.Item)
|
||||
.FirstOrDefaultAsync(b => b.Id == basketId);
|
||||
if (basket == null)
|
||||
{
|
||||
@@ -43,11 +45,19 @@ namespace Web.Services
|
||||
}
|
||||
|
||||
|
||||
public async Task UpdateBasket(Basket basket)
|
||||
//public async Task UpdateBasket(Basket basket)
|
||||
//{
|
||||
// // only need to save changes here
|
||||
// await _context.SaveChangesAsync();
|
||||
//}
|
||||
|
||||
public async Task AddItemToBasket(Basket basket, int productId, int quantity)
|
||||
{
|
||||
// only need to save changes here
|
||||
var item = await _context.CatalogItems.FirstOrDefaultAsync(i => i.Id == productId);
|
||||
|
||||
basket.AddItem(item, item.Price, quantity);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ using Infrastructure.FileSystem;
|
||||
using Infrastructure.Logging;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Web.Services;
|
||||
using ApplicationCore.Services;
|
||||
|
||||
namespace Microsoft.eShopWeb
|
||||
{
|
||||
@@ -71,7 +72,11 @@ namespace Microsoft.eShopWeb
|
||||
services.AddScoped<IBasketService, BasketService>();
|
||||
services.AddScoped<CatalogService>();
|
||||
services.Configure<CatalogSettings>(Configuration);
|
||||
services.AddSingleton<IUriComposer>(new UriComposer(Configuration.Get<CatalogSettings>()));
|
||||
|
||||
// TODO: Remove
|
||||
services.AddSingleton<IImageService, LocalFileImageService>();
|
||||
|
||||
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
|
||||
|
||||
|
||||
|
||||
19
src/Web/ViewModels/BasketItemViewModel.cs
Normal file
19
src/Web/ViewModels/BasketItemViewModel.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.eShopWeb.ViewModels
|
||||
{
|
||||
|
||||
public class BasketItemViewModel
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string ProductId { get; set; }
|
||||
public string ProductName { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
public decimal OldUnitPrice { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public string PictureUrl { get; set; }
|
||||
}
|
||||
}
|
||||
18
src/Web/ViewModels/BasketViewModel.cs
Normal file
18
src/Web/ViewModels/BasketViewModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.eShopWeb.ViewModels
|
||||
{
|
||||
|
||||
public class BasketViewModel
|
||||
{
|
||||
public List<BasketItemViewModel> Items { get; set; } = new List<BasketItemViewModel>();
|
||||
public string BuyerId { get; set; }
|
||||
|
||||
public decimal Total()
|
||||
{
|
||||
return Math.Round(Items.Sum(x => x.UnitPrice * x.Quantity), 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
@using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
@using Microsoft.eShopWeb.ViewModels
|
||||
@{
|
||||
ViewData["Title"] = "Catalog";
|
||||
@model Basket
|
||||
ViewData["Title"] = "Cart";
|
||||
@model BasketViewModel
|
||||
}
|
||||
<section class="esh-catalog-hero">
|
||||
<div class="container">
|
||||
@@ -13,11 +13,60 @@
|
||||
|
||||
@if (Model.Items.Any())
|
||||
{
|
||||
<article class="esh-basket-titles row">
|
||||
<br />
|
||||
<section class="esh-basket-title col-xs-3">Product</section>
|
||||
<section class="esh-basket-title col-xs-3 hidden-lg-down"></section>
|
||||
<section class="esh-basket-title col-xs-2">Price</section>
|
||||
<section class="esh-basket-title col-xs-2">Quantity</section>
|
||||
<section class="esh-basket-title col-xs-2">Cost</section>
|
||||
</article>
|
||||
<div class="esh-catalog-items row">
|
||||
@foreach (var item in Model.Items)
|
||||
{
|
||||
<div class="esh-catalog-item col-md-4">
|
||||
<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" />
|
||||
</section>
|
||||
<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" />
|
||||
</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>
|
||||
<div class="row">
|
||||
|
||||
</div>
|
||||
</article>
|
||||
@*<div class="esh-catalog-item col-md-4">
|
||||
@item.ProductId
|
||||
</div>*@
|
||||
|
||||
<div class="container">
|
||||
<article class="esh-basket-titles esh-basket-titles--clean row">
|
||||
<section class="esh-basket-title col-xs-10"></section>
|
||||
<section class="esh-basket-title col-xs-2">Total</section>
|
||||
</article>
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item col-xs-10"></section>
|
||||
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.Total()</section>
|
||||
</article>
|
||||
|
||||
<article class="esh-basket-items row">
|
||||
<section class="esh-basket-item col-xs-7"></section>
|
||||
<section class="esh-basket-item col-xs-2">
|
||||
<button class="btn esh-basket-checkout" name="name" value="" type="submit">[ Update ]</button>
|
||||
</section>
|
||||
<section class="esh-basket-item col-xs-3">
|
||||
<input type="submit"
|
||||
class="btn esh-basket-checkout"
|
||||
value="[ Checkout ]" name="action" />
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - Microsoft.eShopOnContainers.WebMVC</title>
|
||||
<title>@ViewData["Title"] - Microsoft.eShopOnWeb</title>
|
||||
|
||||
<environment names="Development">
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Pics\**" />
|
||||
<Content Remove="Pics\**" />
|
||||
<EmbeddedResource Remove="Pics\**" />
|
||||
<None Remove="Pics\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="1.50.2" />
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.0.1" />
|
||||
@@ -27,7 +34,6 @@
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.BrowserLink" Version="1.1.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Pics\" />
|
||||
<Folder Include="Views\Catalog\" />
|
||||
<Folder Include="Views\Account\" />
|
||||
<Folder Include="wwwroot\css\catalog\" />
|
||||
|
||||
@@ -145,3 +145,84 @@
|
||||
.esh-catalog-price::before {
|
||||
content: '$';
|
||||
}
|
||||
|
||||
|
||||
|
||||
.esh-basket {
|
||||
min-height: 80vh;
|
||||
}
|
||||
|
||||
.esh-basket-titles {
|
||||
padding-bottom: 1rem;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.esh-basket-titles--clean {
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.esh-basket-title {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.esh-basket-items--border {
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
padding: .5rem 0;
|
||||
}
|
||||
|
||||
.esh-basket-items--border:last-of-type {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.esh-basket-items-margin-left1 {
|
||||
margin-left: 1px;
|
||||
}
|
||||
|
||||
.esh-basket-item {
|
||||
font-size: 1rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.esh-basket-item--middle {
|
||||
line-height: 8rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
.esh-basket-item--middle {
|
||||
line-height: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.esh-basket-item--mark {
|
||||
color: #00A69C;
|
||||
}
|
||||
|
||||
.esh-basket-image {
|
||||
height: 8rem;
|
||||
}
|
||||
|
||||
.esh-basket-input {
|
||||
line-height: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.esh-basket-checkout {
|
||||
background-color: #83D01B;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
color: #FFFFFF;
|
||||
display: inline-block;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
margin-top: 1rem;
|
||||
padding: 1rem 1.5rem;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.35s;
|
||||
}
|
||||
|
||||
.esh-basket-checkout:hover {
|
||||
background-color: #4a760f;
|
||||
transition: all 0.35s;
|
||||
}
|
||||
Reference in New Issue
Block a user