From 65e633e4e0eddcea77c256e9e7d2990af51e3eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Ca=C3=B1izares=20Est=C3=A9vez?= Date: Wed, 2 Nov 2016 20:41:12 +0100 Subject: [PATCH] Add to Cart flow and views --- src/Web/WebMVC/Controllers/CartController.cs | 69 ++++++++++++++ .../WebMVC/Controllers/CatalogController.cs | 4 +- src/Web/WebMVC/Controllers/OrderController.cs | 39 +++----- src/Web/WebMVC/Models/Basket.cs | 24 +++++ src/Web/WebMVC/Models/BasketItem.cs | 17 ++++ src/Web/WebMVC/Models/CatalogItem.cs | 2 +- src/Web/WebMVC/Models/Order.cs | 12 ++- src/Web/WebMVC/Models/OrderItem.cs | 2 +- .../OrderViewModels/CreateOrderViewModel.cs | 12 +++ src/Web/WebMVC/Services/BasketService.cs | 94 +++++++++++++++++++ src/Web/WebMVC/Services/CatalogService.cs | 56 +++++------ src/Web/WebMVC/Services/IBasketService.cs | 18 ++++ src/Web/WebMVC/Services/IOrderingService.cs | 6 +- src/Web/WebMVC/Services/OrderingService.cs | 36 ++----- src/Web/WebMVC/Startup.cs | 8 +- src/Web/WebMVC/ViewComponents/Cart.cs | 6 +- src/Web/WebMVC/ViewComponents/CartList.cs | 8 +- src/Web/WebMVC/Views/Cart/Index.cshtml | 69 ++++++++++++++ src/Web/WebMVC/Views/Catalog/Index.cshtml | 26 ++--- src/Web/WebMVC/Views/Order/Cart.cshtml | 52 ---------- src/Web/WebMVC/Views/Order/Create.cshtml | 56 +++++------ .../Shared/Components/Cart/Default.cshtml | 2 +- .../Shared/Components/CartList/Default.cshtml | 21 +++-- src/Web/WebMVC/wwwroot/css/site.css | 46 +++++++++ src/Web/WebMVC/wwwroot/js/site.js | 13 +++ 25 files changed, 491 insertions(+), 207 deletions(-) create mode 100644 src/Web/WebMVC/Controllers/CartController.cs create mode 100644 src/Web/WebMVC/Models/Basket.cs create mode 100644 src/Web/WebMVC/Models/BasketItem.cs create mode 100644 src/Web/WebMVC/Models/OrderViewModels/CreateOrderViewModel.cs create mode 100644 src/Web/WebMVC/Services/BasketService.cs create mode 100644 src/Web/WebMVC/Services/IBasketService.cs create mode 100644 src/Web/WebMVC/Views/Cart/Index.cshtml delete mode 100644 src/Web/WebMVC/Views/Order/Cart.cshtml diff --git a/src/Web/WebMVC/Controllers/CartController.cs b/src/Web/WebMVC/Controllers/CartController.cs new file mode 100644 index 000000000..ab7c7895c --- /dev/null +++ b/src/Web/WebMVC/Controllers/CartController.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Identity; +using Microsoft.eShopOnContainers.WebMVC.Services; +using Microsoft.eShopOnContainers.WebMVC.Models; +using Microsoft.AspNetCore.Authorization; + +namespace Microsoft.eShopOnContainers.WebMVC.Controllers +{ + [Authorize] + public class CartController : Controller + { + private readonly UserManager _userManager; + private readonly IBasketService _basketSvc; + private readonly ICatalogService _catalogSvc; + + public CartController(IBasketService basketSvc, ICatalogService catalogSvc, UserManager userManager) + { + _userManager = userManager; + _basketSvc = basketSvc; + _catalogSvc = catalogSvc; + } + + public async Task Index() + { + var user = await _userManager.GetUserAsync(HttpContext.User); + var vm = _basketSvc.GetBasket(user); + + return View(vm); + } + + + [HttpPost] + public async Task Index(Dictionary quantities, string action) + { + var user = await _userManager.GetUserAsync(HttpContext.User); + var basket = _basketSvc.SetQuantities(user, quantities); + + if (action == "[ Checkout ]") + { + var order = _basketSvc.MapBasketToOrder(basket); + return RedirectToAction("Create", "Order"); + } + + var vm = _basketSvc.UpdateBasket(basket); + return View(vm); + } + + public async Task AddToCart(string productId) + { + var user = await _userManager.GetUserAsync(HttpContext.User); + var productDetails = _catalogSvc.GetCatalogItem(productId); + var product = new BasketItem() + { + Id = Guid.NewGuid().ToString(), + Quantity = 1, + ProductName = productDetails.Name, + PictureUrl = productDetails.PictureUrl, + UnitPrice = productDetails.Price, + ProductId = productId + }; + _basketSvc.AddToCart(user, product); + return RedirectToAction("Index", "Catalog"); + } + } +} \ No newline at end of file diff --git a/src/Web/WebMVC/Controllers/CatalogController.cs b/src/Web/WebMVC/Controllers/CatalogController.cs index 6f07b0f5c..8a3a4ac45 100644 --- a/src/Web/WebMVC/Controllers/CatalogController.cs +++ b/src/Web/WebMVC/Controllers/CatalogController.cs @@ -27,8 +27,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers var vm = new IndexViewModel() { CatalogItems = await _catalogSvc.GetCatalogItems(6 * (page ?? 0), 6), - Brands = _catalogSvc.GetTypes(), - Types = _catalogSvc.GetBrands(), + Brands = _catalogSvc.GetBrands(), + Types = _catalogSvc.GetTypes(), BrandFilterApplied = BrandFilterApplied ?? 0, TypesFilterApplied = TypesFilterApplied ?? 0, PaginationInfo = new PaginationInfo() diff --git a/src/Web/WebMVC/Controllers/OrderController.cs b/src/Web/WebMVC/Controllers/OrderController.cs index bc39b967f..e110a5f92 100644 --- a/src/Web/WebMVC/Controllers/OrderController.cs +++ b/src/Web/WebMVC/Controllers/OrderController.cs @@ -7,6 +7,7 @@ using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; +using Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels; namespace Microsoft.eShopOnContainers.WebMVC.Controllers { @@ -14,42 +15,24 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers public class OrderController : Controller { private IOrderingService _orderSvc; - private ICatalogService _catalogSvc; + private IBasketService _basketSvc; private readonly UserManager _userManager; - public OrderController(IOrderingService orderSvc, ICatalogService catalogSvc, UserManager userManager) + public OrderController(IOrderingService orderSvc, IBasketService basketSvc, UserManager userManager) { _userManager = userManager; _orderSvc = orderSvc; - _catalogSvc = catalogSvc; + _basketSvc = basketSvc; } - public async Task AddToCart(string productId) + public async Task Create() { - //CCE: I need product details (price, ...), so I retrieve from Catalog service again. - // I don't like POST with a form from the catalog view (I'm avoiding Ajax too), - // I prefer Url.Action and http call here to catalog service to retrieve this info. + var vm = new CreateOrderViewModel(); var user = await _userManager.GetUserAsync(HttpContext.User); - var productDetails = _catalogSvc.GetCatalogItem(productId); - var product = new OrderItem() - { - ProductId = productId, - Quantity = 1, - ProductName = productDetails.Name, - PicsUrl = productDetails.PicsUrl, - UnitPrice = productDetails.Price - }; - _orderSvc.AddToCart(user, product); - return RedirectToAction("Index", "Catalog"); - } - - public IActionResult Cart() - { - return View(); - } - - public IActionResult Create() - { - return View(); + var basket = _basketSvc.GetBasket(user); + var order = _basketSvc.MapBasketToOrder(basket); + vm.Order = order; + + return View(vm); } public async Task Index(Order item) diff --git a/src/Web/WebMVC/Models/Basket.cs b/src/Web/WebMVC/Models/Basket.cs new file mode 100644 index 000000000..6bd0068c1 --- /dev/null +++ b/src/Web/WebMVC/Models/Basket.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.WebMVC.Models +{ + public class Basket + { + public Basket() + { + Items = new List(); + } + + public string Id; + public List Items { get; set; } + public string BuyerId { get; set; } + + public decimal Total() + { + return Items.Sum(x => x.UnitPrice * x.Quantity); + } + } +} diff --git a/src/Web/WebMVC/Models/BasketItem.cs b/src/Web/WebMVC/Models/BasketItem.cs new file mode 100644 index 000000000..15ac19edf --- /dev/null +++ b/src/Web/WebMVC/Models/BasketItem.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.WebMVC.Models +{ + public class BasketItem + { + public string Id { get; set; } + public string ProductId { get; set; } + public string ProductName { get; set; } + public decimal UnitPrice { get; set; } + public int Quantity { get; set; } + public string PictureUrl { get; set; } + } +} diff --git a/src/Web/WebMVC/Models/CatalogItem.cs b/src/Web/WebMVC/Models/CatalogItem.cs index 10c4c6bf6..2c2c6caeb 100644 --- a/src/Web/WebMVC/Models/CatalogItem.cs +++ b/src/Web/WebMVC/Models/CatalogItem.cs @@ -8,6 +8,6 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } - public string PicsUrl { get; set; } + public string PictureUrl { get; set; } } } \ No newline at end of file diff --git a/src/Web/WebMVC/Models/Order.cs b/src/Web/WebMVC/Models/Order.cs index 3527eac32..dad2e3e40 100644 --- a/src/Web/WebMVC/Models/Order.cs +++ b/src/Web/WebMVC/Models/Order.cs @@ -7,6 +7,11 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models { public class Order { + public Order() + { + OrderItems = new List(); + } + public string Id; public List OrderItems { get; set; } public string OrderNumber @@ -27,10 +32,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models //(CDLTLL) public virtual OrderStatus Status { get; set; } } - public enum OrderState + public enum OrderState:int { - Active, - InProcess, - Delivered + InProcess = 0, + Delivered = 1 } } diff --git a/src/Web/WebMVC/Models/OrderItem.cs b/src/Web/WebMVC/Models/OrderItem.cs index e49638c22..ece2ef207 100644 --- a/src/Web/WebMVC/Models/OrderItem.cs +++ b/src/Web/WebMVC/Models/OrderItem.cs @@ -14,7 +14,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Models public decimal UnitPrice { get; set; } public int Quantity { get; set; } public decimal Discount { get; set; } - public string PicsUrl { get; set; } + public string PictureUrl { get; set; } public override string ToString() { return String.Format("Product Id: {0}, Quantity: {1}", this.Id, this.Quantity); diff --git a/src/Web/WebMVC/Models/OrderViewModels/CreateOrderViewModel.cs b/src/Web/WebMVC/Models/OrderViewModels/CreateOrderViewModel.cs new file mode 100644 index 000000000..078686df4 --- /dev/null +++ b/src/Web/WebMVC/Models/OrderViewModels/CreateOrderViewModel.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels +{ + public class CreateOrderViewModel + { + public Order Order { get; set; } + } +} diff --git a/src/Web/WebMVC/Services/BasketService.cs b/src/Web/WebMVC/Services/BasketService.cs new file mode 100644 index 000000000..57f404dcb --- /dev/null +++ b/src/Web/WebMVC/Services/BasketService.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.eShopOnContainers.WebMVC.Models; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.eShopOnContainers.WebMVC.Services +{ + public class BasketService : IBasketService + { + private int _itemsInCart; + private readonly IHttpContextAccessor _httpContextAccessor; + + public BasketService(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + public int ItemsInCart { get { return _itemsInCart; }} + + public void AddToCart(ApplicationUser user, BasketItem product) + { + Basket activeOrder = GetBasket(user); + if (activeOrder == null) + { + activeOrder = new Basket() + { + BuyerId = user.Id, + Id = Guid.NewGuid().ToString(), + Items = new List() + }; + } + + activeOrder.Items.Add(product); + //CCE: lacks and httpcall to persist in the real back.end service. + _httpContextAccessor.HttpContext.Session.SetObject("MyActiveOrder", activeOrder); + + } + + public Basket GetBasket(ApplicationUser user) + { + Basket activeOrder; + activeOrder = _httpContextAccessor.HttpContext.Session.GetObject("MyActiveOrder"); + _itemsInCart = (activeOrder != null) ? activeOrder.Items.Count() : 0; + + return activeOrder; + } + + public Basket UpdateBasket(Basket basket) + { + _httpContextAccessor.HttpContext.Session.SetObject("MyActiveOrder", basket); + return _httpContextAccessor.HttpContext.Session.GetObject("MyActiveOrder"); + } + + public Basket SetQuantities(ApplicationUser user, Dictionary quantities) + { + var basket = GetBasket(user); + + basket.Items.ForEach(x => + { + var quantity = quantities.Where(y => y.Key == x.Id).FirstOrDefault(); + if (quantities.Where(y => y.Key == x.Id).Count() > 0) + x.Quantity = quantity.Value; + }); + + return basket; + } + + public Order MapBasketToOrder(Basket basket) + { + var order = new Order() + { + Id = Guid.NewGuid().ToString(), + BuyerId = basket.BuyerId + }; + + basket.Items.ForEach(x => + { + order.OrderItems.Add(new OrderItem() + { + ProductId = x.ProductId, + OrderId = order.Id, + PictureUrl = x.PictureUrl, + ProductName = x.ProductName, + Quantity = x.Quantity, + UnitPrice = x.UnitPrice + }); + }); + + return order; + } + } +} diff --git a/src/Web/WebMVC/Services/CatalogService.cs b/src/Web/WebMVC/Services/CatalogService.cs index 9a00290e5..c03a6abfe 100644 --- a/src/Web/WebMVC/Services/CatalogService.cs +++ b/src/Web/WebMVC/Services/CatalogService.cs @@ -32,34 +32,34 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services #region fake data _items = new List() { - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, - new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PicsUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" } + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Cupt Black & White Mug", Name = "Cupt Black & White Mug", Price= 17, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=CuptBlack&WhiteMug" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.PrismWhiteT-Shirt" }, + new CatalogItem() { Id = Guid.NewGuid().ToString(), Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = decimal.Parse("19.5"), PictureUrl = "http://fakeimg.pl/370x240/EEEEEE/000/?text=.NETBotBlack" } }; #endregion } diff --git a/src/Web/WebMVC/Services/IBasketService.cs b/src/Web/WebMVC/Services/IBasketService.cs new file mode 100644 index 000000000..538a0cd7e --- /dev/null +++ b/src/Web/WebMVC/Services/IBasketService.cs @@ -0,0 +1,18 @@ +using Microsoft.eShopOnContainers.WebMVC.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.eShopOnContainers.WebMVC.Services +{ + public interface IBasketService + { + Basket GetBasket(ApplicationUser user); + int ItemsInCart { get; } + void AddToCart(ApplicationUser user, BasketItem product); + Basket UpdateBasket(Basket basket); + Basket SetQuantities(ApplicationUser user, Dictionary quantities); + Order MapBasketToOrder(Basket basket); + } +} diff --git a/src/Web/WebMVC/Services/IOrderingService.cs b/src/Web/WebMVC/Services/IOrderingService.cs index 3e8061a58..2c24cd039 100644 --- a/src/Web/WebMVC/Services/IOrderingService.cs +++ b/src/Web/WebMVC/Services/IOrderingService.cs @@ -8,10 +8,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { public interface IOrderingService { - int ItemsInCart { get; } List GetMyOrders(ApplicationUser user); - Order GetActiveOrder(ApplicationUser user); - void AddToCart(ApplicationUser user, OrderItem product); Order GetOrder(ApplicationUser user, Guid orderId); + void CreateOrder(Order order); } + + } diff --git a/src/Web/WebMVC/Services/OrderingService.cs b/src/Web/WebMVC/Services/OrderingService.cs index 0c4f7ac5e..59f52276f 100644 --- a/src/Web/WebMVC/Services/OrderingService.cs +++ b/src/Web/WebMVC/Services/OrderingService.cs @@ -11,7 +11,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services { private List _orders; private int _itemsInCart; - private IHttpContextAccessor _httpContextAccessor; + public int ItemsInCart { get { return _itemsInCart; } } //var ordersUrl = _settings.OrderingUrl + "/api/ordering/orders"; //var dataString = await _http.GetStringAsync(ordersUrl); @@ -19,18 +19,16 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services public OrderingService(IHttpContextAccessor httpContextAccessor) { - _httpContextAccessor = httpContextAccessor; - _orders = new List() { new Order() { BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(), OrderDate = DateTime.Now, - State = OrderState.Active, + State = OrderState.InProcess, OrderItems = new List() { - new OrderItem() { UnitPrice = 12, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" } + new OrderItem() { UnitPrice = 12, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" } } }, new Order() @@ -40,36 +38,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services State = OrderState.InProcess, OrderItems = new List() { - new OrderItem() { UnitPrice = 12, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" } + new OrderItem() { UnitPrice = 12, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" } } }, new Order() { BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(), OrderDate = DateTime.Now, - State = OrderState.InProcess, + State = OrderState.Delivered, OrderItems = new List() { - new OrderItem() { UnitPrice = 12, PicsUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" } + new OrderItem() { UnitPrice = 12, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" } } } }; } - public Order GetActiveOrder(ApplicationUser user) - { - //I think could be a good aproach to work with session to store the active order. - //.... - Order activeOrder; - activeOrder = _httpContextAccessor.HttpContext.Session.GetObject("MyActiveOrder"); - if (activeOrder == null) - activeOrder = _orders.Where(x => x.BuyerId.Equals(user.Id) && x.State == OrderState.Active).FirstOrDefault(); - - _itemsInCart = (activeOrder != null) ? activeOrder.OrderItems.Count() : 0; - - return activeOrder; - } - public Order GetOrder(ApplicationUser user, Guid Id) { return _orders.Where(x => x.BuyerId.Equals(user.Id) && x.Id.Equals(Id)).FirstOrDefault(); @@ -80,13 +64,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services return _orders.Where(x => x.BuyerId.Equals(user.Id)).ToList(); } - public void AddToCart(ApplicationUser user, OrderItem product) + public void CreateOrder(Order order) { - var activeOrder = GetActiveOrder(user); - activeOrder.OrderItems.Add(product); - //CCE: lacks and httpcall to persist in the real back.end service. - _httpContextAccessor.HttpContext.Session.SetObject("MyActiveOrder", activeOrder); - + throw new NotImplementedException(); } } } diff --git a/src/Web/WebMVC/Startup.cs b/src/Web/WebMVC/Startup.cs index 77b7e6fe8..f1666314f 100644 --- a/src/Web/WebMVC/Startup.cs +++ b/src/Web/WebMVC/Startup.cs @@ -49,14 +49,17 @@ namespace Microsoft.eShopOnContainers.WebMVC .AddDefaultTokenProviders(); services.AddMvc(); + + // CCE : Session not apply in this demo we have a mservice to store in redis. (BasketService) Once it's ready I've to remove this lines services.AddDistributedMemoryCache(); // default implementation (in memory), you can move to SQL or custom store that could be Redis.. services.AddSession(); // Add application services. services.AddTransient(); services.AddTransient(); - services.AddSingleton(); + services.AddSingleton(); //CCE: Once services are integrated, a singleton is not needed we can left transient. services.AddTransient(); + services.AddTransient(); services.Configure(Configuration); } @@ -82,10 +85,9 @@ namespace Microsoft.eShopOnContainers.WebMVC app.UseIdentity(); + //CCE: Remember to remove this line once Basket mservice is ready. app.UseSession(); - // Add external authentication middleware below. To configure them please see http://go.microsoft.com/fwlink/?LinkID=532715 - app.UseMvc(routes => { routes.MapRoute( diff --git a/src/Web/WebMVC/ViewComponents/Cart.cs b/src/Web/WebMVC/ViewComponents/Cart.cs index faa9ce00a..1f1b4b3de 100644 --- a/src/Web/WebMVC/ViewComponents/Cart.cs +++ b/src/Web/WebMVC/ViewComponents/Cart.cs @@ -10,9 +10,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents { public class Cart : ViewComponent { - private readonly IOrderingService _cartSvc; + private readonly IBasketService _cartSvc; - public Cart(IOrderingService cartSvc) + public Cart(IBasketService cartSvc) { _cartSvc = cartSvc; } @@ -24,7 +24,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents } private Task ItemsInCartAsync(ApplicationUser user) { - _cartSvc.GetActiveOrder(user); + _cartSvc.GetBasket(user); return Task.Run ( ()=> { return _cartSvc.ItemsInCart; }); } } diff --git a/src/Web/WebMVC/ViewComponents/CartList.cs b/src/Web/WebMVC/ViewComponents/CartList.cs index 66d1bfaa5..d0eb4d7d1 100644 --- a/src/Web/WebMVC/ViewComponents/CartList.cs +++ b/src/Web/WebMVC/ViewComponents/CartList.cs @@ -10,9 +10,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents { public class CartList : ViewComponent { - private readonly IOrderingService _cartSvc; + private readonly IBasketService _cartSvc; - public CartList(IOrderingService cartSvc) + public CartList(IBasketService cartSvc) { _cartSvc = cartSvc; } @@ -22,9 +22,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents var item = await GetItemsAsync(user); return View(item); } - private Task GetItemsAsync(ApplicationUser user) + private Task GetItemsAsync(ApplicationUser user) { - return Task.Run(()=> { return _cartSvc.GetActiveOrder(user); }); + return Task.Run(()=> { return _cartSvc.GetBasket(user); }); } } } diff --git a/src/Web/WebMVC/Views/Cart/Index.cshtml b/src/Web/WebMVC/Views/Cart/Index.cshtml new file mode 100644 index 000000000..7e7fc0324 --- /dev/null +++ b/src/Web/WebMVC/Views/Cart/Index.cshtml @@ -0,0 +1,69 @@ +@model Microsoft.eShopOnContainers.WebMVC.Models.Basket +@inject UserManager UserManager + +@{ + ViewData["Title"] = "My Cart"; +} + +
+ +
+ +
+
+
+



+
+
+ + + + + + + + + + + + + @await Component.InvokeAsync("CartList", new { user = await UserManager.GetUserAsync(User) }) + +
+ PRODUCT + + + + BRAND + + PRICE + + QUANTITY + + COST +
+
+
+
+ + +
+
SUBTOTAL
+
$ 29.00
+
TAX
+
$ 4.20
+
TOTAL
+
$ @Model.Total()
+
+ +
+
+
+
\ No newline at end of file diff --git a/src/Web/WebMVC/Views/Catalog/Index.cshtml b/src/Web/WebMVC/Views/Catalog/Index.cshtml index 94977df5a..6608358ee 100644 --- a/src/Web/WebMVC/Views/Catalog/Index.cshtml +++ b/src/Web/WebMVC/Views/Catalog/Index.cshtml @@ -60,20 +60,20 @@
@foreach (var catalogItem in Model.CatalogItems) { -
-
- - - ADD TO CART - +
+
+
+ + +
+
+ @catalogItem.Name +
+
+ @catalogItem.Price.ToString("N2") +
-
- @catalogItem.Name -
-
- @catalogItem.Price.ToString("N2") -
-
+ }
diff --git a/src/Web/WebMVC/Views/Order/Cart.cshtml b/src/Web/WebMVC/Views/Order/Cart.cshtml deleted file mode 100644 index 1059b25e0..000000000 --- a/src/Web/WebMVC/Views/Order/Cart.cshtml +++ /dev/null @@ -1,52 +0,0 @@ -@model Microsoft.eShopOnContainers.WebMVC.Models.Order -@inject UserManager UserManager - -@{ - ViewData["Title"] = "My Cart"; -} - -
- -
-
-
-



-
-
- - - - - - - - - - - - - @await Component.InvokeAsync("CartList", new { user = await UserManager.GetUserAsync(User) }) - -
- PRODUCT - - - - BRAND - - PRICE - - QUANTITY - - FINAL PRICE -
-
-
-





- -
-
diff --git a/src/Web/WebMVC/Views/Order/Create.cshtml b/src/Web/WebMVC/Views/Order/Create.cshtml index 599888589..5eec32756 100644 --- a/src/Web/WebMVC/Views/Order/Create.cshtml +++ b/src/Web/WebMVC/Views/Order/Create.cshtml @@ -1,4 +1,4 @@ -@model Microsoft.eShopOnContainers.WebMVC.Models.Order +@model Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels.CreateOrderViewModel @{ ViewData["Title"] = "View"; @@ -13,24 +13,24 @@

SHIPPING ADDRESS

- - - + + +
- - - + + +
- - - + + +
- - - + + +


@@ -38,30 +38,30 @@

PAYMENT METHOD

- - - + + +
- - - + + +
- - +
- - +
- - - + + +
diff --git a/src/Web/WebMVC/Views/Shared/Components/Cart/Default.cshtml b/src/Web/WebMVC/Views/Shared/Components/Cart/Default.cshtml index e680a4056..d3f757363 100644 --- a/src/Web/WebMVC/Views/Shared/Components/Cart/Default.cshtml +++ b/src/Web/WebMVC/Views/Shared/Components/Cart/Default.cshtml @@ -5,7 +5,7 @@ }
- +
diff --git a/src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml b/src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml index f7f2c5619..317f5b05b 100644 --- a/src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml +++ b/src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml @@ -1,18 +1,23 @@ -@model Microsoft.eShopOnContainers.WebMVC.Models.Order +@model Microsoft.eShopOnContainers.WebMVC.Models.Basket @{ ViewData["Title"] = "My Cart"; } -@foreach (var item in Model.OrderItems) +@for (int i = 0; i < Model.Items.Count; i++) { + var item = Model.Items[i]; + - - @item.ProductName - ROSLYN - $ @item.UnitPrice - @item.Quantity - $ @(item.Quantity * item.UnitPrice) + + @item.ProductName + ROSLYN + $ @item.UnitPrice + + + + + $ @(item.Quantity * item.UnitPrice) } diff --git a/src/Web/WebMVC/wwwroot/css/site.css b/src/Web/WebMVC/wwwroot/css/site.css index 01d0987a2..5437627cc 100644 --- a/src/Web/WebMVC/wwwroot/css/site.css +++ b/src/Web/WebMVC/wwwroot/css/site.css @@ -201,6 +201,8 @@ select::-ms-expand { .btn-cart { float: right; + margin-top: 40px; + margin-bottom: 40px; } .btn-catalog-apply { @@ -507,16 +509,56 @@ form .col-md-4 { .cart-index-container { min-height: 70vh; padding-top: 40px; + margin-bottom: 30px; } .cart-product-column { max-width: 120px; + text-transform: uppercase; + vertical-align: middle!important; +} + +.cart-subtotal-label { + font-size: 12px; + color: #404040; + margin-top:10px; +} + +.cart-subtotal-value { + font-size: 20px; + color: #00a69c; +} + +.cart-total-label { + font-size: 14px; + color: #404040; + margin-top:10px; +} + +.cart-total-value { + font-size: 28px; + color: #00a69c; } .cart-product-image { max-width: 210px; } +.cart-section-total { + margin-bottom: 5px; + margin-left: 185px; + text-align: left; +} + +.cart-product-column input { + width: 70px; + text-align: center; +} + +.cart-refresh-button { + margin-top:0; +} + .input-validation-error { border: 1px solid #fb0d0d; } @@ -660,6 +702,10 @@ form .col-md-4 { pointer-events: none; } +.table tr { + border-bottom:1px solid #ddd; +} + /* Hide/rearrange for smaller screens */ @media screen and (max-width: 767px) { diff --git a/src/Web/WebMVC/wwwroot/js/site.js b/src/Web/WebMVC/wwwroot/js/site.js index 82ecce7b4..f894f76b8 100644 --- a/src/Web/WebMVC/wwwroot/js/site.js +++ b/src/Web/WebMVC/wwwroot/js/site.js @@ -1 +1,14 @@ // Write your Javascript code. +$('#item_Quantity').change(function () { + $('.cart-refresh-button').removeClass('is-disabled'); +}); + +function checkoutCart(){ + $('#cartForm').attr('action', '/Cart?option=checkout'); + $('#cartForm').submit(); +} + +function refreshCart() { + $('#cartForm').attr('action','/Cart?option=refresh'); + $('#cartForm').submit(); +}