From 5fff10e2a0cf244ce43b8f52cf63950dc15afb8a Mon Sep 17 00:00:00 2001 From: wook Date: Fri, 7 Apr 2017 01:45:20 +0900 Subject: [PATCH] Ch. 8 SportsStore 2nd --- SportsStore.Domain/Entities/Cart.cs | 54 +++++++++++++++ SportsStore.Domain/SportsStore.Domain.csproj | 1 + SportsStore.WebUI/App_Start/RouteConfig.cs | 50 ++++++++++---- .../Controllers/CartController.cs | 66 +++++++++++++++++++ .../Controllers/NavController.cs | 35 ++++++++++ .../Controllers/ProductController.cs | 11 +++- .../Models/CartIndexViewModel.cs | 14 ++++ .../Models/ProductsListViewModel.cs | 2 + SportsStore.WebUI/SportsStore.WebUI.csproj | 5 ++ SportsStore.WebUI/Views/Cart/Index.cshtml | 42 ++++++++++++ SportsStore.WebUI/Views/Nav/Menu.cshtml | 13 ++++ SportsStore.WebUI/Views/Product/List.cshtml | 2 +- .../Views/Shared/ProductSummary.cshtml | 8 +++ SportsStore.WebUI/Views/Shared/_Layout.cshtml | 2 +- 14 files changed, 288 insertions(+), 17 deletions(-) create mode 100644 SportsStore.Domain/Entities/Cart.cs create mode 100644 SportsStore.WebUI/Controllers/CartController.cs create mode 100644 SportsStore.WebUI/Controllers/NavController.cs create mode 100644 SportsStore.WebUI/Models/CartIndexViewModel.cs create mode 100644 SportsStore.WebUI/Views/Cart/Index.cshtml create mode 100644 SportsStore.WebUI/Views/Nav/Menu.cshtml diff --git a/SportsStore.Domain/Entities/Cart.cs b/SportsStore.Domain/Entities/Cart.cs new file mode 100644 index 0000000..d63594c --- /dev/null +++ b/SportsStore.Domain/Entities/Cart.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace SportsStore.Domain.Entities +{ + public class Cart + { + private List lineCollection = new List(); + + public void AddItem(Product product, int quantity) + { + CartLine line = lineCollection + .Where(p => p.Product.ProductID == product.ProductID) + .FirstOrDefault(); + + if (line == null) + { + lineCollection.Add(new CartLine { Product = product, Quantity = quantity }); + } + else + { + line.Quantity += quantity; + } + } + + public void RemoveLine(Product product) + { + lineCollection.RemoveAll(l => l.Product.ProductID == product.ProductID); + } + + public decimal ComputeTotalValue() + { + return lineCollection.Sum(e => e.Product.Price * e.Quantity); + } + + public void Clear() + { + lineCollection.Clear(); + } + + public IEnumerable Lines + { + get { return lineCollection; } + } + } + + public class CartLine + { + public Product Product { get; set; } + public int Quantity { get; set; } + } +} \ No newline at end of file diff --git a/SportsStore.Domain/SportsStore.Domain.csproj b/SportsStore.Domain/SportsStore.Domain.csproj index 3e7cb46..fba237c 100644 --- a/SportsStore.Domain/SportsStore.Domain.csproj +++ b/SportsStore.Domain/SportsStore.Domain.csproj @@ -108,6 +108,7 @@ + diff --git a/SportsStore.WebUI/App_Start/RouteConfig.cs b/SportsStore.WebUI/App_Start/RouteConfig.cs index 9501e32..8af0de6 100644 --- a/SportsStore.WebUI/App_Start/RouteConfig.cs +++ b/SportsStore.WebUI/App_Start/RouteConfig.cs @@ -9,21 +9,47 @@ namespace SportsStore.WebUI { public class RouteConfig { - public static void RegisterRoutes(RouteCollection routes) - { - routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); + public static void RegisterRoutes(RouteCollection routes) + { + routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); - routes.MapRoute( - name: null, - url: "Page{page}", - defaults: new { Controller = "Product", action = "List" } + routes.MapRoute(null, + "", + new {controller = "Product", action = "List", category = (string)null, page = 1 } ); - routes.MapRoute( - name: "Default", - url: "{controller}/{action}/{id}", - defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional } - ); + routes.MapRoute(null, + "page{page}", + new { controller = "Product", action = "List", category = (string)null }, + new { page = @"d+" } + ); + + //routes.MapRoute( + // name: null, + // url: "Page{page}", + // defaults: new { Controller = "Product", action = "List" } + //); + + routes.MapRoute( + null, + "{category}", + new { controller = "Product", action = "List", page = 1 } + ); + + routes.MapRoute( + null, + "{category}/Page{page}", + new { controller = "Product", action = "List" }, + new { page = @"\d+" } + ); + + //routes.MapRoute( + // name: "Default", + // url: "{controller}/{action}/{id}", + // defaults: new { controller = "Product", action = "List", id = UrlParameter.Optional } + //); + + routes.MapRoute(null, "{controller}/{action}"); } } } diff --git a/SportsStore.WebUI/Controllers/CartController.cs b/SportsStore.WebUI/Controllers/CartController.cs new file mode 100644 index 0000000..2db7a20 --- /dev/null +++ b/SportsStore.WebUI/Controllers/CartController.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using SportsStore.Domain.Abstract; +using SportsStore.Domain.Entities; +using SportsStore.WebUI.Models; + +namespace SportsStore.WebUI.Controllers +{ + public class CartController : Controller + { + private IProductRepository repository; + + public CartController(IProductRepository repo) + { + repository = repo; + } + + public ViewResult Index(string returnUrl) + { + return View(new CartIndexViewModel { Cart = GetCart(), ReturnUrl = returnUrl }); + } + + public RedirectToRouteResult AddToCart(int productId, string returnUrl) + { + Product product = repository.Products + .FirstOrDefault(p => p.ProductID == productId); + + if (product != null) + { + GetCart().AddItem(product, 1); + } + + return RedirectToAction("Index", new { returnUrl }); + } + + public RedirectToRouteResult RemoveFromCart(int productId, string returnUrl) + { + Product product = repository.Products + .FirstOrDefault(p => p.ProductID == productId); + + if (product != null) + { + GetCart().RemoveLine(product); + } + + return RedirectToAction("Index", new { returnUrl }); + } + + + private Cart GetCart() + { + Cart cart = (Cart)Session["Cart"]; + if (cart == null) + { + cart = new Cart(); + Session["Cart"] = cart; + } + + return cart; + } + + } +} \ No newline at end of file diff --git a/SportsStore.WebUI/Controllers/NavController.cs b/SportsStore.WebUI/Controllers/NavController.cs new file mode 100644 index 0000000..c142119 --- /dev/null +++ b/SportsStore.WebUI/Controllers/NavController.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using SportsStore.Domain.Abstract; + +namespace SportsStore.WebUI.Controllers +{ + public class NavController : Controller + { + private IProductRepository repository; + public NavController(IProductRepository repo) + { + repository = repo; + } + + public PartialViewResult Menu(string category = null) + { + ViewBag.SelectedCategory = category; + IEnumerable categories = repository.Products + .Select(x => x.Category) + .Distinct() + .OrderBy(x => x); + + return PartialView(categories); + } + + //public string Menu() + //{ + // return "Hello from NavController"; + //} + + } +} \ No newline at end of file diff --git a/SportsStore.WebUI/Controllers/ProductController.cs b/SportsStore.WebUI/Controllers/ProductController.cs index 99c2e47..e443367 100644 --- a/SportsStore.WebUI/Controllers/ProductController.cs +++ b/SportsStore.WebUI/Controllers/ProductController.cs @@ -24,7 +24,7 @@ namespace SportsStore.WebUI.Controllers // return View(repository.Products); //} - public ViewResult List(int page = 1) + public ViewResult List(string category, int page = 1) { //return View(repository.Products // .OrderBy(p => p.ProductID) @@ -34,6 +34,7 @@ namespace SportsStore.WebUI.Controllers ProductsListViewModel model = new ProductsListViewModel { Products = repository.Products + .Where(p => category == null || p.Category == category) .OrderBy(p => p.ProductID) .Skip((page - 1) * PageSize) .Take(PageSize), @@ -41,8 +42,12 @@ namespace SportsStore.WebUI.Controllers { CurrentPage = page, ItemsPerPage = PageSize, - TotalItems = repository.Products.Count() - } + //TotalItems = repository.Products.Count() + TotalItems = category == null + ? repository.Products.Count() + : repository.Products.Where(e => e.Category == category).Count() + }, + CurrentCategory = category }; return View(model); diff --git a/SportsStore.WebUI/Models/CartIndexViewModel.cs b/SportsStore.WebUI/Models/CartIndexViewModel.cs new file mode 100644 index 0000000..0aa9c99 --- /dev/null +++ b/SportsStore.WebUI/Models/CartIndexViewModel.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using SportsStore.Domain.Entities; + +namespace SportsStore.WebUI.Models +{ + public class CartIndexViewModel + { + public Cart Cart { get; set; } + public string ReturnUrl { get; set; } + } +} \ No newline at end of file diff --git a/SportsStore.WebUI/Models/ProductsListViewModel.cs b/SportsStore.WebUI/Models/ProductsListViewModel.cs index b05eadd..413f160 100644 --- a/SportsStore.WebUI/Models/ProductsListViewModel.cs +++ b/SportsStore.WebUI/Models/ProductsListViewModel.cs @@ -10,6 +10,8 @@ namespace SportsStore.WebUI.Models { public IEnumerable Products { get; set; } public PagingInfo PagingInfo { get; set; } + public string CurrentCategory { get; set; } + } } \ No newline at end of file diff --git a/SportsStore.WebUI/SportsStore.WebUI.csproj b/SportsStore.WebUI/SportsStore.WebUI.csproj index 364a2f8..9dba5a6 100644 --- a/SportsStore.WebUI/SportsStore.WebUI.csproj +++ b/SportsStore.WebUI/SportsStore.WebUI.csproj @@ -135,12 +135,15 @@ + + Global.asax + @@ -153,6 +156,8 @@ + + Web.config diff --git a/SportsStore.WebUI/Views/Cart/Index.cshtml b/SportsStore.WebUI/Views/Cart/Index.cshtml new file mode 100644 index 0000000..b2233d5 --- /dev/null +++ b/SportsStore.WebUI/Views/Cart/Index.cshtml @@ -0,0 +1,42 @@ +@model SportsStore.WebUI.Models.CartIndexViewModel +@{ + ViewBag.Title = "Sports Store: Your Cart"; +} + +

Your cart

+ + + + + + + + + + + @foreach (var line in Model.Cart.Lines) + { + + + + + + + } + + + + + + + + +
QuantityItemPriceSubtotal
@line.Quantity@line.Product.Name@line.Product.Price.ToString("c") + @((line.Quantity * line.Product.Price).ToString("c")) +
Total: + @Model.Cart.ComputeTotalValue().ToString("c") +
+ + diff --git a/SportsStore.WebUI/Views/Nav/Menu.cshtml b/SportsStore.WebUI/Views/Nav/Menu.cshtml new file mode 100644 index 0000000..494e4b0 --- /dev/null +++ b/SportsStore.WebUI/Views/Nav/Menu.cshtml @@ -0,0 +1,13 @@ +@model IEnumerable + +@Html.ActionLink("Home", "List", "Product", null, + new { @class = "btn btn-block btn-default btn-lg" }) + +@foreach (var link in Model) +{ + @Html.RouteLink( + link, + new { controller = "Product", action = "List", category = link, page = 1 }, + new { @class = "btn btn-block btn-default btn-lg" + (link == ViewBag.SelectedCategory ? " btn-primary" : "") } + ) +} diff --git a/SportsStore.WebUI/Views/Product/List.cshtml b/SportsStore.WebUI/Views/Product/List.cshtml index 8ecce71..49389ac 100644 --- a/SportsStore.WebUI/Views/Product/List.cshtml +++ b/SportsStore.WebUI/Views/Product/List.cshtml @@ -10,5 +10,5 @@ }
- @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x})) + @Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x, category = Model.CurrentCategory}))
diff --git a/SportsStore.WebUI/Views/Shared/ProductSummary.cshtml b/SportsStore.WebUI/Views/Shared/ProductSummary.cshtml index 89f2807..a48df1c 100644 --- a/SportsStore.WebUI/Views/Shared/ProductSummary.cshtml +++ b/SportsStore.WebUI/Views/Shared/ProductSummary.cshtml @@ -5,5 +5,13 @@ @Model.Name @Model.Price + @using (Html.BeginForm("AddToCart", "Cart")) + { +
+ @Html.HiddenFor(x => x.ProductID) + @Html.Hidden("returnUrl", Request.Url.PathAndQuery) + +
+ } @Model.Description diff --git a/SportsStore.WebUI/Views/Shared/_Layout.cshtml b/SportsStore.WebUI/Views/Shared/_Layout.cshtml index ba65747..740511c 100644 --- a/SportsStore.WebUI/Views/Shared/_Layout.cshtml +++ b/SportsStore.WebUI/Views/Shared/_Layout.cshtml @@ -13,7 +13,7 @@
- Put something useful here later + @Html.Action("Menu", "Nav")
@RenderBody()