diff --git a/src/Web/CatalogSettings.cs b/src/ApplicationCore/CatalogSettings.cs similarity index 100% rename from src/Web/CatalogSettings.cs rename to src/ApplicationCore/CatalogSettings.cs diff --git a/src/ApplicationCore/Entities/Basket.cs b/src/ApplicationCore/Entities/Basket.cs index e635965..c313e1d 100644 --- a/src/ApplicationCore/Entities/Basket.cs +++ b/src/ApplicationCore/Entities/Basket.cs @@ -8,19 +8,20 @@ namespace Microsoft.eShopWeb.ApplicationCore.Entities public string BuyerId { get; set; } public List Items { get; set; } = new List(); - 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; } } diff --git a/src/ApplicationCore/Entities/BasketItem.cs b/src/ApplicationCore/Entities/BasketItem.cs index 19d02fd..70ea9cf 100644 --- a/src/ApplicationCore/Entities/BasketItem.cs +++ b/src/ApplicationCore/Entities/BasketItem.cs @@ -2,8 +2,9 @@ { public class BasketItem : BaseEntity { - 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; } } } diff --git a/src/ApplicationCore/Entities/CatalogItem.cs b/src/ApplicationCore/Entities/CatalogItem.cs index 9f3bdaf..1c6b7f1 100644 --- a/src/ApplicationCore/Entities/CatalogItem.cs +++ b/src/ApplicationCore/Entities/CatalogItem.cs @@ -10,6 +10,5 @@ public CatalogType CatalogType { get; set; } public int CatalogBrandId { get; set; } public CatalogBrand CatalogBrand { get; set; } - public CatalogItem() { } } } \ No newline at end of file diff --git a/src/ApplicationCore/Interfaces/IBasketService.cs b/src/ApplicationCore/Interfaces/IBasketService.cs index 6233083..56d1d0c 100644 --- a/src/ApplicationCore/Interfaces/IBasketService.cs +++ b/src/ApplicationCore/Interfaces/IBasketService.cs @@ -8,6 +8,8 @@ namespace ApplicationCore.Interfaces Task GetBasket(string basketId); Task CreateBasket(); Task CreateBasketForUser(string userId); - Task UpdateBasket(Basket basket); + + Task AddItemToBasket(Basket basket, int productId, int quantity); + //Task UpdateBasket(Basket basket); } } diff --git a/src/ApplicationCore/Interfaces/IUriComposer.cs b/src/ApplicationCore/Interfaces/IUriComposer.cs new file mode 100644 index 0000000..d642dd5 --- /dev/null +++ b/src/ApplicationCore/Interfaces/IUriComposer.cs @@ -0,0 +1,8 @@ +namespace ApplicationCore.Interfaces +{ + + public interface IUriComposer + { + string ComposePicUri(string uriTemplate); + } +} diff --git a/src/ApplicationCore/Services/UriComposer.cs b/src/ApplicationCore/Services/UriComposer.cs new file mode 100644 index 0000000..ac1df54 --- /dev/null +++ b/src/ApplicationCore/Services/UriComposer.cs @@ -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); + + } + } +} diff --git a/src/Web/Controllers/CartController.cs b/src/Web/Controllers/CartController.cs index 2273469..d1e0119 100644 --- a/src/Web/Controllers/CartController.cs +++ b/src/Web/Controllers/CartController.cs @@ -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 _appUserParser; private const string _basketSessionKey = "basketId"; + private readonly IUriComposer _uriComposer; - public CartController(IBasketService basketService) + public CartController(IBasketService basketService, + IUriComposer uriComposer) // IIdentityParser 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"); } diff --git a/src/Web/Services/BasketService.cs b/src/Web/Services/BasketService.cs index 60d21a9..b07d4da 100644 --- a/src/Web/Services/BasketService.cs +++ b/src/Web/Services/BasketService.cs @@ -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(); } - } } diff --git a/src/Web/Startup.cs b/src/Web/Startup.cs index ce3ce99..156282e 100644 --- a/src/Web/Startup.cs +++ b/src/Web/Startup.cs @@ -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(); services.AddScoped(); services.Configure(Configuration); + services.AddSingleton(new UriComposer(Configuration.Get())); + + // TODO: Remove services.AddSingleton(); + services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); diff --git a/src/Web/ViewModels/BasketItemViewModel.cs b/src/Web/ViewModels/BasketItemViewModel.cs new file mode 100644 index 0000000..9256932 --- /dev/null +++ b/src/Web/ViewModels/BasketItemViewModel.cs @@ -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; } + } +} diff --git a/src/Web/ViewModels/BasketViewModel.cs b/src/Web/ViewModels/BasketViewModel.cs new file mode 100644 index 0000000..5087568 --- /dev/null +++ b/src/Web/ViewModels/BasketViewModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.eShopWeb.ViewModels +{ + + public class BasketViewModel + { + public List Items { get; set; } = new List(); + public string BuyerId { get; set; } + + public decimal Total() + { + return Math.Round(Items.Sum(x => x.UnitPrice * x.Quantity), 2); + } + } +} diff --git a/src/Web/Views/Cart/Index.cshtml b/src/Web/Views/Cart/Index.cshtml index 702db5e..9257e48 100644 --- a/src/Web/Views/Cart/Index.cshtml +++ b/src/Web/Views/Cart/Index.cshtml @@ -1,7 +1,7 @@ -@using Microsoft.eShopWeb.ApplicationCore.Entities; +@using Microsoft.eShopWeb.ViewModels @{ - ViewData["Title"] = "Catalog"; - @model Basket + ViewData["Title"] = "Cart"; + @model BasketViewModel }
@@ -13,11 +13,60 @@ @if (Model.Items.Any()) { +
+
+
Product
+
+
Price
+
Quantity
+
Cost
+
@foreach (var item in Model.Items) { -
+
+
+
+ +
+
@item.ProductName
+
$ @item.UnitPrice.ToString("N2")
+
+ + +
+
$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")
+
+
+ +
+
+ @*
@item.ProductId +
*@ + +
+
+
+
Total
+
+ +
+
+
$ @Model.Total()
+
+ +
+
+
+ +
+
+ +
+
}
diff --git a/src/Web/Views/Shared/_Layout.cshtml b/src/Web/Views/Shared/_Layout.cshtml index cb6a1ad..2e77475 100644 --- a/src/Web/Views/Shared/_Layout.cshtml +++ b/src/Web/Views/Shared/_Layout.cshtml @@ -3,7 +3,7 @@ - @ViewData["Title"] - Microsoft.eShopOnContainers.WebMVC + @ViewData["Title"] - Microsoft.eShopOnWeb diff --git a/src/Web/Web.csproj b/src/Web/Web.csproj index 50693f1..82708dd 100644 --- a/src/Web/Web.csproj +++ b/src/Web/Web.csproj @@ -10,6 +10,13 @@ ..\docker-compose.dcproj + + + + + + + @@ -27,7 +34,6 @@ - diff --git a/src/Web/wwwroot/css/catalog/catalog.component.css b/src/Web/wwwroot/css/catalog/catalog.component.css index 3ee2b72..ac401e2 100644 --- a/src/Web/wwwroot/css/catalog/catalog.component.css +++ b/src/Web/wwwroot/css/catalog/catalog.component.css @@ -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; + } \ No newline at end of file